es-check 9.4.7 → 9.5.0
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/README.md +1 -1
- package/lib/check-runner/utils.js +0 -28
- package/lib/cli/index.js +0 -0
- package/lib/constants/es-features/15.js +64 -0
- package/lib/constants/es-features/16.js +115 -0
- package/lib/constants/es-features/index.js +25 -1
- package/lib/detectFeatures.js +18 -104
- package/lib/helpers/astDetector.js +144 -0
- package/lib/helpers/index.js +2 -0
- package/lib/helpers/parsers.js +0 -50
- package/package.json +2 -19
- package/lib/constants/es-features/es-features/15.js +0 -28
- package/lib/constants/es-features/es-features/16.js +0 -39
- package/lib/constants/es-features/es-features/index.js +0 -27
- /package/lib/constants/es-features/{es-features/10.js → 10.js} +0 -0
- /package/lib/constants/es-features/{es-features/11.js → 11.js} +0 -0
- /package/lib/constants/es-features/{es-features/12.js → 12.js} +0 -0
- /package/lib/constants/es-features/{es-features/13.js → 13.js} +0 -0
- /package/lib/constants/es-features/{es-features/14.js → 14.js} +0 -0
- /package/lib/constants/es-features/{es-features/6.js → 6.js} +0 -0
- /package/lib/constants/es-features/{es-features/7.js → 7.js} +0 -0
- /package/lib/constants/es-features/{es-features/8.js → 8.js} +0 -0
- /package/lib/constants/es-features/{es-features/9.js → 9.js} +0 -0
package/README.md
CHANGED
|
@@ -671,7 +671,7 @@ Tested on lodash, axios, react, moment, express, and chalk. See [benchmarks](./t
|
|
|
671
671
|
|
|
672
672
|
## Contributing
|
|
673
673
|
|
|
674
|
-
ES Check has only
|
|
674
|
+
ES Check has only 3 core dependencies: [acorn](https://github.com/ternjs/acorn/) for JavaScript parsing, [fast-glob](https://github.com/mrmlnc/fast-glob) for file globbing, and [browserslist](https://github.com/browserslist/browserslist) for browser targeting.
|
|
675
675
|
|
|
676
676
|
The CLI, logging, and source map support are implemented with custom lightweight solutions using Node.js built-ins to minimize dependencies. To contribute, file an [issue](https://github.com/yowainwright/es-check/issues) or submit a pull request.
|
|
677
677
|
|
|
@@ -285,28 +285,6 @@ function filterIgnoredFiles(files, pathsToIgnore, globOpts) {
|
|
|
285
285
|
});
|
|
286
286
|
}
|
|
287
287
|
|
|
288
|
-
function processLightMode(code, ecmaVersion, config, file, isDebug, logger) {
|
|
289
|
-
const { parseLightMode } = require("../helpers");
|
|
290
|
-
const { error: parseError } = parseLightMode(
|
|
291
|
-
code,
|
|
292
|
-
ecmaVersion,
|
|
293
|
-
config.module,
|
|
294
|
-
config.allowHashBang,
|
|
295
|
-
file,
|
|
296
|
-
);
|
|
297
|
-
|
|
298
|
-
const hasParseError = parseError !== null;
|
|
299
|
-
const shouldDebugError = hasParseError && isDebug;
|
|
300
|
-
|
|
301
|
-
if (shouldDebugError) {
|
|
302
|
-
logger.debug(
|
|
303
|
-
`ES-Check: failed to parse file: ${file} \n - error: ${parseError.err}`,
|
|
304
|
-
);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
return parseError;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
288
|
function processFullAST(
|
|
311
289
|
code,
|
|
312
290
|
acornOpts,
|
|
@@ -425,12 +403,6 @@ function createFileProcessor(config, options) {
|
|
|
425
403
|
logger.debug(`ES-Check: checking ${file}`);
|
|
426
404
|
}
|
|
427
405
|
|
|
428
|
-
const isLightMode = config.light;
|
|
429
|
-
|
|
430
|
-
if (isLightMode) {
|
|
431
|
-
return processLightMode(code, ecmaVersion, config, file, isDebug, logger);
|
|
432
|
-
}
|
|
433
|
-
|
|
434
406
|
return processFullAST(
|
|
435
407
|
code,
|
|
436
408
|
acornOpts,
|
package/lib/cli/index.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
const ES15_FEATURES = {
|
|
2
|
+
StringIsWellFormed: {
|
|
3
|
+
minVersion: 15,
|
|
4
|
+
example: "str.isWellFormed()",
|
|
5
|
+
astInfo: {
|
|
6
|
+
nodeType: "CallExpression",
|
|
7
|
+
property: "isWellFormed",
|
|
8
|
+
},
|
|
9
|
+
},
|
|
10
|
+
StringToWellFormed: {
|
|
11
|
+
minVersion: 15,
|
|
12
|
+
example: "str.toWellFormed()",
|
|
13
|
+
astInfo: {
|
|
14
|
+
nodeType: "CallExpression",
|
|
15
|
+
property: "toWellFormed",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
RegExpUnicodeSetFlag: {
|
|
19
|
+
minVersion: 15,
|
|
20
|
+
example: "/pattern/v",
|
|
21
|
+
astInfo: {
|
|
22
|
+
nodeType: "RegExpLiteral",
|
|
23
|
+
flags: "v",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
PromiseWithResolvers: {
|
|
27
|
+
minVersion: 15,
|
|
28
|
+
example: "Promise.withResolvers()",
|
|
29
|
+
astInfo: {
|
|
30
|
+
nodeType: "CallExpression",
|
|
31
|
+
object: "Promise",
|
|
32
|
+
property: "withResolvers",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
ObjectGroupBy: {
|
|
36
|
+
minVersion: 15,
|
|
37
|
+
example: "Object.groupBy(array, fn)",
|
|
38
|
+
astInfo: {
|
|
39
|
+
nodeType: "CallExpression",
|
|
40
|
+
object: "Object",
|
|
41
|
+
property: "groupBy",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
MapGroupBy: {
|
|
45
|
+
minVersion: 15,
|
|
46
|
+
example: "Map.groupBy(array, fn)",
|
|
47
|
+
astInfo: {
|
|
48
|
+
nodeType: "CallExpression",
|
|
49
|
+
object: "Map",
|
|
50
|
+
property: "groupBy",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
AtomicsWaitAsync: {
|
|
54
|
+
minVersion: 15,
|
|
55
|
+
example: "Atomics.waitAsync(typedArray, index, value)",
|
|
56
|
+
astInfo: {
|
|
57
|
+
nodeType: "CallExpression",
|
|
58
|
+
object: "Atomics",
|
|
59
|
+
property: "waitAsync",
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
module.exports = { ES15_FEATURES };
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
const ES16_FEATURES = {
|
|
2
|
+
ArrayPrototypeGroup: {
|
|
3
|
+
minVersion: 16,
|
|
4
|
+
superseded: true,
|
|
5
|
+
supersededBy: "ObjectGroupBy",
|
|
6
|
+
example: "arr.group(x => x.category)",
|
|
7
|
+
astInfo: {
|
|
8
|
+
nodeType: "CallExpression",
|
|
9
|
+
property: "group",
|
|
10
|
+
excludeObjects: ["console"],
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
ArrayPrototypeGroupToMap: {
|
|
14
|
+
minVersion: 16,
|
|
15
|
+
superseded: true,
|
|
16
|
+
supersededBy: "MapGroupBy",
|
|
17
|
+
example: "arr.groupToMap(x => x.category)",
|
|
18
|
+
astInfo: {
|
|
19
|
+
nodeType: "CallExpression",
|
|
20
|
+
property: "groupToMap",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
PromiseTry: {
|
|
24
|
+
minVersion: 16,
|
|
25
|
+
example: "Promise.try(() => syncOrAsyncFunction())",
|
|
26
|
+
astInfo: {
|
|
27
|
+
nodeType: "CallExpression",
|
|
28
|
+
object: "Promise",
|
|
29
|
+
property: "try",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
DuplicateNamedCaptureGroups: {
|
|
33
|
+
minVersion: 16,
|
|
34
|
+
example: "/(?<name>a)|(?<name>b)/",
|
|
35
|
+
astInfo: {
|
|
36
|
+
nodeType: "RegExpLiteral",
|
|
37
|
+
duplicateNamedGroups: true,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
SetUnion: {
|
|
41
|
+
minVersion: 16,
|
|
42
|
+
example: "set1.union(set2)",
|
|
43
|
+
astInfo: {
|
|
44
|
+
nodeType: "CallExpression",
|
|
45
|
+
property: "union",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
SetIntersection: {
|
|
49
|
+
minVersion: 16,
|
|
50
|
+
example: "set1.intersection(set2)",
|
|
51
|
+
astInfo: {
|
|
52
|
+
nodeType: "CallExpression",
|
|
53
|
+
property: "intersection",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
SetDifference: {
|
|
57
|
+
minVersion: 16,
|
|
58
|
+
example: "set1.difference(set2)",
|
|
59
|
+
astInfo: {
|
|
60
|
+
nodeType: "CallExpression",
|
|
61
|
+
property: "difference",
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
SetSymmetricDifference: {
|
|
65
|
+
minVersion: 16,
|
|
66
|
+
example: "set1.symmetricDifference(set2)",
|
|
67
|
+
astInfo: {
|
|
68
|
+
nodeType: "CallExpression",
|
|
69
|
+
property: "symmetricDifference",
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
SetIsSubsetOf: {
|
|
73
|
+
minVersion: 16,
|
|
74
|
+
example: "set1.isSubsetOf(set2)",
|
|
75
|
+
astInfo: {
|
|
76
|
+
nodeType: "CallExpression",
|
|
77
|
+
property: "isSubsetOf",
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
SetIsSupersetOf: {
|
|
81
|
+
minVersion: 16,
|
|
82
|
+
example: "set1.isSupersetOf(set2)",
|
|
83
|
+
astInfo: {
|
|
84
|
+
nodeType: "CallExpression",
|
|
85
|
+
property: "isSupersetOf",
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
SetIsDisjointFrom: {
|
|
89
|
+
minVersion: 16,
|
|
90
|
+
example: "set1.isDisjointFrom(set2)",
|
|
91
|
+
astInfo: {
|
|
92
|
+
nodeType: "CallExpression",
|
|
93
|
+
property: "isDisjointFrom",
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
Float16Array: {
|
|
97
|
+
minVersion: 16,
|
|
98
|
+
example: "new Float16Array()",
|
|
99
|
+
astInfo: {
|
|
100
|
+
nodeType: "NewExpression",
|
|
101
|
+
callee: "Float16Array",
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
RegExpEscape: {
|
|
105
|
+
minVersion: 16,
|
|
106
|
+
example: "RegExp.escape(str)",
|
|
107
|
+
astInfo: {
|
|
108
|
+
nodeType: "CallExpression",
|
|
109
|
+
object: "RegExp",
|
|
110
|
+
property: "escape",
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
module.exports = { ES16_FEATURES };
|
|
@@ -1,10 +1,34 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { ES6_FEATURES } = require("./6");
|
|
2
|
+
const { ES7_FEATURES } = require("./7");
|
|
3
|
+
const { ES8_FEATURES } = require("./8");
|
|
4
|
+
const { ES9_FEATURES } = require("./9");
|
|
5
|
+
const { ES10_FEATURES } = require("./10");
|
|
6
|
+
const { ES11_FEATURES } = require("./11");
|
|
7
|
+
const { ES12_FEATURES } = require("./12");
|
|
8
|
+
const { ES13_FEATURES } = require("./13");
|
|
9
|
+
const { ES14_FEATURES } = require("./14");
|
|
10
|
+
const { ES15_FEATURES } = require("./15");
|
|
11
|
+
const { ES16_FEATURES } = require("./16");
|
|
2
12
|
const {
|
|
3
13
|
POLYFILL_PATTERNS,
|
|
4
14
|
IMPORT_PATTERNS,
|
|
5
15
|
FEATURE_TO_POLYFILL_MAP,
|
|
6
16
|
} = require("./polyfills");
|
|
7
17
|
|
|
18
|
+
const ES_FEATURES = {
|
|
19
|
+
...ES6_FEATURES,
|
|
20
|
+
...ES7_FEATURES,
|
|
21
|
+
...ES8_FEATURES,
|
|
22
|
+
...ES9_FEATURES,
|
|
23
|
+
...ES10_FEATURES,
|
|
24
|
+
...ES11_FEATURES,
|
|
25
|
+
...ES12_FEATURES,
|
|
26
|
+
...ES13_FEATURES,
|
|
27
|
+
...ES14_FEATURES,
|
|
28
|
+
...ES15_FEATURES,
|
|
29
|
+
...ES16_FEATURES,
|
|
30
|
+
};
|
|
31
|
+
|
|
8
32
|
module.exports = {
|
|
9
33
|
ES_FEATURES,
|
|
10
34
|
POLYFILL_PATTERNS,
|
package/lib/detectFeatures.js
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
const { fastBrakeSync } = require("fast-brake/sync");
|
|
2
1
|
const {
|
|
3
2
|
ES_FEATURES,
|
|
4
3
|
POLYFILL_PATTERNS,
|
|
5
4
|
IMPORT_PATTERNS,
|
|
6
5
|
FEATURE_TO_POLYFILL_MAP,
|
|
7
6
|
} = require("./constants");
|
|
8
|
-
const
|
|
7
|
+
const { detectFeaturesFromAST } = require("./helpers/astDetector");
|
|
9
8
|
|
|
10
|
-
const fastbrake = fastBrakeSync({ plugins: [esversionPlugin.default] });
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Detects polyfills in the code and adds them to the polyfills Set
|
|
14
|
-
* @param {string} code - The source code to check
|
|
15
|
-
* @param {Set} polyfills - Set to store detected polyfills
|
|
16
|
-
*/
|
|
17
9
|
const detectPolyfills = (
|
|
18
10
|
code,
|
|
19
11
|
polyfills,
|
|
@@ -35,54 +27,6 @@ const detectPolyfills = (
|
|
|
35
27
|
}
|
|
36
28
|
};
|
|
37
29
|
|
|
38
|
-
const featureNameMap = {
|
|
39
|
-
let_const: ["let", "const"],
|
|
40
|
-
arrow_functions: "ArrowFunctions",
|
|
41
|
-
template_literals: "TemplateLiterals",
|
|
42
|
-
destructuring: "Destructuring",
|
|
43
|
-
classes: "class",
|
|
44
|
-
extends: "extends",
|
|
45
|
-
spread_rest: ["RestSpread", "ArraySpread"],
|
|
46
|
-
default_parameters: "DefaultParams",
|
|
47
|
-
default_params: "DefaultParams",
|
|
48
|
-
for_of: "ForOf",
|
|
49
|
-
import: "import",
|
|
50
|
-
export: "export",
|
|
51
|
-
import_export: ["import", "export"],
|
|
52
|
-
async_await: "AsyncAwait",
|
|
53
|
-
generators: "Generators",
|
|
54
|
-
promise: "Promise",
|
|
55
|
-
promise_resolve: "PromiseResolve",
|
|
56
|
-
promise_reject: "PromiseReject",
|
|
57
|
-
promise_any: "PromiseAny",
|
|
58
|
-
promise_allSettled: "PromiseAllSettled",
|
|
59
|
-
map: "Map",
|
|
60
|
-
set: "Set",
|
|
61
|
-
weakmap: "WeakMap",
|
|
62
|
-
weakset: "WeakSet",
|
|
63
|
-
symbol: "Symbol",
|
|
64
|
-
proxy: "Proxy",
|
|
65
|
-
reflect: "Reflect",
|
|
66
|
-
weakref: "WeakRef",
|
|
67
|
-
finalization_registry: "FinalizationRegistry",
|
|
68
|
-
exponentiation: "ExponentOperator",
|
|
69
|
-
object_spread: "ObjectSpread",
|
|
70
|
-
rest_spread_properties: "ObjectSpread",
|
|
71
|
-
optional_catch: "OptionalCatchBinding",
|
|
72
|
-
bigint: "BigInt",
|
|
73
|
-
nullish_coalescing: "NullishCoalescing",
|
|
74
|
-
optional_chaining: "OptionalChaining",
|
|
75
|
-
private_fields: "PrivateClassFields",
|
|
76
|
-
logical_assignment: "LogicalAssignment",
|
|
77
|
-
numeric_separators: "NumericSeparators",
|
|
78
|
-
class_fields: "ClassFields",
|
|
79
|
-
top_level_await: "TopLevelAwait",
|
|
80
|
-
globalThis: "globalThis",
|
|
81
|
-
array_at: "ArrayPrototypeAt",
|
|
82
|
-
object_hasOwn: "ObjectHasOwn",
|
|
83
|
-
string_replaceAll: "StringReplaceAll",
|
|
84
|
-
};
|
|
85
|
-
|
|
86
30
|
const detectFeatures = (
|
|
87
31
|
code,
|
|
88
32
|
ecmaVersion,
|
|
@@ -92,56 +36,26 @@ const detectFeatures = (
|
|
|
92
36
|
) => {
|
|
93
37
|
const { checkForPolyfills, ast } = options;
|
|
94
38
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (ast) {
|
|
101
|
-
detectedFeatures = [];
|
|
102
|
-
} else {
|
|
103
|
-
try {
|
|
104
|
-
detectedFeatures = fastbrake.detect(code);
|
|
105
|
-
} catch (err) {
|
|
106
|
-
const error = new Error(`Failed to parse code: ${err.message}`);
|
|
107
|
-
error.type = "ES-Check";
|
|
108
|
-
throw error;
|
|
109
|
-
}
|
|
39
|
+
if (!ast) {
|
|
40
|
+
const error = new Error("AST is required for feature detection");
|
|
41
|
+
error.type = "ES-Check";
|
|
42
|
+
throw error;
|
|
110
43
|
}
|
|
111
44
|
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
return acc;
|
|
115
|
-
}, {});
|
|
116
|
-
|
|
117
|
-
detectedFeatures.forEach((feature) => {
|
|
118
|
-
const mapped = featureNameMap[feature.name];
|
|
119
|
-
|
|
120
|
-
if (mapped) {
|
|
121
|
-
if (Array.isArray(mapped)) {
|
|
122
|
-
mapped.forEach((name) => {
|
|
123
|
-
if (ES_FEATURES[name]) {
|
|
124
|
-
foundFeatures[name] = true;
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
} else if (ES_FEATURES[mapped]) {
|
|
128
|
-
foundFeatures[mapped] = true;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
});
|
|
45
|
+
const polyfills = new Set();
|
|
46
|
+
if (checkForPolyfills) detectPolyfills(code, polyfills);
|
|
132
47
|
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
});
|
|
48
|
+
const foundFeatures = detectFeaturesFromAST(ast);
|
|
49
|
+
|
|
50
|
+
const unsupportedFeatures = Object.entries(ES_FEATURES)
|
|
51
|
+
.filter(
|
|
52
|
+
([name, { minVersion }]) =>
|
|
53
|
+
foundFeatures[name] &&
|
|
54
|
+
minVersion > ecmaVersion &&
|
|
55
|
+
!ignoreList.has(name) &&
|
|
56
|
+
!(checkForPolyfills && polyfills.has(name)),
|
|
57
|
+
)
|
|
58
|
+
.map(([name]) => name);
|
|
145
59
|
|
|
146
60
|
if (unsupportedFeatures.length > 0) {
|
|
147
61
|
const error = new Error(
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
const { ES_FEATURES } = require("../constants");
|
|
2
|
+
const { checkMap } = require("./ast");
|
|
3
|
+
|
|
4
|
+
const CHILD_KEYS = [
|
|
5
|
+
"body",
|
|
6
|
+
"declarations",
|
|
7
|
+
"expression",
|
|
8
|
+
"left",
|
|
9
|
+
"right",
|
|
10
|
+
"argument",
|
|
11
|
+
"arguments",
|
|
12
|
+
"callee",
|
|
13
|
+
"object",
|
|
14
|
+
"property",
|
|
15
|
+
"properties",
|
|
16
|
+
"elements",
|
|
17
|
+
"params",
|
|
18
|
+
"id",
|
|
19
|
+
"init",
|
|
20
|
+
"test",
|
|
21
|
+
"consequent",
|
|
22
|
+
"alternate",
|
|
23
|
+
"cases",
|
|
24
|
+
"discriminant",
|
|
25
|
+
"block",
|
|
26
|
+
"handler",
|
|
27
|
+
"finalizer",
|
|
28
|
+
"source",
|
|
29
|
+
"specifiers",
|
|
30
|
+
"declaration",
|
|
31
|
+
"exported",
|
|
32
|
+
"imported",
|
|
33
|
+
"local",
|
|
34
|
+
"key",
|
|
35
|
+
"value",
|
|
36
|
+
"superClass",
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
function normalizeNodeType(nodeType) {
|
|
40
|
+
if (nodeType === "ExportDeclaration") {
|
|
41
|
+
return [
|
|
42
|
+
"ExportNamedDeclaration",
|
|
43
|
+
"ExportDefaultDeclaration",
|
|
44
|
+
"ExportAllDeclaration",
|
|
45
|
+
];
|
|
46
|
+
}
|
|
47
|
+
if (nodeType === "BigIntLiteral") {
|
|
48
|
+
return ["Literal"];
|
|
49
|
+
}
|
|
50
|
+
return [nodeType];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function buildFeatureIndex(features) {
|
|
54
|
+
const index = {};
|
|
55
|
+
for (const [name, { astInfo }] of Object.entries(features)) {
|
|
56
|
+
if (!astInfo?.nodeType) continue;
|
|
57
|
+
const types = normalizeNodeType(astInfo.nodeType);
|
|
58
|
+
for (const t of types) {
|
|
59
|
+
(index[t] ||= []).push({ name, astInfo });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return index;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const featuresByNodeType = buildFeatureIndex(ES_FEATURES);
|
|
66
|
+
|
|
67
|
+
function matchesFeature(node, astInfo) {
|
|
68
|
+
if (astInfo.childType) {
|
|
69
|
+
return node.elements?.some((el) => el?.type === astInfo.childType) || false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (astInfo.name && node.type === "Identifier") {
|
|
73
|
+
return node.name === astInfo.name;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (astInfo.nodeType === "BigIntLiteral") {
|
|
77
|
+
return node.bigint !== undefined;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (astInfo.kind && node.kind !== astInfo.kind) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (astInfo.operator && node.operator !== astInfo.operator) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (astInfo.property === "superClass") {
|
|
89
|
+
return node.superClass !== null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (node.type === "CallExpression" || node.type === "NewExpression") {
|
|
93
|
+
return checkMap(node, astInfo);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function detectFeaturesFromAST(ast) {
|
|
100
|
+
const foundFeatures = Object.create(null);
|
|
101
|
+
for (const key of Object.keys(ES_FEATURES)) {
|
|
102
|
+
foundFeatures[key] = false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const remaining = new Set(Object.keys(ES_FEATURES));
|
|
106
|
+
const stack = [ast];
|
|
107
|
+
|
|
108
|
+
while (stack.length > 0 && remaining.size > 0) {
|
|
109
|
+
const node = stack.pop();
|
|
110
|
+
if (!node || typeof node !== "object") continue;
|
|
111
|
+
|
|
112
|
+
const candidates = featuresByNodeType[node.type];
|
|
113
|
+
if (candidates) {
|
|
114
|
+
for (const { name, astInfo } of candidates) {
|
|
115
|
+
if (!remaining.has(name)) continue;
|
|
116
|
+
if (matchesFeature(node, astInfo)) {
|
|
117
|
+
foundFeatures[name] = true;
|
|
118
|
+
remaining.delete(name);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
for (const key of CHILD_KEYS) {
|
|
124
|
+
const child = node[key];
|
|
125
|
+
if (!child) continue;
|
|
126
|
+
if (Array.isArray(child)) {
|
|
127
|
+
for (let i = child.length - 1; i >= 0; i--) {
|
|
128
|
+
if (child[i]) stack.push(child[i]);
|
|
129
|
+
}
|
|
130
|
+
} else if (child.type) {
|
|
131
|
+
stack.push(child);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return foundFeatures;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
module.exports = {
|
|
140
|
+
normalizeNodeType,
|
|
141
|
+
buildFeatureIndex,
|
|
142
|
+
matchesFeature,
|
|
143
|
+
detectFeaturesFromAST,
|
|
144
|
+
};
|
package/lib/helpers/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const logger = require("./logger");
|
|
2
2
|
const parsers = require("./parsers");
|
|
3
3
|
const ast = require("./ast");
|
|
4
|
+
const astDetector = require("./astDetector");
|
|
4
5
|
const files = require("./files");
|
|
5
6
|
const cli = require("../cli/utils");
|
|
6
7
|
const sourcemap = require("./sourcemap");
|
|
@@ -12,6 +13,7 @@ module.exports = Object.assign(
|
|
|
12
13
|
logger,
|
|
13
14
|
parsers,
|
|
14
15
|
ast,
|
|
16
|
+
astDetector,
|
|
15
17
|
files,
|
|
16
18
|
cli,
|
|
17
19
|
sourcemap,
|
package/lib/helpers/parsers.js
CHANGED
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
const { fastBrakeSync } = require("fast-brake/sync");
|
|
2
|
-
const esversionPlugin = require("fast-brake/plugins/esversion");
|
|
3
|
-
const { ECMA_VERSION_MAP } = require("../constants/versions");
|
|
4
|
-
|
|
5
|
-
const fastbrake = fastBrakeSync({ plugins: [esversionPlugin.default] });
|
|
6
|
-
|
|
7
|
-
function getTargetVersion(ecmaVersion) {
|
|
8
|
-
return ECMA_VERSION_MAP[ecmaVersion] || "es5";
|
|
9
|
-
}
|
|
10
|
-
|
|
11
1
|
function parseCode(code, acornOpts, acorn, file) {
|
|
12
2
|
try {
|
|
13
3
|
const ast = acorn.parse(code, acornOpts);
|
|
@@ -30,46 +20,6 @@ function parseCode(code, acornOpts, acorn, file) {
|
|
|
30
20
|
}
|
|
31
21
|
}
|
|
32
22
|
|
|
33
|
-
function parseLightMode(code, ecmaVersion, isModule, allowHashBang, file) {
|
|
34
|
-
const targetVersion = getTargetVersion(ecmaVersion);
|
|
35
|
-
|
|
36
|
-
const codeToCheck =
|
|
37
|
-
allowHashBang && code.startsWith("#!")
|
|
38
|
-
? code.slice(code.indexOf("\n") + 1)
|
|
39
|
-
: code;
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
const isCompatible = fastbrake.check(codeToCheck, {
|
|
43
|
-
target: targetVersion,
|
|
44
|
-
sourceType: isModule ? "module" : "script",
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
if (!isCompatible) {
|
|
48
|
-
return {
|
|
49
|
-
error: {
|
|
50
|
-
err: new Error(
|
|
51
|
-
`Code contains features incompatible with ${targetVersion}`,
|
|
52
|
-
),
|
|
53
|
-
stack: "",
|
|
54
|
-
file,
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return { error: null };
|
|
60
|
-
} catch (err) {
|
|
61
|
-
return {
|
|
62
|
-
error: {
|
|
63
|
-
err: new Error(`Failed to check code in light mode: ${err.message}`),
|
|
64
|
-
stack: err.stack || "",
|
|
65
|
-
file,
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
23
|
module.exports = {
|
|
72
|
-
getTargetVersion,
|
|
73
24
|
parseCode,
|
|
74
|
-
parseLightMode,
|
|
75
25
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "es-check",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.5.0",
|
|
4
4
|
"description": "Checks the ECMAScript version of .js glob against a specified version of ECMAScript with a shell command",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,8 +17,6 @@
|
|
|
17
17
|
"es-check": "lib/cli/index.js"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
|
-
"commit": "git-cz",
|
|
21
|
-
"commit-msg": "commitlint --edit $1",
|
|
22
20
|
"dev": "pnpm site:dev",
|
|
23
21
|
"lint": "oxlint lib",
|
|
24
22
|
"lint:ci": "oxlint lib --quiet",
|
|
@@ -52,11 +50,9 @@
|
|
|
52
50
|
"url": "https://github.com/yowainwright/es-check/issues"
|
|
53
51
|
},
|
|
54
52
|
"homepage": "https://github.com/yowainwright/es-check#readme",
|
|
53
|
+
"website": "https://jeffry.in/es-check",
|
|
55
54
|
"devDependencies": {
|
|
56
|
-
"@commitlint/cli": "20.1.0",
|
|
57
|
-
"@commitlint/config-conventional": "^20.0.0",
|
|
58
55
|
"codependence": "^0.3.1",
|
|
59
|
-
"commitizen": "4.3.1",
|
|
60
56
|
"oxlint": "^1.29.0",
|
|
61
57
|
"pastoralist": "1.8.2",
|
|
62
58
|
"prettier": "3.6.2",
|
|
@@ -65,7 +61,6 @@
|
|
|
65
61
|
"dependencies": {
|
|
66
62
|
"acorn": "8.15.0",
|
|
67
63
|
"browserslist": "^4.28.0",
|
|
68
|
-
"fast-brake": "^0.1.6",
|
|
69
64
|
"fast-glob": "^3.3.3"
|
|
70
65
|
},
|
|
71
66
|
"engines": {
|
|
@@ -90,18 +85,6 @@
|
|
|
90
85
|
"test js version",
|
|
91
86
|
"test ecmascript version"
|
|
92
87
|
],
|
|
93
|
-
"commitlint": {
|
|
94
|
-
"extends": [
|
|
95
|
-
"@commitlint/config-conventional"
|
|
96
|
-
],
|
|
97
|
-
"rules": {
|
|
98
|
-
"header-max-length": [
|
|
99
|
-
2,
|
|
100
|
-
"always",
|
|
101
|
-
120
|
|
102
|
-
]
|
|
103
|
-
}
|
|
104
|
-
},
|
|
105
88
|
"release-it": {
|
|
106
89
|
"git": {
|
|
107
90
|
"commitMessage": "chore: release v${version}",
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
const ES15_FEATURES = {
|
|
2
|
-
StringIsWellFormed: {
|
|
3
|
-
minVersion: 15,
|
|
4
|
-
example: "str.isWellFormed()",
|
|
5
|
-
astInfo: {
|
|
6
|
-
nodeType: "CallExpression",
|
|
7
|
-
property: "isWellFormed",
|
|
8
|
-
},
|
|
9
|
-
},
|
|
10
|
-
StringToWellFormed: {
|
|
11
|
-
minVersion: 15,
|
|
12
|
-
example: "str.toWellFormed()",
|
|
13
|
-
astInfo: {
|
|
14
|
-
nodeType: "CallExpression",
|
|
15
|
-
property: "toWellFormed",
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
RegExpUnicodeSetFlag: {
|
|
19
|
-
minVersion: 15,
|
|
20
|
-
example: "/pattern/v",
|
|
21
|
-
astInfo: {
|
|
22
|
-
nodeType: "RegExpLiteral",
|
|
23
|
-
flags: "v",
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
module.exports = { ES15_FEATURES };
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
const ES16_FEATURES = {
|
|
2
|
-
ArrayGroup: {
|
|
3
|
-
minVersion: 16,
|
|
4
|
-
example: "arr.group(x => x.category)",
|
|
5
|
-
astInfo: {
|
|
6
|
-
nodeType: "CallExpression",
|
|
7
|
-
property: "group",
|
|
8
|
-
excludeObjects: ["console"],
|
|
9
|
-
},
|
|
10
|
-
},
|
|
11
|
-
ArrayGroupToMap: {
|
|
12
|
-
minVersion: 16,
|
|
13
|
-
example: "arr.groupToMap(x => x.category)",
|
|
14
|
-
astInfo: {
|
|
15
|
-
nodeType: "CallExpression",
|
|
16
|
-
property: "groupToMap",
|
|
17
|
-
excludeObjects: ["console"],
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
PromiseTry: {
|
|
21
|
-
minVersion: 16,
|
|
22
|
-
example: "Promise.try(() => syncOrAsyncFunction())",
|
|
23
|
-
astInfo: {
|
|
24
|
-
nodeType: "CallExpression",
|
|
25
|
-
object: "Promise",
|
|
26
|
-
property: "try",
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
DuplicateNamedCaptureGroups: {
|
|
30
|
-
minVersion: 16,
|
|
31
|
-
example: "/(?<name>a)|(?<name>b)/",
|
|
32
|
-
astInfo: {
|
|
33
|
-
nodeType: "RegExpLiteral",
|
|
34
|
-
duplicateNamedGroups: true,
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
module.exports = { ES16_FEATURES };
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
const { ES6_FEATURES } = require("./6");
|
|
2
|
-
const { ES7_FEATURES } = require("./7");
|
|
3
|
-
const { ES8_FEATURES } = require("./8");
|
|
4
|
-
const { ES9_FEATURES } = require("./9");
|
|
5
|
-
const { ES10_FEATURES } = require("./10");
|
|
6
|
-
const { ES11_FEATURES } = require("./11");
|
|
7
|
-
const { ES12_FEATURES } = require("./12");
|
|
8
|
-
const { ES13_FEATURES } = require("./13");
|
|
9
|
-
const { ES14_FEATURES } = require("./14");
|
|
10
|
-
const { ES15_FEATURES } = require("./15");
|
|
11
|
-
const { ES16_FEATURES } = require("./16");
|
|
12
|
-
|
|
13
|
-
const ES_FEATURES = {
|
|
14
|
-
...ES6_FEATURES,
|
|
15
|
-
...ES7_FEATURES,
|
|
16
|
-
...ES8_FEATURES,
|
|
17
|
-
...ES9_FEATURES,
|
|
18
|
-
...ES10_FEATURES,
|
|
19
|
-
...ES11_FEATURES,
|
|
20
|
-
...ES12_FEATURES,
|
|
21
|
-
...ES13_FEATURES,
|
|
22
|
-
...ES14_FEATURES,
|
|
23
|
-
...ES15_FEATURES,
|
|
24
|
-
...ES16_FEATURES,
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
module.exports = { ES_FEATURES };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|