es-check 9.6.4 → 9.7.2

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.
@@ -10,29 +10,29 @@ const { ES14_FEATURES } = require("./14");
10
10
  const { ES15_FEATURES } = require("./15");
11
11
  const { ES16_FEATURES } = require("./16");
12
12
  const { ES17_FEATURES } = require("./17");
13
- const {
14
- POLYFILL_PATTERNS,
15
- IMPORT_PATTERNS,
16
- FEATURE_TO_POLYFILL_MAP,
17
- } = require("./polyfills");
13
+ const { ES_GLOBAL_MIN_VERSION, ES_GLOBALS_SOURCE } = require("./globals");
14
+ const { POLYFILL_PATTERNS, IMPORT_PATTERNS, FEATURE_TO_POLYFILL_MAP } = require("./polyfills");
18
15
 
19
- const ES_FEATURES = {
20
- ...ES6_FEATURES,
21
- ...ES7_FEATURES,
22
- ...ES8_FEATURES,
23
- ...ES9_FEATURES,
24
- ...ES10_FEATURES,
25
- ...ES11_FEATURES,
26
- ...ES12_FEATURES,
27
- ...ES13_FEATURES,
28
- ...ES14_FEATURES,
29
- ...ES15_FEATURES,
30
- ...ES16_FEATURES,
31
- ...ES17_FEATURES,
32
- };
16
+ const ES_FEATURES = Object.assign(
17
+ {},
18
+ ES6_FEATURES,
19
+ ES7_FEATURES,
20
+ ES8_FEATURES,
21
+ ES9_FEATURES,
22
+ ES10_FEATURES,
23
+ ES11_FEATURES,
24
+ ES12_FEATURES,
25
+ ES13_FEATURES,
26
+ ES14_FEATURES,
27
+ ES15_FEATURES,
28
+ ES16_FEATURES,
29
+ ES17_FEATURES,
30
+ );
33
31
 
34
32
  module.exports = {
35
33
  ES_FEATURES,
34
+ ES_GLOBAL_MIN_VERSION,
35
+ ES_GLOBALS_SOURCE,
36
36
  POLYFILL_PATTERNS,
37
37
  IMPORT_PATTERNS,
38
38
  FEATURE_TO_POLYFILL_MAP,
@@ -14,13 +14,11 @@ const POLYFILL_PATTERNS = [
14
14
 
15
15
  const IMPORT_PATTERNS = [
16
16
  {
17
- pattern:
18
- /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.array\.to-sorted['"]/,
17
+ pattern: /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.array\.to-sorted['"]/,
19
18
  feature: "ArrayToSorted",
20
19
  },
21
20
  {
22
- pattern:
23
- /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.array\.find-last['"]/,
21
+ pattern: /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.array\.find-last['"]/,
24
22
  feature: "ArrayFindLast",
25
23
  },
26
24
  {
@@ -29,8 +27,7 @@ const IMPORT_PATTERNS = [
29
27
  feature: "ArrayFindLastIndex",
30
28
  },
31
29
  {
32
- pattern:
33
- /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.array\.at['"]/,
30
+ pattern: /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.array\.at['"]/,
34
31
  feature: "ArrayAt",
35
32
  },
36
33
  {
@@ -39,33 +36,27 @@ const IMPORT_PATTERNS = [
39
36
  feature: "StringReplaceAll",
40
37
  },
41
38
  {
42
- pattern:
43
- /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.string\.match-all['"]/,
39
+ pattern: /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.string\.match-all['"]/,
44
40
  feature: "StringMatchAll",
45
41
  },
46
42
  {
47
- pattern:
48
- /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.string\.at['"]/,
43
+ pattern: /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.string\.at['"]/,
49
44
  feature: "StringAt",
50
45
  },
51
46
  {
52
- pattern:
53
- /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.object\.has-own['"]/,
47
+ pattern: /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.object\.has-own['"]/,
54
48
  feature: "ObjectHasOwn",
55
49
  },
56
50
  {
57
- pattern:
58
- /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.promise\.any['"]/,
51
+ pattern: /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.promise\.any['"]/,
59
52
  feature: "PromiseAny",
60
53
  },
61
54
  {
62
- pattern:
63
- /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.regexp\.exec['"]/,
55
+ pattern: /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.regexp\.exec['"]/,
64
56
  feature: "RegExpExec",
65
57
  },
66
58
  {
67
- pattern:
68
- /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.global-this['"]/,
59
+ pattern: /(?:from\s+|require\s*\(\s*|import\s+)['"]core-js\/modules\/es\.global-this['"]/,
69
60
  feature: "GlobalThis",
70
61
  },
71
62
  ];
@@ -94,11 +85,7 @@ const FEATURE_TO_POLYFILL_MAP = {
94
85
  /['"]core-js\/modules\/es\.object\.assign['"]/,
95
86
  /\bobject-assign\b/,
96
87
  ],
97
- Promise: [
98
- /\bPromise\s*=/,
99
- /['"]core-js\/modules\/es\.promise['"]/,
100
- /es6-promise/,
101
- ],
88
+ Promise: [/\bPromise\s*=/, /['"]core-js\/modules\/es\.promise['"]/, /es6-promise/],
102
89
  "String.prototype.startsWith": [
103
90
  /\bString\.prototype\.startsWith\s*=/,
104
91
  /['"]core-js\/modules\/es\.string\.starts-with['"]/,
@@ -122,14 +109,8 @@ const FEATURE_TO_POLYFILL_MAP = {
122
109
  /['"]core-js\/modules\/es\.array\.includes['"]/,
123
110
  ],
124
111
 
125
- "Object.values": [
126
- /\bObject\.values\s*=/,
127
- /['"]core-js\/modules\/es\.object\.values['"]/,
128
- ],
129
- "Object.entries": [
130
- /\bObject\.entries\s*=/,
131
- /['"]core-js\/modules\/es\.object\.entries['"]/,
132
- ],
112
+ "Object.values": [/\bObject\.values\s*=/, /['"]core-js\/modules\/es\.object\.values['"]/],
113
+ "Object.entries": [/\bObject\.entries\s*=/, /['"]core-js\/modules\/es\.object\.entries['"]/],
133
114
  "Object.getOwnPropertyDescriptors": [
134
115
  /\bObject\.getOwnPropertyDescriptors\s*=/,
135
116
  /['"]core-js\/modules\/es\.object\.get-own-property-descriptors['"]/,
@@ -180,10 +161,7 @@ const FEATURE_TO_POLYFILL_MAP = {
180
161
  globalThis: [/\bglobalThis\s*=/, /['"]core-js\/modules\/es\.global-this['"]/],
181
162
  BigInt: [/\bBigInt\s*=/, /['"]core-js\/modules\/es\.bigint['"]/],
182
163
 
183
- "Promise.any": [
184
- /\bPromise\.any\s*=/,
185
- /['"]core-js\/modules\/es\.promise\.any['"]/,
186
- ],
164
+ "Promise.any": [/\bPromise\.any\s*=/, /['"]core-js\/modules\/es\.promise\.any['"]/],
187
165
  "String.prototype.replaceAll": [
188
166
  /\bString\.prototype\.replaceAll\s*=/,
189
167
  /['"]core-js\/modules\/es\.string\.replace-all['"]/,
@@ -238,10 +216,7 @@ const FEATURE_TO_POLYFILL_MAP = {
238
216
  /\bcore[-_]js[-_]modules[-_][^/\n]*array[-_]with/,
239
217
  ],
240
218
 
241
- "Object.hasOwn": [
242
- /\bObject\.hasOwn\s*=/,
243
- /['"]core-js\/modules\/es\.object\.has-own['"]/,
244
- ],
219
+ "Object.hasOwn": [/\bObject\.hasOwn\s*=/, /['"]core-js\/modules\/es\.object\.has-own['"]/],
245
220
  "String.prototype.isWellFormed": [
246
221
  /\bString\.prototype\.isWellFormed\s*=/,
247
222
  /['"]core-js\/modules\/es\.string\.is-well-formed['"]/,
@@ -259,10 +234,7 @@ const FEATURE_TO_POLYFILL_MAP = {
259
234
  /\bArray\.prototype\.groupToMap\s*=/,
260
235
  /['"]core-js\/modules\/es\.array\.group-to-map['"]/,
261
236
  ],
262
- "Promise.try": [
263
- /\bPromise\.try\s*=/,
264
- /['"]core-js\/modules\/es\.promise\.try['"]/,
265
- ],
237
+ "Promise.try": [/\bPromise\.try\s*=/, /['"]core-js\/modules\/es\.promise\.try['"]/],
266
238
 
267
239
  "Array.fromAsync": [
268
240
  /\bArray\.fromAsync\s*=/,
@@ -20,19 +20,14 @@ function getParserVersionForFeature(featureName, targetEsVersion) {
20
20
  return Math.max(targetEsVersion, requiredParser);
21
21
  }
22
22
 
23
- function getMinimumParserVersion(
24
- targetEsVersion,
25
- enableFeatureDetection = false,
26
- ) {
23
+ function getMinimumParserVersion(targetEsVersion, enableFeatureDetection = false) {
27
24
  if (!enableFeatureDetection) {
28
25
  return targetEsVersion;
29
26
  }
30
27
 
31
28
  let minParserVersion = targetEsVersion;
32
29
 
33
- for (const [_feature, requiredParser] of Object.entries(
34
- FEATURE_PARSER_REQUIREMENTS,
35
- )) {
30
+ for (const [_feature, requiredParser] of Object.entries(FEATURE_PARSER_REQUIREMENTS)) {
36
31
  if (targetEsVersion >= requiredParser) {
37
32
  minParserVersion = Math.max(minParserVersion, requiredParser);
38
33
  }
@@ -1,4 +1,62 @@
1
1
  const versions = require("./versions");
2
2
  const esFeatures = require("./es-features");
3
3
 
4
- module.exports = Object.assign({}, versions, esFeatures);
4
+ const receiverHeuristics = {
5
+ ARRAY_CONSTRUCTOR_FUNCTIONS: new Set(["Array", "from", "of", "slice", "filter", "map", "concat"]),
6
+ ARRAY_LIKE_NAMES: new Set(["arr", "array", "list", "items", "values", "arguments"]),
7
+ ARRAY_METHODS: new Set(["slice", "filter", "map", "concat", "from", "of"]),
8
+ COMMON_NON_ARRAY_NAMES: new Set([
9
+ "obj",
10
+ "object",
11
+ "foo",
12
+ "bar",
13
+ "baz",
14
+ "data",
15
+ "config",
16
+ "options",
17
+ "params",
18
+ "props",
19
+ "state",
20
+ "item",
21
+ "element",
22
+ "node",
23
+ "target",
24
+ "source",
25
+ "result",
26
+ "response",
27
+ "request",
28
+ "payload",
29
+ "model",
30
+ "view",
31
+ "controller",
32
+ "service",
33
+ "utils",
34
+ "helpers",
35
+ "custom",
36
+ ]),
37
+ COMMON_NON_SET_NAMES: new Set([
38
+ "settings",
39
+ "setup",
40
+ "setter",
41
+ "setstate",
42
+ "setvalue",
43
+ "setdata",
44
+ "setitem",
45
+ "setinterval",
46
+ "settimeout",
47
+ "offset",
48
+ "dataset",
49
+ "reset",
50
+ "asset",
51
+ "charset",
52
+ "onset",
53
+ "subset",
54
+ "mindset",
55
+ "closet",
56
+ "baseset",
57
+ ]),
58
+ MAP_CONSTRUCTORS: new Set(["Map", "WeakMap"]),
59
+ SET_LIKE_NAMES: new Set(["set", "sets", "seta", "setb", "set1", "set2"]),
60
+ };
61
+
62
+ module.exports = Object.assign({}, versions, esFeatures, receiverHeuristics);
@@ -22,10 +22,16 @@ const coreJsPolyfillable = new Set([
22
22
  "ArrayToSorted",
23
23
  "ArrayToSpliced",
24
24
  "ArrayWith",
25
+ "DataViewGetFloat16",
26
+ "DataViewSetFloat16",
25
27
  "ErrorCause",
26
28
  "ErrorIsError",
29
+ "IteratorConcat",
27
30
  "Map",
31
+ "MapGetOrInsert",
32
+ "MapGetOrInsertComputed",
28
33
  "MapGroupBy",
34
+ "MathSumPrecise",
29
35
  "ObjectEntries",
30
36
  "ObjectFromEntries",
31
37
  "ObjectGroupBy",
@@ -55,6 +61,12 @@ const coreJsPolyfillable = new Set([
55
61
  "StringReplaceAll",
56
62
  "StringToWellFormed",
57
63
  "Symbol",
64
+ "Uint8ArrayFromBase64",
65
+ "Uint8ArrayFromHex",
66
+ "Uint8ArraySetFromBase64",
67
+ "Uint8ArraySetFromHex",
68
+ "Uint8ArrayToBase64",
69
+ "Uint8ArrayToHex",
58
70
  "WeakMap",
59
71
  "WeakSet",
60
72
  "globalThis",
@@ -223,7 +223,7 @@ const VERSION_ORDER = [
223
223
  "es2026",
224
224
  ];
225
225
 
226
- const LATEST_PARSER_VERSION = 2025;
226
+ const LATEST_PARSER_VERSION = 2026;
227
227
 
228
228
  module.exports = {
229
229
  ECMA_VERSION_MAP,
@@ -4,10 +4,8 @@ const {
4
4
  IMPORT_PATTERNS,
5
5
  FEATURE_TO_POLYFILL_MAP,
6
6
  } = require("./constants");
7
- const {
8
- POLYFILLABLE_FEATURES,
9
- CORE_JS_POLYFILLABLE,
10
- } = require("./constants/polyfillableFeatures");
7
+ const { ES_GLOBAL_MIN_VERSION } = require("./constants/es-features/globals");
8
+ const { POLYFILLABLE_FEATURES, CORE_JS_POLYFILLABLE } = require("./constants/polyfillableFeatures");
11
9
  const { detectFeaturesFromAST } = require("./helpers/astDetector");
12
10
 
13
11
  function getPolyfillableFeatures(library) {
@@ -18,9 +16,7 @@ function getPolyfillableFeatures(library) {
18
16
  let normalizedLibrary;
19
17
  try {
20
18
  normalizedLibrary =
21
- typeof library === "string"
22
- ? library.toLowerCase()
23
- : String(library).toLowerCase();
19
+ typeof library === "string" ? library.toLowerCase() : String(library).toLowerCase();
24
20
  } catch {
25
21
  return POLYFILLABLE_FEATURES;
26
22
  }
@@ -35,19 +31,16 @@ function getPolyfillableFeatures(library) {
35
31
  const detectPolyfills = (
36
32
  code,
37
33
  polyfills,
38
- {
39
- polyfillPatterns = POLYFILL_PATTERNS,
40
- importPatterns = IMPORT_PATTERNS,
41
- } = {},
34
+ { polyfillPatterns = POLYFILL_PATTERNS, importPatterns = IMPORT_PATTERNS } = {},
42
35
  ) => {
43
- if (code.includes("core-js") || code.includes("polyfill")) {
36
+ const hasPolyfillHint = code.includes("core-js") || code.includes("polyfill");
37
+ if (hasPolyfillHint) {
44
38
  for (const { pattern, feature } of polyfillPatterns) {
45
39
  if (pattern.test(code)) polyfills.add(feature);
46
40
  }
47
41
 
48
42
  const hasCoreJsModuleRef =
49
- (code.includes("import") || code.includes("require")) &&
50
- code.includes("core-js");
43
+ (code.includes("import") || code.includes("require")) && code.includes("core-js");
51
44
  if (hasCoreJsModuleRef) {
52
45
  for (const { pattern, feature } of importPatterns) {
53
46
  if (pattern.test(code)) polyfills.add(feature);
@@ -56,13 +49,7 @@ const detectPolyfills = (
56
49
  }
57
50
  };
58
51
 
59
- const detectFeatures = (
60
- code,
61
- ecmaVersion,
62
- sourceType,
63
- ignoreList = new Set(),
64
- options = {},
65
- ) => {
52
+ const detectFeatures = (code, ecmaVersion, sourceType, ignoreList = new Set(), options = {}) => {
66
53
  const { checkForPolyfills, ast, ignorePolyfillable } = options;
67
54
 
68
55
  if (!ast) {
@@ -76,21 +63,32 @@ const detectFeatures = (
76
63
 
77
64
  const foundFeatures = detectFeaturesFromAST(ast);
78
65
 
79
- const polyfillableSet = ignorePolyfillable
80
- ? getPolyfillableFeatures(ignorePolyfillable)
81
- : null;
82
-
83
- const unsupportedFeatures = Object.entries(ES_FEATURES)
84
- .filter(
85
- ([name, { minVersion }]) =>
86
- foundFeatures[name] &&
87
- minVersion > ecmaVersion &&
88
- !ignoreList.has(name) &&
89
- !(checkForPolyfills && polyfills.has(name)) &&
90
- !(polyfillableSet && polyfillableSet.has(name)),
91
- )
66
+ const polyfillableSet = ignorePolyfillable ? getPolyfillableFeatures(ignorePolyfillable) : null;
67
+
68
+ function isUnsupportedFeature(name, minVersion) {
69
+ const wasFound = foundFeatures[name];
70
+ const requiresHigherVersion = minVersion > ecmaVersion;
71
+ const isIgnored = ignoreList.has(name);
72
+ const isPolyfilled = checkForPolyfills && polyfills.has(name);
73
+ const isPolyfillableIgnored = polyfillableSet && polyfillableSet.has(name);
74
+
75
+ const isAllowed = isIgnored || isPolyfilled || isPolyfillableIgnored;
76
+ const shouldReport = wasFound && requiresHigherVersion;
77
+ if (!shouldReport) return false;
78
+ return !isAllowed;
79
+ }
80
+
81
+ const unsupportedStandardFeatures = Object.entries(ES_FEATURES)
82
+ .filter(([name, { minVersion }]) => isUnsupportedFeature(name, minVersion))
83
+ .map(([name]) => name);
84
+
85
+ const unsupportedGlobalFeatures = Object.entries(ES_GLOBAL_MIN_VERSION)
86
+ .filter(([name]) => !ES_FEATURES[name])
87
+ .filter(([name, minVersion]) => isUnsupportedFeature(name, minVersion))
92
88
  .map(([name]) => name);
93
89
 
90
+ const unsupportedFeatures = unsupportedStandardFeatures.concat(unsupportedGlobalFeatures);
91
+
94
92
  if (unsupportedFeatures.length > 0) {
95
93
  const error = new Error(
96
94
  `Unsupported features detected: ${unsupportedFeatures.join(", ")}. ` +
@@ -108,42 +106,48 @@ const detectFeatures = (
108
106
  };
109
107
  };
110
108
 
111
- function detectPolyfillsForFeatures(
112
- code,
113
- logger,
114
- featureMap = FEATURE_TO_POLYFILL_MAP,
115
- ) {
109
+ function detectPolyfillsForFeatures(code, logger, featureMap = FEATURE_TO_POLYFILL_MAP) {
116
110
  const polyfills = new Set();
117
- if (!code || !featureMap) return polyfills;
111
+ const hasNoPolyfillInput = !code || !featureMap;
112
+ if (hasNoPolyfillInput) return polyfills;
118
113
 
119
114
  const polyfillFeatures = Object.entries(featureMap);
120
- polyfillFeatures.forEach(([feature, patterns]) => {
121
- const isPolyfilled = patterns.some((pattern) => pattern.test(code));
115
+ let index = 0;
116
+ while (index < polyfillFeatures.length) {
117
+ const [feature, patterns] = polyfillFeatures[index];
118
+ const isPolyfilled = hasMatchingPattern(code, patterns);
122
119
  if (isPolyfilled) polyfills.add(feature);
123
- });
120
+ index += 1;
121
+ }
124
122
 
125
123
  if (logger?.isLevelEnabled?.("debug")) {
126
124
  const hasPolyfills = polyfills.size > 0;
127
125
  if (hasPolyfills)
128
- logger.debug(
129
- `ES-Check: Detected polyfills: ${Array.from(polyfills).join(", ")}`,
130
- );
126
+ logger.debug(`ES-Check: Detected polyfills: ${Array.from(polyfills).join(", ")}`);
131
127
  else logger.debug("ES-Check: No polyfills detected.");
132
128
  }
133
129
 
134
130
  return polyfills;
135
131
  }
136
132
 
133
+ function hasMatchingPattern(code, patterns) {
134
+ let index = 0;
135
+ while (index < patterns.length) {
136
+ const pattern = patterns[index];
137
+ if (pattern.test(code)) return true;
138
+ index += 1;
139
+ }
140
+
141
+ return false;
142
+ }
143
+
137
144
  const filterPolyfilled = (unsupportedFeatures, polyfills) => {
138
145
  const hasPolyfills = polyfills && polyfills.size > 0;
139
146
  if (!hasPolyfills) return unsupportedFeatures;
140
147
  return unsupportedFeatures.filter((feature) => !polyfills.has(feature));
141
148
  };
142
149
 
143
- const filterPolyfillableFeatures = (
144
- unsupportedFeatures,
145
- ignorePolyfillable,
146
- ) => {
150
+ const filterPolyfillableFeatures = (unsupportedFeatures, ignorePolyfillable) => {
147
151
  if (!ignorePolyfillable) return unsupportedFeatures;
148
152
 
149
153
  const polyfillableSet = getPolyfillableFeatures(ignorePolyfillable);