Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,8 @@

- Built-in date/time recognition for ISO 8601 and common local formats
- New `parseDates` option to enable the feature

## 2.3.0 (2025-06-09)

- URL and file path detection via `parseUrls` and `parseFilePaths` options
- New examples and benchmarks covering the feature
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ A small utility that automatically converts strings and other values into the mo
- Supports typed arrays
- Evaluates simple math expressions
- Recognizes common date/time formats
- Detects URLs and file-system paths
- Optional environment variable expansion
- Optional function-string parsing
- Advanced features are disabled by default and can be enabled individually
Expand Down Expand Up @@ -62,6 +63,8 @@ autoParse('Map:[["a",1]]', { parseMapSets: true }).get('a') // => 1
autoParse('Uint8Array[1,2]', { parseTypedArrays: true })[0] // => 1
autoParse('2 + 3 * 4', { parseExpressions: true }) // => 14
autoParse('2023-06-01', { parseDates: true }) // => Date object
autoParse('http://example.com', { parseUrls: true }) // => URL instance
autoParse('./foo/bar', { parseFilePaths: true }) // => normalized path
process.env.TEST_ENV = '123'
autoParse('$TEST_ENV', { expandEnv: true }) // => 123
const double = autoParse('x => x * 2', { parseFunctionStrings: true })
Expand Down Expand Up @@ -126,9 +129,11 @@ More examples can be found in the [`examples/`](examples) directory.
- `parseTypedArrays` – support typed array notation.
- `parseExpressions` – evaluate simple math expressions.
- `parseDates` – recognize ISO 8601 and common local date/time strings.
- `parseUrls` – detect valid URLs and return `URL` objects.
- `parseFilePaths` – detect file-system paths and normalize them.
- `currencySymbols` – object mapping extra currency symbols to codes, e.g. `{ 'r$': 'BRL', "\u20BA": 'TRY' }`.

## Benchmarks (v2.2.0)
## Benchmarks (v2.3.0)

The following timings are measured on Node.js using `npm test` and represent roughly how long it takes to parse 10 000 values after warm‑up:

Expand All @@ -143,6 +148,8 @@ The following timings are measured on Node.js using `npm test` and represent rou
| options combined | ~6 |
| plugin hook | ~4 |
| date/time parse | ~5 |
| URL parse | ~5 |
| file path parse | ~5 |

Even a single parse is extremely fast:

Expand All @@ -157,6 +164,8 @@ Even a single parse is extremely fast:
| options combined | ~0.0006 |
| plugin hook | ~0.0004 |
| date/time parse | ~0.0005 |
| URL parse | ~0.0005 |
| file path parse | ~0.0005 |

These numbers demonstrate the parser runs in well under a millisecond for typical values, so performance should never be a concern.

Expand Down Expand Up @@ -194,6 +203,9 @@ optional environment variable and function-string handling. See
Version 2.2 introduces optional date/time recognition. See
[docs/RELEASE_NOTES_2.2.md](docs/RELEASE_NOTES_2.2.md) for details.

Version 2.3 adds URL and file path detection. See
[docs/RELEASE_NOTES_2.3.md](docs/RELEASE_NOTES_2.3.md) for details.

## Contributing

1. Fork the repository and create a branch for your feature or fix.
Expand Down
29 changes: 29 additions & 0 deletions dist/auto-parse.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,20 @@ var require_auto_parse = __commonJS({
}
return null;
}
function parseUrlString(str) {
try {
return new URL(str);
} catch (e) {
return null;
}
}
function parseFilePathString(str) {
const re = /^(?:[A-Za-z]:[\\/]|\\\\|\.{1,2}[\\/]|~[\\/]|\/)/;
if (re.test(str)) {
return str.replace(/\\+/g, "/").replace(/\/+/g, "/");
}
return null;
}
function parseExpressionString(str) {
if (/^[0-9+\-*/() %.]+$/.test(str) && /[+\-*/()%]/.test(str)) {
try {
Expand Down Expand Up @@ -338,6 +352,11 @@ var require_auto_parse = __commonJS({
return new Map(autoParse(value, options));
case "set":
return new Set(autoParse(value, options));
case "url":
return new URL(value);
case "path":
case "filepath":
return parseFilePathString(String(value)) || String(value);
default:
if (typeof type === "function") {
if (/Array$/.test(type.name)) {
Expand Down Expand Up @@ -466,6 +485,16 @@ var require_auto_parse = __commonJS({
if (dt)
return returnIfAllowed(dt, options, originalValue);
}
if (options.parseUrls) {
const u = parseUrlString(trimmed);
if (u)
return returnIfAllowed(u, options, originalValue);
}
if (options.parseFilePaths) {
const p = parseFilePathString(trimmed);
if (p)
return returnIfAllowed(p, options, originalValue);
}
value = stripTrimLower(trimmed, Object.assign({}, options, { stripStartChars: false }));
if (value === "undefined" || value === "") {
return returnIfAllowed(void 0, options, originalValue);
Expand Down
29 changes: 29 additions & 0 deletions dist/auto-parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,20 @@ function parseDateTimeString(str) {
}
return null;
}
function parseUrlString(str) {
try {
return new URL(str);
} catch (e) {
return null;
}
}
function parseFilePathString(str) {
const re = /^(?:[A-Za-z]:[\\/]|\\\\|\.{1,2}[\\/]|~[\\/]|\/)/;
if (re.test(str)) {
return str.replace(/\\+/g, "/").replace(/\/+/g, "/");
}
return null;
}
function parseExpressionString(str) {
if (/^[0-9+\-*/() %.]+$/.test(str) && /[+\-*/()%]/.test(str)) {
try {
Expand Down Expand Up @@ -331,6 +345,11 @@ function parseType(value, type, options = {}) {
return new Map(autoParse(value, options));
case "set":
return new Set(autoParse(value, options));
case "url":
return new URL(value);
case "path":
case "filepath":
return parseFilePathString(String(value)) || String(value);
default:
if (typeof type === "function") {
if (/Array$/.test(type.name)) {
Expand Down Expand Up @@ -459,6 +478,16 @@ function autoParse(value, typeOrOptions) {
if (dt)
return returnIfAllowed(dt, options, originalValue);
}
if (options.parseUrls) {
const u = parseUrlString(trimmed);
if (u)
return returnIfAllowed(u, options, originalValue);
}
if (options.parseFilePaths) {
const p = parseFilePathString(trimmed);
if (p)
return returnIfAllowed(p, options, originalValue);
}
value = stripTrimLower(trimmed, Object.assign({}, options, { stripStartChars: false }));
if (value === "undefined" || value === "") {
return returnIfAllowed(void 0, options, originalValue);
Expand Down
9 changes: 9 additions & 0 deletions docs/RELEASE_NOTES_2.3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Release Notes: Version 2.3

Version 2.3 introduces optional URL and file path parsing.

- URLs such as `https://example.com` return `URL` objects when `parseUrls` is enabled.
- File-system paths like `./foo/bar` normalize to platform-neutral strings when `parseFilePaths` is enabled.
- Both features are disabled by default and can be turned on individually via options.

See the [CHANGELOG](../CHANGELOG.md) for the full history.
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ them with `node <file>` from this directory.
- `plugin.js` illustrates registering a simple plugin.
- `types.js` covers advanced types like `BigInt` and `Symbol`.
- `dates.js` demonstrates the optional date/time parsing capability.
- `urls.js` shows URL and file path detection.
- `all-options.js` exercises every available option in one script.
4 changes: 4 additions & 0 deletions examples/urls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const autoParse = require('..')

console.log('URL:', autoParse('https://example.com', { parseUrls: true }))
console.log('Path:', autoParse('./foo/bar', { parseFilePaths: true }))
2 changes: 2 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export interface AutoParseOptions {
parseTypedArrays?: boolean;
parseExpressions?: boolean;
parseDates?: boolean;
parseUrls?: boolean;
parseFilePaths?: boolean;
type?: any;
}
export type Parser = (value: any, type?: any, options?: AutoParseOptions) => any | undefined;
Expand Down
29 changes: 29 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,22 @@ function parseDateTimeString (str) {
return null
}

function parseUrlString (str) {
try {
return new URL(str)
} catch (e) {
return null
}
}

function parseFilePathString (str) {
const re = /^(?:[A-Za-z]:[\\/]|\\\\|\.{1,2}[\\/]|~[\\/]|\/)/
if (re.test(str)) {
return str.replace(/\\+/g, '/').replace(/\/+/g, '/')
}
return null
}

function parseExpressionString (str) {
if (/^[0-9+\-*/() %.]+$/.test(str) && /[+\-*/()%]/.test(str)) {
try {
Expand Down Expand Up @@ -377,6 +393,11 @@ function parseType (value, type, options = {}) {
return new Map(autoParse(value, options))
case 'set':
return new Set(autoParse(value, options))
case 'url':
return new URL(value)
case 'path':
case 'filepath':
return parseFilePathString(String(value)) || String(value)
default:
if (typeof type === 'function') {
if (/Array$/.test(type.name)) {
Expand Down Expand Up @@ -530,6 +551,14 @@ function autoParse (value, typeOrOptions) {
const dt = parseDateTimeString(trimmed)
if (dt) return returnIfAllowed(dt, options, originalValue)
}
if (options.parseUrls) {
const u = parseUrlString(trimmed)
if (u) return returnIfAllowed(u, options, originalValue)
}
if (options.parseFilePaths) {
const p = parseFilePathString(trimmed)
if (p) return returnIfAllowed(p, options, originalValue)
}
value = stripTrimLower(trimmed, Object.assign({}, options, { stripStartChars: false }))
if (value === 'undefined' || value === '') {
return returnIfAllowed(undefined, options, originalValue)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "auto-parse",
"version": "2.2.0",
"version": "2.3.0",
"description": "Automatically convert any value to its best matching JavaScript type. Supports numbers, booleans, objects, arrays, BigInt, Symbol, comma-separated numbers, prefix stripping, allowed type enforcement and a plugin API.",
"main": "index.js",
"types": "index.d.ts",
Expand Down
26 changes: 26 additions & 0 deletions test/performance.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,30 @@ describe('Performance', () => {
console.log('date parse time', time)
expect(time).toBeLessThan(300)
})

test('url parse performance', () => {
for (let i = 0; i < 1000; i++) {
autoParse('https://example.com', { parseUrls: true })
}
const time = benchmark(() => {
for (let i = 0; i < 10000; i++) {
autoParse('https://example.com', { parseUrls: true })
}
})
console.log('url parse time', time)
expect(time).toBeLessThan(300)
})

test('file path parse performance', () => {
for (let i = 0; i < 1000; i++) {
autoParse('./foo/bar', { parseFilePaths: true })
}
const time = benchmark(() => {
for (let i = 0; i < 10000; i++) {
autoParse('./foo/bar', { parseFilePaths: true })
}
})
console.log('path parse time', time)
expect(time).toBeLessThan(300)
})
})
19 changes: 19 additions & 0 deletions test/url-path.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const autoParse = require('../index.js')
const { assert } = require('chai')

describe('URL and file path parsing', function () {
it('parses URL strings when enabled', function () {
const url = autoParse('https://example.com', { parseUrls: true })
assert.instanceOf(url, URL)
assert.strictEqual(url.hostname, 'example.com')
})

it('parses file paths when enabled', function () {
const p = autoParse('./foo/bar', { parseFilePaths: true })
assert.strictEqual(p.includes('foo'), true)
})

it('defaults to string when disabled', function () {
assert.strictEqual(autoParse('https://example.com'), 'https://example.com')
})
})