@fluixi/utils 1.0.0-alpha.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +73 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/dist/lib/array/advanced.cjs +1 -0
- package/dist/lib/array/advanced.d.ts +1116 -0
- package/dist/lib/array/advanced.d.ts.map +1 -0
- package/dist/lib/array/advanced.js +2429 -0
- package/dist/lib/array/advanced.mjs +1 -0
- package/dist/lib/array/array.cjs +1 -0
- package/dist/lib/array/array.d.ts +6 -0
- package/dist/lib/array/array.d.ts.map +1 -0
- package/dist/lib/array/array.js +31 -0
- package/dist/lib/array/array.mjs +1 -0
- package/dist/lib/array/index.cjs +1 -0
- package/dist/lib/array/index.d.ts +4 -0
- package/dist/lib/array/index.d.ts.map +1 -0
- package/dist/lib/array/index.js +3 -0
- package/dist/lib/array/index.mjs +1 -0
- package/dist/lib/array/utils.cjs +1 -0
- package/dist/lib/array/utils.d.ts +100 -0
- package/dist/lib/array/utils.d.ts.map +1 -0
- package/dist/lib/array/utils.js +165 -0
- package/dist/lib/array/utils.mjs +1 -0
- package/dist/lib/color/color.cjs +1 -0
- package/dist/lib/color/color.d.ts +366 -0
- package/dist/lib/color/color.d.ts.map +1 -0
- package/dist/lib/color/color.js +722 -0
- package/dist/lib/color/color.mjs +1 -0
- package/dist/lib/color/constants.cjs +1 -0
- package/dist/lib/color/constants.d.ts +361 -0
- package/dist/lib/color/constants.d.ts.map +1 -0
- package/dist/lib/color/constants.js +358 -0
- package/dist/lib/color/constants.mjs +1 -0
- package/dist/lib/color/conversions.cjs +1 -0
- package/dist/lib/color/conversions.d.ts +166 -0
- package/dist/lib/color/conversions.d.ts.map +1 -0
- package/dist/lib/color/conversions.js +766 -0
- package/dist/lib/color/conversions.mjs +1 -0
- package/dist/lib/color/helpers.cjs +1 -0
- package/dist/lib/color/helpers.d.ts +75 -0
- package/dist/lib/color/helpers.d.ts.map +1 -0
- package/dist/lib/color/helpers.js +419 -0
- package/dist/lib/color/helpers.mjs +1 -0
- package/dist/lib/color/index.cjs +1 -0
- package/dist/lib/color/index.d.ts +12 -0
- package/dist/lib/color/index.d.ts.map +1 -0
- package/dist/lib/color/index.js +15 -0
- package/dist/lib/color/index.mjs +1 -0
- package/dist/lib/color/types.cjs +1 -0
- package/dist/lib/color/types.d.ts +179 -0
- package/dist/lib/color/types.d.ts.map +1 -0
- package/dist/lib/color/types.js +1 -0
- package/dist/lib/color/types.mjs +0 -0
- package/dist/lib/color/utils.cjs +1 -0
- package/dist/lib/color/utils.d.ts +199 -0
- package/dist/lib/color/utils.d.ts.map +1 -0
- package/dist/lib/color/utils.js +858 -0
- package/dist/lib/color/utils.mjs +1 -0
- package/dist/lib/compare/comparators.cjs +1 -0
- package/dist/lib/compare/comparators.d.ts +65 -0
- package/dist/lib/compare/comparators.d.ts.map +1 -0
- package/dist/lib/compare/comparators.js +210 -0
- package/dist/lib/compare/comparators.mjs +1 -0
- package/dist/lib/compare/index.cjs +1 -0
- package/dist/lib/compare/index.d.ts +2 -0
- package/dist/lib/compare/index.d.ts.map +1 -0
- package/dist/lib/compare/index.js +1 -0
- package/dist/lib/compare/index.mjs +1 -0
- package/dist/lib/crypto/hash.cjs +1 -0
- package/dist/lib/crypto/hash.d.ts +6 -0
- package/dist/lib/crypto/hash.d.ts.map +1 -0
- package/dist/lib/crypto/hash.js +53 -0
- package/dist/lib/crypto/hash.mjs +1 -0
- package/dist/lib/crypto/index.cjs +1 -0
- package/dist/lib/crypto/index.d.ts +2 -0
- package/dist/lib/crypto/index.d.ts.map +1 -0
- package/dist/lib/crypto/index.js +1 -0
- package/dist/lib/crypto/index.mjs +1 -0
- package/dist/lib/dom/events.cjs +1 -0
- package/dist/lib/dom/events.d.ts +159 -0
- package/dist/lib/dom/events.d.ts.map +1 -0
- package/dist/lib/dom/events.js +50 -0
- package/dist/lib/dom/events.mjs +1 -0
- package/dist/lib/dom/index.cjs +1 -0
- package/dist/lib/dom/index.d.ts +3 -0
- package/dist/lib/dom/index.d.ts.map +1 -0
- package/dist/lib/dom/index.js +2 -0
- package/dist/lib/dom/index.mjs +1 -0
- package/dist/lib/dom/utils.cjs +1 -0
- package/dist/lib/dom/utils.d.ts +6 -0
- package/dist/lib/dom/utils.d.ts.map +1 -0
- package/dist/lib/dom/utils.js +37 -0
- package/dist/lib/dom/utils.mjs +1 -0
- package/dist/lib/functions/functions.cjs +1 -0
- package/dist/lib/functions/functions.d.ts +329 -0
- package/dist/lib/functions/functions.d.ts.map +1 -0
- package/dist/lib/functions/functions.js +585 -0
- package/dist/lib/functions/functions.mjs +1 -0
- package/dist/lib/functions/index.cjs +1 -0
- package/dist/lib/functions/index.d.ts +3 -0
- package/dist/lib/functions/index.d.ts.map +1 -0
- package/dist/lib/functions/index.js +1 -0
- package/dist/lib/functions/index.mjs +1 -0
- package/dist/lib/functions/types.cjs +1 -0
- package/dist/lib/functions/types.d.ts +2 -0
- package/dist/lib/functions/types.d.ts.map +1 -0
- package/dist/lib/functions/types.js +1 -0
- package/dist/lib/functions/types.mjs +0 -0
- package/dist/lib/helpers.cjs +1 -0
- package/dist/lib/helpers.d.ts +13 -0
- package/dist/lib/helpers.d.ts.map +1 -0
- package/dist/lib/helpers.js +66 -0
- package/dist/lib/helpers.mjs +1 -0
- package/dist/lib/index.cjs +1 -0
- package/dist/lib/index.d.ts +6 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +8 -0
- package/dist/lib/index.mjs +1 -0
- package/dist/lib/maths/constants.cjs +1 -0
- package/dist/lib/maths/constants.d.ts +84 -0
- package/dist/lib/maths/constants.d.ts.map +1 -0
- package/dist/lib/maths/constants.js +79 -0
- package/dist/lib/maths/constants.mjs +1 -0
- package/dist/lib/maths/fn/advanced.cjs +1 -0
- package/dist/lib/maths/fn/advanced.d.ts +149 -0
- package/dist/lib/maths/fn/advanced.d.ts.map +1 -0
- package/dist/lib/maths/fn/advanced.js +264 -0
- package/dist/lib/maths/fn/advanced.mjs +1 -0
- package/dist/lib/maths/fn/basic.cjs +1 -0
- package/dist/lib/maths/fn/basic.d.ts +182 -0
- package/dist/lib/maths/fn/basic.d.ts.map +1 -0
- package/dist/lib/maths/fn/basic.js +343 -0
- package/dist/lib/maths/fn/basic.mjs +1 -0
- package/dist/lib/maths/fn/complex.cjs +1 -0
- package/dist/lib/maths/fn/complex.d.ts +153 -0
- package/dist/lib/maths/fn/complex.d.ts.map +1 -0
- package/dist/lib/maths/fn/complex.js +383 -0
- package/dist/lib/maths/fn/complex.mjs +1 -0
- package/dist/lib/maths/fn/index.cjs +1 -0
- package/dist/lib/maths/fn/index.d.ts +10 -0
- package/dist/lib/maths/fn/index.d.ts.map +1 -0
- package/dist/lib/maths/fn/index.js +9 -0
- package/dist/lib/maths/fn/index.mjs +1 -0
- package/dist/lib/maths/fn/trigo.cjs +1 -0
- package/dist/lib/maths/fn/trigo.d.ts +147 -0
- package/dist/lib/maths/fn/trigo.d.ts.map +1 -0
- package/dist/lib/maths/fn/trigo.js +227 -0
- package/dist/lib/maths/fn/trigo.mjs +1 -0
- package/dist/lib/maths/fn/vector.cjs +1 -0
- package/dist/lib/maths/fn/vector.d.ts +512 -0
- package/dist/lib/maths/fn/vector.d.ts.map +1 -0
- package/dist/lib/maths/fn/vector.js +1136 -0
- package/dist/lib/maths/fn/vector.mjs +1 -0
- package/dist/lib/maths/formatter.cjs +1 -0
- package/dist/lib/maths/formatter.d.ts +35 -0
- package/dist/lib/maths/formatter.d.ts.map +1 -0
- package/dist/lib/maths/formatter.js +56 -0
- package/dist/lib/maths/formatter.mjs +1 -0
- package/dist/lib/maths/guards.cjs +1 -0
- package/dist/lib/maths/guards.d.ts +166 -0
- package/dist/lib/maths/guards.d.ts.map +1 -0
- package/dist/lib/maths/guards.js +315 -0
- package/dist/lib/maths/guards.mjs +1 -0
- package/dist/lib/maths/index.cjs +1 -0
- package/dist/lib/maths/index.d.ts +24 -0
- package/dist/lib/maths/index.d.ts.map +1 -0
- package/dist/lib/maths/index.js +29 -0
- package/dist/lib/maths/index.mjs +1 -0
- package/dist/lib/maths/parser.cjs +1 -0
- package/dist/lib/maths/parser.d.ts +20 -0
- package/dist/lib/maths/parser.d.ts.map +1 -0
- package/dist/lib/maths/parser.js +78 -0
- package/dist/lib/maths/parser.mjs +1 -0
- package/dist/lib/maths/random.cjs +1 -0
- package/dist/lib/maths/random.d.ts +27 -0
- package/dist/lib/maths/random.d.ts.map +1 -0
- package/dist/lib/maths/random.js +49 -0
- package/dist/lib/maths/random.mjs +1 -0
- package/dist/lib/maths/types/advanced.cjs +1 -0
- package/dist/lib/maths/types/advanced.d.ts +357 -0
- package/dist/lib/maths/types/advanced.d.ts.map +1 -0
- package/dist/lib/maths/types/advanced.js +5 -0
- package/dist/lib/maths/types/advanced.mjs +0 -0
- package/dist/lib/maths/types/basic.cjs +1 -0
- package/dist/lib/maths/types/basic.d.ts +95 -0
- package/dist/lib/maths/types/basic.d.ts.map +1 -0
- package/dist/lib/maths/types/basic.js +5 -0
- package/dist/lib/maths/types/basic.mjs +0 -0
- package/dist/lib/maths/types/index.cjs +1 -0
- package/dist/lib/maths/types/index.d.ts +4 -0
- package/dist/lib/maths/types/index.d.ts.map +1 -0
- package/dist/lib/maths/types/index.js +3 -0
- package/dist/lib/maths/types/index.mjs +0 -0
- package/dist/lib/maths/types/negative.cjs +1 -0
- package/dist/lib/maths/types/negative.d.ts +51 -0
- package/dist/lib/maths/types/negative.d.ts.map +1 -0
- package/dist/lib/maths/types/negative.js +5 -0
- package/dist/lib/maths/types/negative.mjs +0 -0
- package/dist/lib/maths/types/operations.cjs +1 -0
- package/dist/lib/maths/types/operations.d.ts +188 -0
- package/dist/lib/maths/types/operations.d.ts.map +1 -0
- package/dist/lib/maths/types/operations.js +6 -0
- package/dist/lib/maths/types/operations.mjs +0 -0
- package/dist/lib/object/clone.cjs +1 -0
- package/dist/lib/object/clone.d.ts +46 -0
- package/dist/lib/object/clone.d.ts.map +1 -0
- package/dist/lib/object/clone.js +104 -0
- package/dist/lib/object/clone.mjs +1 -0
- package/dist/lib/object/diff.cjs +1 -0
- package/dist/lib/object/diff.d.ts +203 -0
- package/dist/lib/object/diff.d.ts.map +1 -0
- package/dist/lib/object/diff.js +805 -0
- package/dist/lib/object/diff.mjs +1 -0
- package/dist/lib/object/getter-setter.cjs +1 -0
- package/dist/lib/object/getter-setter.d.ts +361 -0
- package/dist/lib/object/getter-setter.d.ts.map +1 -0
- package/dist/lib/object/getter-setter.js +1771 -0
- package/dist/lib/object/getter-setter.mjs +1 -0
- package/dist/lib/object/index.cjs +6 -0
- package/dist/lib/object/index.d.ts +13 -0
- package/dist/lib/object/index.d.ts.map +1 -0
- package/dist/lib/object/index.js +12 -0
- package/dist/lib/object/index.mjs +6 -0
- package/dist/lib/object/merge.cjs +1 -0
- package/dist/lib/object/merge.d.ts +93 -0
- package/dist/lib/object/merge.d.ts.map +1 -0
- package/dist/lib/object/merge.js +474 -0
- package/dist/lib/object/merge.mjs +1 -0
- package/dist/lib/object/object.cjs +1 -0
- package/dist/lib/object/object.d.ts +128 -0
- package/dist/lib/object/object.d.ts.map +1 -0
- package/dist/lib/object/object.js +432 -0
- package/dist/lib/object/object.mjs +1 -0
- package/dist/lib/object/omit.cjs +1 -0
- package/dist/lib/object/omit.d.ts +351 -0
- package/dist/lib/object/omit.d.ts.map +1 -0
- package/dist/lib/object/omit.js +656 -0
- package/dist/lib/object/omit.mjs +1 -0
- package/dist/lib/object/reconcile.cjs +1 -0
- package/dist/lib/object/reconcile.d.ts +7 -0
- package/dist/lib/object/reconcile.d.ts.map +1 -0
- package/dist/lib/object/reconcile.js +122 -0
- package/dist/lib/object/reconcile.mjs +1 -0
- package/dist/lib/object/selector.cjs +1 -0
- package/dist/lib/object/selector.d.ts +50 -0
- package/dist/lib/object/selector.d.ts.map +1 -0
- package/dist/lib/object/selector.js +371 -0
- package/dist/lib/object/selector.mjs +1 -0
- package/dist/lib/object/sort.cjs +1 -0
- package/dist/lib/object/sort.d.ts +149 -0
- package/dist/lib/object/sort.d.ts.map +1 -0
- package/dist/lib/object/sort.js +298 -0
- package/dist/lib/object/sort.mjs +1 -0
- package/dist/lib/object/transform.cjs +1 -0
- package/dist/lib/object/transform.d.ts +620 -0
- package/dist/lib/object/transform.d.ts.map +1 -0
- package/dist/lib/object/transform.js +1058 -0
- package/dist/lib/object/transform.mjs +1 -0
- package/dist/lib/object/types.cjs +1 -0
- package/dist/lib/object/types.d.ts +250 -0
- package/dist/lib/object/types.d.ts.map +1 -0
- package/dist/lib/object/types.js +1 -0
- package/dist/lib/object/types.mjs +0 -0
- package/dist/lib/object/utils.cjs +6 -0
- package/dist/lib/object/utils.d.ts +165 -0
- package/dist/lib/object/utils.d.ts.map +1 -0
- package/dist/lib/object/utils.js +444 -0
- package/dist/lib/object/utils.mjs +6 -0
- package/dist/lib/primitive/boolean/boolean.cjs +1 -0
- package/dist/lib/primitive/boolean/boolean.d.ts +276 -0
- package/dist/lib/primitive/boolean/boolean.d.ts.map +1 -0
- package/dist/lib/primitive/boolean/boolean.js +615 -0
- package/dist/lib/primitive/boolean/boolean.mjs +1 -0
- package/dist/lib/primitive/boolean/index.cjs +1 -0
- package/dist/lib/primitive/boolean/index.d.ts +3 -0
- package/dist/lib/primitive/boolean/index.d.ts.map +1 -0
- package/dist/lib/primitive/boolean/index.js +2 -0
- package/dist/lib/primitive/boolean/index.mjs +1 -0
- package/dist/lib/primitive/boolean/types.cjs +1 -0
- package/dist/lib/primitive/boolean/types.d.ts +14 -0
- package/dist/lib/primitive/boolean/types.d.ts.map +1 -0
- package/dist/lib/primitive/boolean/types.js +1 -0
- package/dist/lib/primitive/boolean/types.mjs +0 -0
- package/dist/lib/primitive/date/date.cjs +1 -0
- package/dist/lib/primitive/date/date.d.ts +641 -0
- package/dist/lib/primitive/date/date.d.ts.map +1 -0
- package/dist/lib/primitive/date/date.js +1998 -0
- package/dist/lib/primitive/date/date.mjs +1 -0
- package/dist/lib/primitive/date/index.cjs +1 -0
- package/dist/lib/primitive/date/index.d.ts +3 -0
- package/dist/lib/primitive/date/index.d.ts.map +1 -0
- package/dist/lib/primitive/date/index.js +2 -0
- package/dist/lib/primitive/date/index.mjs +1 -0
- package/dist/lib/primitive/date/types.cjs +1 -0
- package/dist/lib/primitive/date/types.d.ts +205 -0
- package/dist/lib/primitive/date/types.d.ts.map +1 -0
- package/dist/lib/primitive/date/types.js +7 -0
- package/dist/lib/primitive/date/types.mjs +0 -0
- package/dist/lib/primitive/index.cjs +5 -0
- package/dist/lib/primitive/index.d.ts +5 -0
- package/dist/lib/primitive/index.d.ts.map +1 -0
- package/dist/lib/primitive/index.js +4 -0
- package/dist/lib/primitive/index.mjs +5 -0
- package/dist/lib/primitive/string/index.cjs +5 -0
- package/dist/lib/primitive/string/index.d.ts +3 -0
- package/dist/lib/primitive/string/index.d.ts.map +1 -0
- package/dist/lib/primitive/string/index.js +2 -0
- package/dist/lib/primitive/string/index.mjs +5 -0
- package/dist/lib/primitive/string/parser-2.cjs +8 -0
- package/dist/lib/primitive/string/parser-2.d.ts +17 -0
- package/dist/lib/primitive/string/parser-2.d.ts.map +1 -0
- package/dist/lib/primitive/string/parser-2.js +656 -0
- package/dist/lib/primitive/string/parser-2.mjs +8 -0
- package/dist/lib/primitive/string/parser.cjs +3 -0
- package/dist/lib/primitive/string/parser.d.ts +9 -0
- package/dist/lib/primitive/string/parser.d.ts.map +1 -0
- package/dist/lib/primitive/string/parser.js +775 -0
- package/dist/lib/primitive/string/parser.mjs +3 -0
- package/dist/lib/primitive/string/string.cjs +5 -0
- package/dist/lib/primitive/string/string.d.ts +535 -0
- package/dist/lib/primitive/string/string.d.ts.map +1 -0
- package/dist/lib/primitive/string/string.js +1301 -0
- package/dist/lib/primitive/string/string.mjs +5 -0
- package/dist/lib/primitive/string/types.cjs +1 -0
- package/dist/lib/primitive/string/types.d.ts +318 -0
- package/dist/lib/primitive/string/types.d.ts.map +1 -0
- package/dist/lib/primitive/string/types.js +5 -0
- package/dist/lib/primitive/string/types.mjs +0 -0
- package/dist/lib/primitive/types.cjs +1 -0
- package/dist/lib/primitive/types.d.ts +27 -0
- package/dist/lib/primitive/types.d.ts.map +1 -0
- package/dist/lib/primitive/types.js +1 -0
- package/dist/lib/primitive/types.mjs +0 -0
- package/dist/lib/url/index.cjs +1 -0
- package/dist/lib/url/index.d.ts +3 -0
- package/dist/lib/url/index.d.ts.map +1 -0
- package/dist/lib/url/index.js +2 -0
- package/dist/lib/url/index.mjs +1 -0
- package/dist/lib/url/parser.cjs +1 -0
- package/dist/lib/url/parser.d.ts +216 -0
- package/dist/lib/url/parser.d.ts.map +1 -0
- package/dist/lib/url/parser.js +488 -0
- package/dist/lib/url/parser.mjs +1 -0
- package/dist/lib/url/types.cjs +1 -0
- package/dist/lib/url/types.d.ts +18 -0
- package/dist/lib/url/types.d.ts.map +1 -0
- package/dist/lib/url/types.js +1 -0
- package/dist/lib/url/types.mjs +0 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -0
- package/package.json +150 -0
|
@@ -0,0 +1,775 @@
|
|
|
1
|
+
// type ParserOptions = {
|
|
2
|
+
// allowUnquotedKeys?: boolean;
|
|
3
|
+
// allowTrailingCommas?: boolean;
|
|
4
|
+
// allowSingleQuotes?: boolean;
|
|
5
|
+
// allowComments?: boolean;
|
|
6
|
+
// allowUndefined?: boolean;
|
|
7
|
+
// allowSpecialNumbers?: boolean;
|
|
8
|
+
// reviver?: (key: string, value: any) => any;
|
|
9
|
+
// strict?: boolean;
|
|
10
|
+
// maxDepth?: number;
|
|
11
|
+
// };
|
|
12
|
+
// class ParseError extends Error {
|
|
13
|
+
// constructor(
|
|
14
|
+
// message: string,
|
|
15
|
+
// public position: number,
|
|
16
|
+
// public context: string = ''
|
|
17
|
+
// ) {
|
|
18
|
+
// super(`ParseError at position ${position}: ${message}${context ? ` (${context})` : ''}`);
|
|
19
|
+
// this.name = 'ParseError';
|
|
20
|
+
// }
|
|
21
|
+
// }
|
|
22
|
+
// /**
|
|
23
|
+
// * Safe, typed parser for JavaScript object literals
|
|
24
|
+
// */
|
|
25
|
+
// export function parseObjectString<T = any>(str: string, options: ParserOptions = {}): T {
|
|
26
|
+
// // Input validation
|
|
27
|
+
// if (typeof str !== 'string') {
|
|
28
|
+
// throw new TypeError('Input must be a string');
|
|
29
|
+
// }
|
|
30
|
+
// if (str.trim().length === 0) {
|
|
31
|
+
// throw new ParseError('Input string is empty', 0);
|
|
32
|
+
// }
|
|
33
|
+
// // Default options
|
|
34
|
+
// const opts: Required<ParserOptions> = {
|
|
35
|
+
// allowUnquotedKeys: true,
|
|
36
|
+
// allowTrailingCommas: true,
|
|
37
|
+
// allowSingleQuotes: true,
|
|
38
|
+
// allowComments: true,
|
|
39
|
+
// allowUndefined: false,
|
|
40
|
+
// allowSpecialNumbers: false,
|
|
41
|
+
// reviver: undefined!,
|
|
42
|
+
// strict: false,
|
|
43
|
+
// maxDepth: 100,
|
|
44
|
+
// ...options,
|
|
45
|
+
// };
|
|
46
|
+
// let index = 0;
|
|
47
|
+
// let currentChar = str[0] || '';
|
|
48
|
+
// // Helper functions
|
|
49
|
+
// const next = (): void => {
|
|
50
|
+
// index++;
|
|
51
|
+
// currentChar = str[index] || '';
|
|
52
|
+
// };
|
|
53
|
+
// const peek = (offset = 1): string => str[index + offset] || '';
|
|
54
|
+
// const isEnd = (): boolean => index >= str.length;
|
|
55
|
+
// const expectChar = (char: string, errorMessage: string): void => {
|
|
56
|
+
// if (currentChar !== char) {
|
|
57
|
+
// throw new ParseError(errorMessage, index, `Expected '${char}', got '${currentChar}'`);
|
|
58
|
+
// }
|
|
59
|
+
// };
|
|
60
|
+
// // Skip functions
|
|
61
|
+
// const skipWhitespace = (): void => {
|
|
62
|
+
// while (!isEnd() && /\s/.test(currentChar)) {
|
|
63
|
+
// next();
|
|
64
|
+
// }
|
|
65
|
+
// };
|
|
66
|
+
// const skipComments = (): void => {
|
|
67
|
+
// if (!opts.allowComments) return;
|
|
68
|
+
// // Single line comment
|
|
69
|
+
// if (currentChar === '/' && peek() === '/') {
|
|
70
|
+
// next(); // Skip '/'
|
|
71
|
+
// next(); // Skip second '/'
|
|
72
|
+
// while (!isEnd() && (peek() !== '\n' && peek() !== '\r')) {
|
|
73
|
+
// // while (!isEnd() && currentChar !== '\n' && currentChar !== '\r') {
|
|
74
|
+
// next();
|
|
75
|
+
// }
|
|
76
|
+
// skipWhitespace();
|
|
77
|
+
// }
|
|
78
|
+
// // Multi-line comment
|
|
79
|
+
// if (currentChar === '/' && peek() === '*') {
|
|
80
|
+
// next(); // Skip '/'
|
|
81
|
+
// next(); // Skip '*'
|
|
82
|
+
// while (!isEnd()) {
|
|
83
|
+
// if (peek() === '/') {
|
|
84
|
+
// // if (currentChar === '*' && peek() === '/') {
|
|
85
|
+
// next(); // Skip '*'
|
|
86
|
+
// next(); // Skip '/'
|
|
87
|
+
// break;
|
|
88
|
+
// }
|
|
89
|
+
// next();
|
|
90
|
+
// }
|
|
91
|
+
// skipWhitespace();
|
|
92
|
+
// }
|
|
93
|
+
// };
|
|
94
|
+
// const skipWhitespaceAndComments = (): void => {
|
|
95
|
+
// while (!isEnd()) {
|
|
96
|
+
// const prevIndex = index;
|
|
97
|
+
// skipWhitespace();
|
|
98
|
+
// skipComments();
|
|
99
|
+
// if (index === prevIndex) break;
|
|
100
|
+
// }
|
|
101
|
+
// };
|
|
102
|
+
// // Character classification helpers
|
|
103
|
+
// const isDigit = (char: string): boolean => char >= '0' && char <= '9';
|
|
104
|
+
// const isHexDigit = (char: string): boolean =>
|
|
105
|
+
// (char >= '0' && char <= '9') ||
|
|
106
|
+
// (char >= 'a' && char <= 'f') ||
|
|
107
|
+
// (char >= 'A' && char <= 'F');
|
|
108
|
+
// const isIdentifierStart = (char: string): boolean =>
|
|
109
|
+
// (char >= 'a' && char <= 'z') ||
|
|
110
|
+
// (char >= 'A' && char <= 'Z') ||
|
|
111
|
+
// char === '_' ||
|
|
112
|
+
// char === '$';
|
|
113
|
+
// const isIdentifierChar = (char: string): boolean =>
|
|
114
|
+
// isIdentifierStart(char) || isDigit(char);
|
|
115
|
+
// // Main parse function with depth tracking
|
|
116
|
+
// const parseValue = (depth = 0): any => {
|
|
117
|
+
// if (depth > opts.maxDepth) {
|
|
118
|
+
// throw new ParseError(`Maximum nesting depth (${opts.maxDepth}) exceeded`, index);
|
|
119
|
+
// }
|
|
120
|
+
// skipWhitespaceAndComments();
|
|
121
|
+
// if (isEnd()) {
|
|
122
|
+
// throw new ParseError('Unexpected end of input', index);
|
|
123
|
+
// }
|
|
124
|
+
// switch (currentChar) {
|
|
125
|
+
// case '{':
|
|
126
|
+
// return parseObject(depth + 1);
|
|
127
|
+
// case '[':
|
|
128
|
+
// return parseArray(depth + 1);
|
|
129
|
+
// case '"':
|
|
130
|
+
// case "'":
|
|
131
|
+
// return parseString();
|
|
132
|
+
// case '-':
|
|
133
|
+
// case '0':
|
|
134
|
+
// case '1':
|
|
135
|
+
// case '2':
|
|
136
|
+
// case '3':
|
|
137
|
+
// case '4':
|
|
138
|
+
// case '5':
|
|
139
|
+
// case '6':
|
|
140
|
+
// case '7':
|
|
141
|
+
// case '8':
|
|
142
|
+
// case '9':
|
|
143
|
+
// return parseNumber();
|
|
144
|
+
// case 't':
|
|
145
|
+
// case 'f':
|
|
146
|
+
// case 'n':
|
|
147
|
+
// return parseKeyword();
|
|
148
|
+
// case 'u':
|
|
149
|
+
// if (opts.allowUndefined) {
|
|
150
|
+
// return parseKeyword();
|
|
151
|
+
// }
|
|
152
|
+
// throw new ParseError('Unexpected character', index, "'u' at start of undefined");
|
|
153
|
+
// case 'I':
|
|
154
|
+
// case 'N':
|
|
155
|
+
// if (opts.allowSpecialNumbers) {
|
|
156
|
+
// return parseSpecialNumber();
|
|
157
|
+
// }
|
|
158
|
+
// throw new ParseError('Unexpected character', index);
|
|
159
|
+
// default:
|
|
160
|
+
// throw new ParseError(`Unexpected character '${currentChar}'`, index);
|
|
161
|
+
// }
|
|
162
|
+
// };
|
|
163
|
+
// const parseObject = (depth: number): Record<string, any> => {
|
|
164
|
+
// const obj: Record<string, any> = {};
|
|
165
|
+
// next(); // Skip '{'
|
|
166
|
+
// skipWhitespaceAndComments();
|
|
167
|
+
// // Empty object
|
|
168
|
+
// if (currentChar === '}') {
|
|
169
|
+
// next();
|
|
170
|
+
// return obj;
|
|
171
|
+
// }
|
|
172
|
+
// while (!isEnd()) {
|
|
173
|
+
// skipWhitespaceAndComments();
|
|
174
|
+
// // Parse key
|
|
175
|
+
// let key: string;
|
|
176
|
+
// if (currentChar === '"' || (opts.allowSingleQuotes && currentChar === "'")) {
|
|
177
|
+
// key = parseString();
|
|
178
|
+
// } else if (opts.allowUnquotedKeys && isIdentifierStart(currentChar)) {
|
|
179
|
+
// const start = index;
|
|
180
|
+
// while (!isEnd() && isIdentifierChar(currentChar)) {
|
|
181
|
+
// next();
|
|
182
|
+
// }
|
|
183
|
+
// key = str.slice(start, index);
|
|
184
|
+
// } else {
|
|
185
|
+
// throw new ParseError('Expected property name', index);
|
|
186
|
+
// }
|
|
187
|
+
// skipWhitespaceAndComments();
|
|
188
|
+
// // Colon
|
|
189
|
+
// expectChar(':', 'Expected colon after property name');
|
|
190
|
+
// next();
|
|
191
|
+
// skipWhitespaceAndComments();
|
|
192
|
+
// // Value
|
|
193
|
+
// obj[key] = parseValue(depth);
|
|
194
|
+
// skipWhitespaceAndComments();
|
|
195
|
+
// // Check for end or comma
|
|
196
|
+
// if (currentChar === '}') {
|
|
197
|
+
// next();
|
|
198
|
+
// break;
|
|
199
|
+
// }
|
|
200
|
+
// if (currentChar === ',') {
|
|
201
|
+
// next();
|
|
202
|
+
// skipWhitespaceAndComments();
|
|
203
|
+
// // Check for trailing comma
|
|
204
|
+
// // if (currentChar === '}') {
|
|
205
|
+
// if (peek() === '}') {
|
|
206
|
+
// if (opts.allowTrailingCommas) {
|
|
207
|
+
// next();
|
|
208
|
+
// break;
|
|
209
|
+
// }
|
|
210
|
+
// throw new ParseError('Trailing comma not allowed', index);
|
|
211
|
+
// }
|
|
212
|
+
// continue;
|
|
213
|
+
// }
|
|
214
|
+
// throw new ParseError('Expected comma or closing brace', index);
|
|
215
|
+
// }
|
|
216
|
+
// return obj;
|
|
217
|
+
// };
|
|
218
|
+
// const parseArray = (depth: number): any[] => {
|
|
219
|
+
// const arr: any[] = [];
|
|
220
|
+
// next(); // Skip '['
|
|
221
|
+
// skipWhitespaceAndComments();
|
|
222
|
+
// // Empty array
|
|
223
|
+
// if (currentChar === ']') {
|
|
224
|
+
// next();
|
|
225
|
+
// return arr;
|
|
226
|
+
// }
|
|
227
|
+
// while (!isEnd()) {
|
|
228
|
+
// arr.push(parseValue(depth));
|
|
229
|
+
// skipWhitespaceAndComments();
|
|
230
|
+
// // Check for end or comma
|
|
231
|
+
// if (currentChar === ']') {
|
|
232
|
+
// next();
|
|
233
|
+
// break;
|
|
234
|
+
// }
|
|
235
|
+
// if (currentChar === ',') {
|
|
236
|
+
// next();
|
|
237
|
+
// skipWhitespaceAndComments();
|
|
238
|
+
// // Trailing comma check
|
|
239
|
+
// if (peek() === ']') {
|
|
240
|
+
// // if (currentChar === ']') {
|
|
241
|
+
// if (opts.allowTrailingCommas) {
|
|
242
|
+
// next();
|
|
243
|
+
// break;
|
|
244
|
+
// }
|
|
245
|
+
// throw new ParseError('Trailing comma not allowed', index);
|
|
246
|
+
// }
|
|
247
|
+
// continue;
|
|
248
|
+
// }
|
|
249
|
+
// throw new ParseError('Expected comma or closing bracket', index);
|
|
250
|
+
// }
|
|
251
|
+
// return arr;
|
|
252
|
+
// };
|
|
253
|
+
// const parseString = (): string => {
|
|
254
|
+
// const quoteChar = currentChar;
|
|
255
|
+
// if (quoteChar === "'" && !opts.allowSingleQuotes) {
|
|
256
|
+
// throw new ParseError('Single quotes not allowed', index);
|
|
257
|
+
// }
|
|
258
|
+
// next(); // Skip opening quote
|
|
259
|
+
// let result = '';
|
|
260
|
+
// const startIndex = index;
|
|
261
|
+
// while (!isEnd() && currentChar !== quoteChar) {
|
|
262
|
+
// if (currentChar === '\\') {
|
|
263
|
+
// next();
|
|
264
|
+
// if (isEnd()) {
|
|
265
|
+
// throw new ParseError('Unterminated string', startIndex);
|
|
266
|
+
// }
|
|
267
|
+
// result += parseEscapeSequence();
|
|
268
|
+
// } else {
|
|
269
|
+
// result += currentChar;
|
|
270
|
+
// next();
|
|
271
|
+
// }
|
|
272
|
+
// }
|
|
273
|
+
// if (currentChar !== quoteChar) {
|
|
274
|
+
// throw new ParseError('Unterminated string', startIndex);
|
|
275
|
+
// }
|
|
276
|
+
// next(); // Skip closing quote
|
|
277
|
+
// return result;
|
|
278
|
+
// };
|
|
279
|
+
// const parseEscapeSequence = (): string => {
|
|
280
|
+
// const escStart = index;
|
|
281
|
+
// switch (currentChar) {
|
|
282
|
+
// case '"':
|
|
283
|
+
// case "'":
|
|
284
|
+
// case '\\':
|
|
285
|
+
// case '/':
|
|
286
|
+
// const char = currentChar;
|
|
287
|
+
// next();
|
|
288
|
+
// return char;
|
|
289
|
+
// case 'b':
|
|
290
|
+
// next();
|
|
291
|
+
// return '\b';
|
|
292
|
+
// case 'f':
|
|
293
|
+
// next();
|
|
294
|
+
// return '\f';
|
|
295
|
+
// case 'n':
|
|
296
|
+
// next();
|
|
297
|
+
// return '\n';
|
|
298
|
+
// case 'r':
|
|
299
|
+
// next();
|
|
300
|
+
// return '\r';
|
|
301
|
+
// case 't':
|
|
302
|
+
// next();
|
|
303
|
+
// return '\t';
|
|
304
|
+
// case 'u':
|
|
305
|
+
// next();
|
|
306
|
+
// return parseUnicodeEscape();
|
|
307
|
+
// default:
|
|
308
|
+
// // Return the character as-is (like JavaScript does)
|
|
309
|
+
// const escapedChar = currentChar;
|
|
310
|
+
// next();
|
|
311
|
+
// return escapedChar;
|
|
312
|
+
// }
|
|
313
|
+
// };
|
|
314
|
+
// const parseUnicodeEscape = (): string => {
|
|
315
|
+
// const start = index;
|
|
316
|
+
// let hex = '';
|
|
317
|
+
// // Parse 4 hex digits
|
|
318
|
+
// for (let i = 0; i < 4; i++) {
|
|
319
|
+
// if (isEnd() || !isHexDigit(currentChar)) {
|
|
320
|
+
// throw new ParseError('Invalid Unicode escape sequence', start);
|
|
321
|
+
// }
|
|
322
|
+
// hex += currentChar;
|
|
323
|
+
// next();
|
|
324
|
+
// }
|
|
325
|
+
// return String.fromCharCode(parseInt(hex, 16));
|
|
326
|
+
// };
|
|
327
|
+
// const parseNumber = (): number => {
|
|
328
|
+
// const start = index;
|
|
329
|
+
// let numberStr = '';
|
|
330
|
+
// // Sign
|
|
331
|
+
// if (currentChar === '-') {
|
|
332
|
+
// numberStr += currentChar;
|
|
333
|
+
// next();
|
|
334
|
+
// }
|
|
335
|
+
// // Integer part
|
|
336
|
+
// if (currentChar === '0') {
|
|
337
|
+
// numberStr += currentChar;
|
|
338
|
+
// next();
|
|
339
|
+
// } else {
|
|
340
|
+
// while (!isEnd() && isDigit(currentChar)) {
|
|
341
|
+
// numberStr += currentChar;
|
|
342
|
+
// next();
|
|
343
|
+
// }
|
|
344
|
+
// }
|
|
345
|
+
// // Fraction part
|
|
346
|
+
// if (currentChar === '.') {
|
|
347
|
+
// numberStr += currentChar;
|
|
348
|
+
// next();
|
|
349
|
+
// while (!isEnd() && isDigit(currentChar)) {
|
|
350
|
+
// numberStr += currentChar;
|
|
351
|
+
// next();
|
|
352
|
+
// }
|
|
353
|
+
// }
|
|
354
|
+
// // Exponent
|
|
355
|
+
// if (currentChar === 'e' || currentChar === 'E') {
|
|
356
|
+
// numberStr += currentChar;
|
|
357
|
+
// next();
|
|
358
|
+
// // if (currentChar === '+' || currentChar === '-') {
|
|
359
|
+
// if (peek() === '+' || peek() === '-') {
|
|
360
|
+
// numberStr += currentChar;
|
|
361
|
+
// next();
|
|
362
|
+
// }
|
|
363
|
+
// while (!isEnd() && isDigit(currentChar)) {
|
|
364
|
+
// numberStr += currentChar;
|
|
365
|
+
// next();
|
|
366
|
+
// }
|
|
367
|
+
// }
|
|
368
|
+
// const num = parseFloat(numberStr);
|
|
369
|
+
// if (isNaN(num)) {
|
|
370
|
+
// throw new ParseError('Invalid number', start);
|
|
371
|
+
// }
|
|
372
|
+
// return num;
|
|
373
|
+
// };
|
|
374
|
+
// const parseSpecialNumber = (): number => {
|
|
375
|
+
// const start = index;
|
|
376
|
+
// if (currentChar === 'I') {
|
|
377
|
+
// const word = str.slice(index, index + 8);
|
|
378
|
+
// if (word === 'Infinity') {
|
|
379
|
+
// for (let i = 0; i < 8; i++) next();
|
|
380
|
+
// return Infinity;
|
|
381
|
+
// }
|
|
382
|
+
// } else if (currentChar === 'N') {
|
|
383
|
+
// const word = str.slice(index, index + 3);
|
|
384
|
+
// if (word === 'NaN') {
|
|
385
|
+
// for (let i = 0; i < 3; i++) next();
|
|
386
|
+
// return NaN;
|
|
387
|
+
// }
|
|
388
|
+
// } else if (currentChar === '-' && peek() === 'I') {
|
|
389
|
+
// const word = str.slice(index, index + 9);
|
|
390
|
+
// if (word === '-Infinity') {
|
|
391
|
+
// for (let i = 0; i < 9; i++) next();
|
|
392
|
+
// return -Infinity;
|
|
393
|
+
// }
|
|
394
|
+
// }
|
|
395
|
+
// throw new ParseError('Invalid special number', start);
|
|
396
|
+
// };
|
|
397
|
+
// const parseKeyword = (): any => {
|
|
398
|
+
// const start = index;
|
|
399
|
+
// let keyword = '';
|
|
400
|
+
// while (!isEnd() && /[a-zA-Z]/.test(currentChar)) {
|
|
401
|
+
// keyword += currentChar;
|
|
402
|
+
// next();
|
|
403
|
+
// }
|
|
404
|
+
// switch (keyword) {
|
|
405
|
+
// case 'true':
|
|
406
|
+
// return true;
|
|
407
|
+
// case 'false':
|
|
408
|
+
// return false;
|
|
409
|
+
// case 'null':
|
|
410
|
+
// return null;
|
|
411
|
+
// case 'undefined':
|
|
412
|
+
// if (opts.allowUndefined) {
|
|
413
|
+
// return undefined;
|
|
414
|
+
// }
|
|
415
|
+
// throw new ParseError('undefined is not allowed', start);
|
|
416
|
+
// default:
|
|
417
|
+
// throw new ParseError(`Unexpected keyword '${keyword}'`, start);
|
|
418
|
+
// }
|
|
419
|
+
// };
|
|
420
|
+
// // Main parse execution
|
|
421
|
+
// try {
|
|
422
|
+
// skipWhitespaceAndComments();
|
|
423
|
+
// const result = parseValue();
|
|
424
|
+
// // Check for trailing characters
|
|
425
|
+
// skipWhitespaceAndComments();
|
|
426
|
+
// if (!isEnd()) {
|
|
427
|
+
// throw new ParseError('Unexpected trailing characters', index);
|
|
428
|
+
// }
|
|
429
|
+
// // Apply reviver if provided
|
|
430
|
+
// if (opts.reviver) {
|
|
431
|
+
// return applyReviver({ '': result }, '', result, opts.reviver);
|
|
432
|
+
// }
|
|
433
|
+
// return result as T;
|
|
434
|
+
// } catch (error) {
|
|
435
|
+
// // Fallback to JSON.parse if not strict
|
|
436
|
+
// if (!opts.strict && error instanceof ParseError) {
|
|
437
|
+
// try {
|
|
438
|
+
// return opts.reviver
|
|
439
|
+
// ? JSON.parse(str, opts.reviver)
|
|
440
|
+
// : JSON.parse(str);
|
|
441
|
+
// } catch {
|
|
442
|
+
// throw error;
|
|
443
|
+
// }
|
|
444
|
+
// }
|
|
445
|
+
// throw error;
|
|
446
|
+
// }
|
|
447
|
+
// }
|
|
448
|
+
// function applyReviver(
|
|
449
|
+
// holder: Record<string, any>,
|
|
450
|
+
// key: string,
|
|
451
|
+
// value: any,
|
|
452
|
+
// reviver: (key: string, value: any) => any
|
|
453
|
+
// ): any {
|
|
454
|
+
// if (value && typeof value === 'object') {
|
|
455
|
+
// if (Array.isArray(value)) {
|
|
456
|
+
// return value.map((item, index) =>
|
|
457
|
+
// applyReviver(value, index.toString(), item, reviver)
|
|
458
|
+
// );
|
|
459
|
+
// } else {
|
|
460
|
+
// const result: Record<string, any> = {};
|
|
461
|
+
// for (const [k, v] of Object.entries(value)) {
|
|
462
|
+
// const transformed = applyReviver(value, k, v, reviver);
|
|
463
|
+
// if (transformed !== undefined) {
|
|
464
|
+
// result[k] = transformed;
|
|
465
|
+
// }
|
|
466
|
+
// }
|
|
467
|
+
// return result;
|
|
468
|
+
// }
|
|
469
|
+
// }
|
|
470
|
+
// return reviver.call(holder, key, value);
|
|
471
|
+
// }
|
|
472
|
+
/**
|
|
473
|
+
* Fix the regex patterns in the custom parse function
|
|
474
|
+
* Improved version with proper comment handling
|
|
475
|
+
*/
|
|
476
|
+
function customParse(str, options = {}) {
|
|
477
|
+
// First, try to parse as JSON
|
|
478
|
+
try {
|
|
479
|
+
return JSON.parse(str);
|
|
480
|
+
}
|
|
481
|
+
catch (e) {
|
|
482
|
+
// If JSON.parse fails, attempt to fix common JS object literal issues
|
|
483
|
+
return parseJsObjectLiteral(str, options);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
function parseJsObjectLiteral(str, options = {}) {
|
|
487
|
+
const { allowComments = true, allowUnquotedKeys = true, allowSingleQuotes = true, allowTrailingCommas = true, allowUndefined = false } = options;
|
|
488
|
+
let fixed = str.trim();
|
|
489
|
+
// 1. Remove comments if allowed
|
|
490
|
+
if (allowComments) {
|
|
491
|
+
// Fix: Proper comment regex that handles multi-line and single-line comments
|
|
492
|
+
// Remove multi-line comments: /* ... */
|
|
493
|
+
fixed = fixed.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
494
|
+
// Remove single-line comments: // ... (but not in strings!)
|
|
495
|
+
// We need to be careful not to remove // inside quotes
|
|
496
|
+
// Simple approach: process line by line
|
|
497
|
+
const lines = fixed.split('\n');
|
|
498
|
+
const cleanedLines = lines.map(line => {
|
|
499
|
+
// Find comment position, but ignore // inside quotes
|
|
500
|
+
let inString = false;
|
|
501
|
+
let stringChar = '';
|
|
502
|
+
let escapeNext = false;
|
|
503
|
+
for (let i = 0; i < line.length; i++) {
|
|
504
|
+
const char = line[i];
|
|
505
|
+
if (escapeNext) {
|
|
506
|
+
escapeNext = false;
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
if (char === '\\') {
|
|
510
|
+
escapeNext = true;
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
514
|
+
inString = true;
|
|
515
|
+
stringChar = char;
|
|
516
|
+
}
|
|
517
|
+
else if (inString && char === stringChar) {
|
|
518
|
+
inString = false;
|
|
519
|
+
stringChar = '';
|
|
520
|
+
}
|
|
521
|
+
else if (!inString && char === '/' && line[i + 1] === '/') {
|
|
522
|
+
// Found comment start outside string
|
|
523
|
+
return line.substring(0, i);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
return line;
|
|
527
|
+
});
|
|
528
|
+
fixed = cleanedLines.join('\n');
|
|
529
|
+
}
|
|
530
|
+
// 2. Fix unquoted keys (if allowed)
|
|
531
|
+
if (allowUnquotedKeys) {
|
|
532
|
+
// Fix: Better regex that handles edge cases
|
|
533
|
+
// Match property names that are valid identifiers
|
|
534
|
+
// Look for pattern: {key: or ,key: or { key : or , key :
|
|
535
|
+
fixed = fixed.replace(/([{,]\s*)([a-zA-Z_$][a-zA-Z0-9_$]*)(\s*:)/g, '$1"$2"$3');
|
|
536
|
+
}
|
|
537
|
+
// 3. Convert single quotes to double quotes (if allowed)
|
|
538
|
+
if (allowSingleQuotes) {
|
|
539
|
+
// Fix: Better regex that handles escaped quotes
|
|
540
|
+
// Process string literals with single quotes
|
|
541
|
+
let result = '';
|
|
542
|
+
let inSingleQuote = false;
|
|
543
|
+
let inDoubleQuote = false;
|
|
544
|
+
let escapeNext = false;
|
|
545
|
+
let i = 0;
|
|
546
|
+
while (i < fixed.length) {
|
|
547
|
+
const char = fixed[i];
|
|
548
|
+
if (escapeNext) {
|
|
549
|
+
result += char;
|
|
550
|
+
escapeNext = false;
|
|
551
|
+
i++;
|
|
552
|
+
continue;
|
|
553
|
+
}
|
|
554
|
+
if (char === '\\') {
|
|
555
|
+
escapeNext = true;
|
|
556
|
+
result += char;
|
|
557
|
+
i++;
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
if (char === "'" && !inDoubleQuote) {
|
|
561
|
+
if (inSingleQuote) {
|
|
562
|
+
// Closing single quote
|
|
563
|
+
result += '"';
|
|
564
|
+
inSingleQuote = false;
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
// Opening single quote
|
|
568
|
+
result += '"';
|
|
569
|
+
inSingleQuote = true;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
else if (char === '"' && !inSingleQuote) {
|
|
573
|
+
if (inDoubleQuote) {
|
|
574
|
+
inDoubleQuote = false;
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
inDoubleQuote = true;
|
|
578
|
+
}
|
|
579
|
+
result += char;
|
|
580
|
+
}
|
|
581
|
+
else {
|
|
582
|
+
result += char;
|
|
583
|
+
}
|
|
584
|
+
i++;
|
|
585
|
+
}
|
|
586
|
+
fixed = result;
|
|
587
|
+
}
|
|
588
|
+
// 4. Remove trailing commas (if allowed)
|
|
589
|
+
if (allowTrailingCommas) {
|
|
590
|
+
// Fix: Better regex that handles trailing commas in arrays and objects
|
|
591
|
+
// Remove commas before ] or }
|
|
592
|
+
// Need to avoid removing commas inside strings
|
|
593
|
+
let result = '';
|
|
594
|
+
let inString = false;
|
|
595
|
+
let stringChar = '';
|
|
596
|
+
let escapeNext = false;
|
|
597
|
+
let i = 0;
|
|
598
|
+
while (i < fixed.length) {
|
|
599
|
+
const char = fixed[i];
|
|
600
|
+
if (escapeNext) {
|
|
601
|
+
result += char;
|
|
602
|
+
escapeNext = false;
|
|
603
|
+
i++;
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
606
|
+
if (char === '\\') {
|
|
607
|
+
escapeNext = true;
|
|
608
|
+
result += char;
|
|
609
|
+
i++;
|
|
610
|
+
continue;
|
|
611
|
+
}
|
|
612
|
+
if ((char === '"' || char === "'") && !inString) {
|
|
613
|
+
inString = true;
|
|
614
|
+
stringChar = char;
|
|
615
|
+
result += char;
|
|
616
|
+
}
|
|
617
|
+
else if (inString && char === stringChar) {
|
|
618
|
+
inString = false;
|
|
619
|
+
stringChar = '';
|
|
620
|
+
result += char;
|
|
621
|
+
}
|
|
622
|
+
else if (!inString && char === ',') {
|
|
623
|
+
// Check if next non-whitespace char is ] or }
|
|
624
|
+
let j = i + 1;
|
|
625
|
+
while (j < fixed.length && /\s/.test(fixed[j])) {
|
|
626
|
+
j++;
|
|
627
|
+
}
|
|
628
|
+
if (j < fixed.length && (fixed[j] === ']' || fixed[j] === '}')) {
|
|
629
|
+
// Skip this comma (don't add to result)
|
|
630
|
+
i++;
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
result += char;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
result += char;
|
|
639
|
+
}
|
|
640
|
+
i++;
|
|
641
|
+
}
|
|
642
|
+
fixed = result;
|
|
643
|
+
}
|
|
644
|
+
// 5. Handle undefined (if allowed)
|
|
645
|
+
if (allowUndefined) {
|
|
646
|
+
// Replace undefined with null (JSON doesn't support undefined)
|
|
647
|
+
// Need to avoid replacing undefined inside strings
|
|
648
|
+
let result = '';
|
|
649
|
+
let inString = false;
|
|
650
|
+
let stringChar = '';
|
|
651
|
+
let escapeNext = false;
|
|
652
|
+
let i = 0;
|
|
653
|
+
while (i < fixed.length) {
|
|
654
|
+
if (escapeNext) {
|
|
655
|
+
result += fixed[i];
|
|
656
|
+
escapeNext = false;
|
|
657
|
+
i++;
|
|
658
|
+
continue;
|
|
659
|
+
}
|
|
660
|
+
if (fixed[i] === '\\') {
|
|
661
|
+
escapeNext = true;
|
|
662
|
+
result += fixed[i];
|
|
663
|
+
i++;
|
|
664
|
+
continue;
|
|
665
|
+
}
|
|
666
|
+
if ((fixed[i] === '"' || fixed[i] === "'") && !inString) {
|
|
667
|
+
inString = true;
|
|
668
|
+
stringChar = fixed[i];
|
|
669
|
+
result += fixed[i];
|
|
670
|
+
}
|
|
671
|
+
else if (inString && fixed[i] === stringChar) {
|
|
672
|
+
inString = false;
|
|
673
|
+
stringChar = '';
|
|
674
|
+
result += fixed[i];
|
|
675
|
+
}
|
|
676
|
+
else if (!inString && fixed.substr(i, 9) === 'undefined') {
|
|
677
|
+
// Check if it's really the undefined keyword (not part of a larger word)
|
|
678
|
+
const before = i > 0 ? fixed[i - 1] : '';
|
|
679
|
+
const after = i + 8 < fixed.length ? fixed[i + 9] : '';
|
|
680
|
+
const isWordChar = /[a-zA-Z0-9_$]/.test(before) || /[a-zA-Z0-9_$]/.test(after);
|
|
681
|
+
if (!isWordChar) {
|
|
682
|
+
result += 'null';
|
|
683
|
+
i += 9;
|
|
684
|
+
continue;
|
|
685
|
+
}
|
|
686
|
+
else {
|
|
687
|
+
result += fixed[i];
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
else {
|
|
691
|
+
result += fixed[i];
|
|
692
|
+
}
|
|
693
|
+
i++;
|
|
694
|
+
}
|
|
695
|
+
fixed = result;
|
|
696
|
+
}
|
|
697
|
+
// Try to parse the fixed string as JSON
|
|
698
|
+
try {
|
|
699
|
+
return JSON.parse(fixed);
|
|
700
|
+
}
|
|
701
|
+
catch (e) {
|
|
702
|
+
// If still fails, try a manual parser as fallback
|
|
703
|
+
// return manualParse(str, options);
|
|
704
|
+
return undefined;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
// Alternative: A simpler regex-based approach with better patterns
|
|
708
|
+
function simpleJsObjectParse(str) {
|
|
709
|
+
// This is a simpler version that just handles the most common cases
|
|
710
|
+
let fixed = str;
|
|
711
|
+
// Remove comments (simplified)
|
|
712
|
+
fixed = fixed
|
|
713
|
+
// Remove multi-line comments
|
|
714
|
+
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
715
|
+
// Remove single-line comments
|
|
716
|
+
.replace(/\/\/.*$/gm, '');
|
|
717
|
+
// Add quotes to unquoted keys (improved)
|
|
718
|
+
// This pattern is more careful about what it matches
|
|
719
|
+
fixed = fixed.replace(/([{,]\s*)([a-zA-Z_$][\w$]*)(\s*:)/g, (match, prefix, key, suffix) => {
|
|
720
|
+
// Don't quote if it's already a number or special value
|
|
721
|
+
if (key === 'true' || key === 'false' || key === 'null' || key === 'undefined') {
|
|
722
|
+
return match;
|
|
723
|
+
}
|
|
724
|
+
// Don't quote if it looks like a number
|
|
725
|
+
if (/^\d/.test(key)) {
|
|
726
|
+
return match;
|
|
727
|
+
}
|
|
728
|
+
return `${prefix}"${key}"${suffix}`;
|
|
729
|
+
});
|
|
730
|
+
// Convert single quotes to double (careful with escaped quotes)
|
|
731
|
+
// This is a simplified approach - for production, use the state machine
|
|
732
|
+
fixed = fixed.replace(/'([^'\\]*(?:\\.[^'\\]*)*)'/g, '"$1"');
|
|
733
|
+
// Remove trailing commas
|
|
734
|
+
fixed = fixed.replace(/,(\s*[\]}])/g, '$1');
|
|
735
|
+
try {
|
|
736
|
+
return JSON.parse(fixed);
|
|
737
|
+
}
|
|
738
|
+
catch (e) {
|
|
739
|
+
throw new SyntaxError(`Failed to parse JavaScript object literal: ${e}`);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
// console.log('Testing regex fixes:');
|
|
743
|
+
// const testCases = [
|
|
744
|
+
// // Unquoted keys
|
|
745
|
+
// '{name: "John", age: 30}',
|
|
746
|
+
// // Single quotes
|
|
747
|
+
// "{'name': 'John', 'age': 30}",
|
|
748
|
+
// // Mixed quotes
|
|
749
|
+
// "{name: 'John', \"age\": 30}",
|
|
750
|
+
// // Trailing comma
|
|
751
|
+
// '{name: "John", age: 30,}',
|
|
752
|
+
// // With comments
|
|
753
|
+
// `{
|
|
754
|
+
// // This is a comment
|
|
755
|
+
// name: "John",
|
|
756
|
+
// /* Multi-line
|
|
757
|
+
// comment */
|
|
758
|
+
// age: 30
|
|
759
|
+
// }`,
|
|
760
|
+
// // Array with trailing comma
|
|
761
|
+
// '["a", "b", "c",]',
|
|
762
|
+
// // Nested with issues
|
|
763
|
+
// '{data: {name: "John", items: [1, 2, 3,]}}'
|
|
764
|
+
// ];
|
|
765
|
+
// testCases.forEach((test, i) => {
|
|
766
|
+
// console.log(`\nTest ${i + 1}: ${test.slice(0, 50)}...`);
|
|
767
|
+
// try {
|
|
768
|
+
// const result = simpleJsObjectParse(test);
|
|
769
|
+
// console.log('Success:', JSON.stringify(result));
|
|
770
|
+
// } catch (e) {
|
|
771
|
+
// console.log('Error:', e.message);
|
|
772
|
+
// }
|
|
773
|
+
// });
|
|
774
|
+
// Export for use
|
|
775
|
+
export { customParse, simpleJsObjectParse, parseJsObjectLiteral };
|