es-check 9.7.2 → 9.8.1
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 +16 -4
- package/lib/browserslist.js +54 -6
- package/lib/check-runner/index.js +2 -1
- package/lib/check-runner/utils.js +41 -15
- package/lib/constants/es-features/browserSupport.js +2421 -0
- package/lib/constants/es-features/index.js +2 -0
- package/lib/constants/featureParserMapping.js +7 -2
- package/lib/constants/polyfillableFeatures.js +7 -10
- package/lib/constants/versions.js +18 -0
- package/lib/detectFeatures.js +25 -9
- package/lib/helpers/browserSupport.js +89 -0
- package/package.json +24 -23
|
@@ -12,6 +12,7 @@ const { ES16_FEATURES } = require("./16");
|
|
|
12
12
|
const { ES17_FEATURES } = require("./17");
|
|
13
13
|
const { ES_GLOBAL_MIN_VERSION, ES_GLOBALS_SOURCE } = require("./globals");
|
|
14
14
|
const { POLYFILL_PATTERNS, IMPORT_PATTERNS, FEATURE_TO_POLYFILL_MAP } = require("./polyfills");
|
|
15
|
+
const { FEATURE_BROWSER_SUPPORT } = require("./browserSupport");
|
|
15
16
|
|
|
16
17
|
const ES_FEATURES = Object.assign(
|
|
17
18
|
{},
|
|
@@ -36,4 +37,5 @@ module.exports = {
|
|
|
36
37
|
POLYFILL_PATTERNS,
|
|
37
38
|
IMPORT_PATTERNS,
|
|
38
39
|
FEATURE_TO_POLYFILL_MAP,
|
|
40
|
+
FEATURE_BROWSER_SUPPORT,
|
|
39
41
|
};
|
|
@@ -20,14 +20,19 @@ function getParserVersionForFeature(featureName, targetEsVersion) {
|
|
|
20
20
|
return Math.max(targetEsVersion, requiredParser);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
function getMinimumParserVersion(
|
|
23
|
+
function getMinimumParserVersion(
|
|
24
|
+
targetEsVersion,
|
|
25
|
+
enableFeatureDetection = false,
|
|
26
|
+
) {
|
|
24
27
|
if (!enableFeatureDetection) {
|
|
25
28
|
return targetEsVersion;
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
let minParserVersion = targetEsVersion;
|
|
29
32
|
|
|
30
|
-
for (const [_feature, requiredParser] of Object.entries(
|
|
33
|
+
for (const [_feature, requiredParser] of Object.entries(
|
|
34
|
+
FEATURE_PARSER_REQUIREMENTS,
|
|
35
|
+
)) {
|
|
31
36
|
if (targetEsVersion >= requiredParser) {
|
|
32
37
|
minParserVersion = Math.max(minParserVersion, requiredParser);
|
|
33
38
|
}
|
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* These values use es-check's internal feature names (e.g. "ArrayToSorted"),
|
|
5
|
-
* not core-js module names (e.g. "es.array.to-sorted"). Core-js module names
|
|
6
|
-
* cannot be used directly because es-check matches features against its own
|
|
7
|
-
* ES_FEATURES keys, which follow PascalCase naming derived from acorn AST
|
|
8
|
-
* detection. The generation script bridges the two naming schemes by converting
|
|
9
|
-
* core-js modules to es-check feature names and intersecting with ES_FEATURES.
|
|
10
|
-
*/
|
|
1
|
+
// Generated from core-js-compat 3.50.0; run pnpm scripts:generate:polyfills.
|
|
2
|
+
// Feature names are mapped explicitly in scripts/constants.mjs.
|
|
11
3
|
const coreJsPolyfillable = new Set([
|
|
4
|
+
"AggregateError",
|
|
12
5
|
"ArrayBufferTransfer",
|
|
13
6
|
"ArrayBufferTransferToFixedLength",
|
|
14
7
|
"ArrayFindLast",
|
|
@@ -22,11 +15,15 @@ const coreJsPolyfillable = new Set([
|
|
|
22
15
|
"ArrayToSorted",
|
|
23
16
|
"ArrayToSpliced",
|
|
24
17
|
"ArrayWith",
|
|
18
|
+
"DataView",
|
|
25
19
|
"DataViewGetFloat16",
|
|
26
20
|
"DataViewSetFloat16",
|
|
27
21
|
"ErrorCause",
|
|
28
22
|
"ErrorIsError",
|
|
23
|
+
"Iterator",
|
|
29
24
|
"IteratorConcat",
|
|
25
|
+
"JSONIsRawJSON",
|
|
26
|
+
"JSONRawJSON",
|
|
30
27
|
"Map",
|
|
31
28
|
"MapGetOrInsert",
|
|
32
29
|
"MapGetOrInsertComputed",
|
|
@@ -225,10 +225,28 @@ const VERSION_ORDER = [
|
|
|
225
225
|
|
|
226
226
|
const LATEST_PARSER_VERSION = 2026;
|
|
227
227
|
|
|
228
|
+
const BROWSERSLIST_TO_BCD = {
|
|
229
|
+
and_chr: "chrome_android",
|
|
230
|
+
and_ff: "firefox_android",
|
|
231
|
+
android: "webview_android",
|
|
232
|
+
chrome: "chrome",
|
|
233
|
+
deno: "deno",
|
|
234
|
+
edge: "edge",
|
|
235
|
+
firefox: "firefox",
|
|
236
|
+
ie: "ie",
|
|
237
|
+
ios_saf: "safari_ios",
|
|
238
|
+
node: "nodejs",
|
|
239
|
+
op_mob: "opera_android",
|
|
240
|
+
opera: "opera",
|
|
241
|
+
safari: "safari",
|
|
242
|
+
samsung: "samsunginternet_android",
|
|
243
|
+
};
|
|
244
|
+
|
|
228
245
|
module.exports = {
|
|
229
246
|
ECMA_VERSION_MAP,
|
|
230
247
|
ECMA_VERSION_TO_NUMBER,
|
|
231
248
|
BROWSER_TO_ES_VERSION,
|
|
249
|
+
BROWSERSLIST_TO_BCD,
|
|
232
250
|
JS_VERSIONS,
|
|
233
251
|
VERSION_ORDER,
|
|
234
252
|
LATEST_PARSER_VERSION,
|
package/lib/detectFeatures.js
CHANGED
|
@@ -7,6 +7,7 @@ const {
|
|
|
7
7
|
const { ES_GLOBAL_MIN_VERSION } = require("./constants/es-features/globals");
|
|
8
8
|
const { POLYFILLABLE_FEATURES, CORE_JS_POLYFILLABLE } = require("./constants/polyfillableFeatures");
|
|
9
9
|
const { detectFeaturesFromAST } = require("./helpers/astDetector");
|
|
10
|
+
const { getUnsupportedBrowsers, formatFeatureWithBrowsers } = require("./helpers/browserSupport");
|
|
10
11
|
|
|
11
12
|
function getPolyfillableFeatures(library) {
|
|
12
13
|
if (!library) {
|
|
@@ -50,7 +51,7 @@ const detectPolyfills = (
|
|
|
50
51
|
};
|
|
51
52
|
|
|
52
53
|
const detectFeatures = (code, ecmaVersion, sourceType, ignoreList = new Set(), options = {}) => {
|
|
53
|
-
const { checkForPolyfills, ast, ignorePolyfillable } = options;
|
|
54
|
+
const { checkForPolyfills, ast, ignorePolyfillable, targetBrowsers } = options;
|
|
54
55
|
|
|
55
56
|
if (!ast) {
|
|
56
57
|
const error = new Error("AST is required for feature detection");
|
|
@@ -65,17 +66,26 @@ const detectFeatures = (code, ecmaVersion, sourceType, ignoreList = new Set(), o
|
|
|
65
66
|
|
|
66
67
|
const polyfillableSet = ignorePolyfillable ? getPolyfillableFeatures(ignorePolyfillable) : null;
|
|
67
68
|
|
|
69
|
+
const browserDetails = {};
|
|
70
|
+
|
|
68
71
|
function isUnsupportedFeature(name, minVersion) {
|
|
69
72
|
const wasFound = foundFeatures[name];
|
|
73
|
+
if (!wasFound) return false;
|
|
74
|
+
|
|
75
|
+
const unsupportedBrowsers = getUnsupportedBrowsers(name, targetBrowsers);
|
|
76
|
+
const lacksBrowserSupport = unsupportedBrowsers.length > 0;
|
|
70
77
|
const requiresHigherVersion = minVersion > ecmaVersion;
|
|
78
|
+
const shouldReport = requiresHigherVersion || lacksBrowserSupport;
|
|
79
|
+
if (!shouldReport) return false;
|
|
80
|
+
|
|
71
81
|
const isIgnored = ignoreList.has(name);
|
|
72
82
|
const isPolyfilled = checkForPolyfills && polyfills.has(name);
|
|
73
83
|
const isPolyfillableIgnored = polyfillableSet && polyfillableSet.has(name);
|
|
74
|
-
|
|
75
84
|
const isAllowed = isIgnored || isPolyfilled || isPolyfillableIgnored;
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
85
|
+
if (isAllowed) return false;
|
|
86
|
+
|
|
87
|
+
if (lacksBrowserSupport) browserDetails[name] = unsupportedBrowsers;
|
|
88
|
+
return true;
|
|
79
89
|
}
|
|
80
90
|
|
|
81
91
|
const unsupportedStandardFeatures = Object.entries(ES_FEATURES)
|
|
@@ -90,12 +100,17 @@ const detectFeatures = (code, ecmaVersion, sourceType, ignoreList = new Set(), o
|
|
|
90
100
|
const unsupportedFeatures = unsupportedStandardFeatures.concat(unsupportedGlobalFeatures);
|
|
91
101
|
|
|
92
102
|
if (unsupportedFeatures.length > 0) {
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
103
|
+
const hasBrowserDetails = Object.keys(browserDetails).length > 0;
|
|
104
|
+
const featureList = unsupportedFeatures
|
|
105
|
+
.map((name) => formatFeatureWithBrowsers(name, browserDetails[name]))
|
|
106
|
+
.join(", ");
|
|
107
|
+
const reason = hasBrowserDetails
|
|
108
|
+
? `These require a higher ES version than ${ecmaVersion} or are not supported by the target browsers.`
|
|
109
|
+
: `These require a higher ES version than ${ecmaVersion}.`;
|
|
110
|
+
const error = new Error(`Unsupported features detected: ${featureList}. ${reason}`);
|
|
97
111
|
error.type = "ES-Check";
|
|
98
112
|
error.features = unsupportedFeatures;
|
|
113
|
+
error.browserDetails = browserDetails;
|
|
99
114
|
error.ecmaVersion = ecmaVersion;
|
|
100
115
|
throw error;
|
|
101
116
|
}
|
|
@@ -103,6 +118,7 @@ const detectFeatures = (code, ecmaVersion, sourceType, ignoreList = new Set(), o
|
|
|
103
118
|
return {
|
|
104
119
|
foundFeatures,
|
|
105
120
|
unsupportedFeatures,
|
|
121
|
+
browserDetails,
|
|
106
122
|
};
|
|
107
123
|
};
|
|
108
124
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const { FEATURE_BROWSER_SUPPORT } = require("../constants/es-features/browserSupport");
|
|
2
|
+
|
|
3
|
+
function compareVersions(a, b) {
|
|
4
|
+
const aParts = String(a).split(".").map(Number);
|
|
5
|
+
const bParts = String(b).split(".").map(Number);
|
|
6
|
+
const length = Math.max(aParts.length, bParts.length);
|
|
7
|
+
|
|
8
|
+
let index = 0;
|
|
9
|
+
while (index < length) {
|
|
10
|
+
const diff = (aParts[index] || 0) - (bParts[index] || 0);
|
|
11
|
+
if (diff !== 0) return diff;
|
|
12
|
+
index += 1;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function isVersionSupported(targetVersion, versionAdded) {
|
|
19
|
+
const isSupportedWithoutVersion = versionAdded === true;
|
|
20
|
+
if (isSupportedWithoutVersion) return true;
|
|
21
|
+
|
|
22
|
+
const isNeverSupported = versionAdded === false;
|
|
23
|
+
if (isNeverSupported) return false;
|
|
24
|
+
|
|
25
|
+
return compareVersions(targetVersion, versionAdded) >= 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function keepLowestVersionPerBrowser(browsers) {
|
|
29
|
+
const lowestByName = new Map();
|
|
30
|
+
|
|
31
|
+
browsers.forEach((browser) => {
|
|
32
|
+
const current = lowestByName.get(browser.name);
|
|
33
|
+
const isLower = !current || compareVersions(browser.version, current.version) < 0;
|
|
34
|
+
if (isLower) lowestByName.set(browser.name, browser);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return Array.from(lowestByName.values());
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getUnsupportedBrowsers(
|
|
41
|
+
featureName,
|
|
42
|
+
targetBrowsers,
|
|
43
|
+
browserSupport = FEATURE_BROWSER_SUPPORT,
|
|
44
|
+
) {
|
|
45
|
+
const support = browserSupport[featureName];
|
|
46
|
+
const hasNoTargets = !targetBrowsers || targetBrowsers.length === 0;
|
|
47
|
+
const hasNoData = !support || hasNoTargets;
|
|
48
|
+
if (hasNoData) return [];
|
|
49
|
+
|
|
50
|
+
const unsupported = targetBrowsers.filter((browser) => {
|
|
51
|
+
const versionAdded = support[browser.name];
|
|
52
|
+
const hasBrowserData = versionAdded !== undefined;
|
|
53
|
+
if (!hasBrowserData) return false;
|
|
54
|
+
return !isVersionSupported(browser.version, versionAdded);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return keepLowestVersionPerBrowser(unsupported).map((browser) => ({
|
|
58
|
+
name: browser.name,
|
|
59
|
+
version: browser.version,
|
|
60
|
+
requiredVersion: support[browser.name],
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function formatBrowserRequirement({ name, version, requiredVersion }) {
|
|
65
|
+
const isNeverSupported = requiredVersion === false;
|
|
66
|
+
if (isNeverSupported) return `${name} ${version} has no support`;
|
|
67
|
+
return `${name} ${version} requires ${requiredVersion}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function formatFeatureWithBrowsers(featureName, unsupportedBrowsers) {
|
|
71
|
+
const hasNoBrowsers = !unsupportedBrowsers || unsupportedBrowsers.length === 0;
|
|
72
|
+
if (hasNoBrowsers) return featureName;
|
|
73
|
+
|
|
74
|
+
const requirements = unsupportedBrowsers.map(formatBrowserRequirement).join(", ");
|
|
75
|
+
return `${featureName} (${requirements})`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function formatTargetBrowsers(targetBrowsers) {
|
|
79
|
+
return targetBrowsers.map((browser) => `${browser.name} ${browser.version}`).join(", ");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = {
|
|
83
|
+
compareVersions,
|
|
84
|
+
isVersionSupported,
|
|
85
|
+
getUnsupportedBrowsers,
|
|
86
|
+
formatBrowserRequirement,
|
|
87
|
+
formatFeatureWithBrowsers,
|
|
88
|
+
formatTargetBrowsers,
|
|
89
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "es-check",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.8.1",
|
|
4
4
|
"description": "Checks the ECMAScript version of .js glob against a specified version of ECMAScript with a shell command",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"check for es6",
|
|
@@ -75,9 +75,10 @@
|
|
|
75
75
|
"release:tag:dry": "node scripts/release-tag.mjs --dry-run",
|
|
76
76
|
"release:dry": "release-it --dry-run --no-git.requireUpstream",
|
|
77
77
|
"report:coverage": "mkdir -p coverage && node tests/scripts/test-runner.js unit --coverage --reporter=lcov --reporter-destination=coverage/lcov.info",
|
|
78
|
-
"scripts:generate": "pnpm run scripts:generate:requirements && pnpm run scripts:generate:polyfills",
|
|
78
|
+
"scripts:generate": "pnpm run scripts:generate:requirements && pnpm run scripts:generate:polyfills && pnpm run scripts:generate:browser-support",
|
|
79
79
|
"scripts:generate:requirements": "node scripts/generate/requirements/parser.mjs",
|
|
80
80
|
"scripts:generate:polyfills": "node scripts/generate/polyfills/core.mjs",
|
|
81
|
+
"scripts:generate:browser-support": "node scripts/generate/browser-support/index.mjs",
|
|
81
82
|
"test": "node tests/scripts/test-runner.js unit && npm run test:e2e",
|
|
82
83
|
"test:unit": "node tests/scripts/test-runner.js unit",
|
|
83
84
|
"test:unit:verbose": "node tests/scripts/test-runner.js unit --verbose",
|
|
@@ -96,17 +97,17 @@
|
|
|
96
97
|
},
|
|
97
98
|
"dependencies": {
|
|
98
99
|
"acorn": "8.18.0",
|
|
99
|
-
"browserslist": "4.
|
|
100
|
+
"browserslist": "4.29.0",
|
|
100
101
|
"fast-glob": "^3.3.3"
|
|
101
102
|
},
|
|
102
103
|
"devDependencies": {
|
|
103
|
-
"@mdn/browser-compat-data": "^8.1.
|
|
104
|
+
"@mdn/browser-compat-data": "^8.1.2",
|
|
104
105
|
"codependence": "1.0.15",
|
|
105
106
|
"core-js-compat": "^3.50.0",
|
|
106
|
-
"oxfmt": "^0.
|
|
107
|
-
"oxlint": "^1.
|
|
108
|
-
"pastoralist": "1.13.
|
|
109
|
-
"release-it": "21.0
|
|
107
|
+
"oxfmt": "^0.68.0",
|
|
108
|
+
"oxlint": "^1.83.0",
|
|
109
|
+
"pastoralist": "1.13.4",
|
|
110
|
+
"release-it": "21.1.0"
|
|
110
111
|
},
|
|
111
112
|
"peerDependencies": {},
|
|
112
113
|
"optionalDependencies": {},
|
|
@@ -134,20 +135,6 @@
|
|
|
134
135
|
"site/package.json"
|
|
135
136
|
]
|
|
136
137
|
},
|
|
137
|
-
"pastoralist": {
|
|
138
|
-
"depPaths": [
|
|
139
|
-
"package.json",
|
|
140
|
-
"site/package.json"
|
|
141
|
-
],
|
|
142
|
-
"security": {
|
|
143
|
-
"enabled": true,
|
|
144
|
-
"provider": "github",
|
|
145
|
-
"autoFix": true,
|
|
146
|
-
"interactive": false,
|
|
147
|
-
"severityThreshold": "low",
|
|
148
|
-
"hasWorkspaceSecurityChecks": true
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
138
|
"release-it": {
|
|
152
139
|
"git": {
|
|
153
140
|
"commitMessage": "chore(release): ${version}",
|
|
@@ -172,5 +159,19 @@
|
|
|
172
159
|
"after:release": "echo Successfully released ${name} v${version} to ${repo.repository}."
|
|
173
160
|
}
|
|
174
161
|
},
|
|
175
|
-
"website": "https://jeffry.in/es-check"
|
|
162
|
+
"website": "https://jeffry.in/es-check",
|
|
163
|
+
"pastoralist": {
|
|
164
|
+
"depPaths": [
|
|
165
|
+
"package.json",
|
|
166
|
+
"site/package.json"
|
|
167
|
+
],
|
|
168
|
+
"security": {
|
|
169
|
+
"enabled": true,
|
|
170
|
+
"provider": "github",
|
|
171
|
+
"autoFix": true,
|
|
172
|
+
"interactive": false,
|
|
173
|
+
"severityThreshold": "low",
|
|
174
|
+
"hasWorkspaceSecurityChecks": true
|
|
175
|
+
}
|
|
176
|
+
}
|
|
176
177
|
}
|