es-check
Version:
Checks the ECMAScript version of .js glob against a specified version of ECMAScript with a shell command
115 lines (98 loc) • 3.02 kB
JavaScript
const {
ES_FEATURES,
POLYFILL_PATTERNS,
IMPORT_PATTERNS,
FEATURE_TO_POLYFILL_MAP,
} = require("./constants");
const { detectFeaturesFromAST } = require("./helpers/astDetector");
const detectPolyfills = (
code,
polyfills,
{
polyfillPatterns = POLYFILL_PATTERNS,
importPatterns = IMPORT_PATTERNS,
} = {},
) => {
if (code.includes("core-js") || code.includes("polyfill")) {
for (const { pattern, feature } of polyfillPatterns) {
if (pattern.test(code)) polyfills.add(feature);
}
if (code.includes("import") && code.includes("core-js")) {
for (const { pattern, feature } of importPatterns) {
if (pattern.test(code)) polyfills.add(feature);
}
}
}
};
const detectFeatures = (
code,
ecmaVersion,
sourceType,
ignoreList = new Set(),
options = {},
) => {
const { checkForPolyfills, ast } = options;
if (!ast) {
const error = new Error("AST is required for feature detection");
error.type = "ES-Check";
throw error;
}
const polyfills = new Set();
if (checkForPolyfills) detectPolyfills(code, polyfills);
const foundFeatures = detectFeaturesFromAST(ast);
const unsupportedFeatures = Object.entries(ES_FEATURES)
.filter(
([name, { minVersion }]) =>
foundFeatures[name] &&
minVersion > ecmaVersion &&
!ignoreList.has(name) &&
!(checkForPolyfills && polyfills.has(name)),
)
.map(([name]) => name);
if (unsupportedFeatures.length > 0) {
const error = new Error(
`Unsupported features detected: ${unsupportedFeatures.join(", ")}. ` +
`These require a higher ES version than ${ecmaVersion}.`,
);
error.type = "ES-Check";
error.features = unsupportedFeatures;
error.ecmaVersion = ecmaVersion;
throw error;
}
return {
foundFeatures,
unsupportedFeatures,
};
};
function detectPolyfillsForFeatures(
code,
logger,
featureMap = FEATURE_TO_POLYFILL_MAP,
) {
const polyfills = new Set();
if (!code || !featureMap) return polyfills;
if (logger?.isLevelEnabled?.("debug")) {
}
const polyfillFeatures = Object.entries(featureMap);
polyfillFeatures.forEach(([feature, patterns]) => {
const isPolyfilled = patterns.some((pattern) => pattern.test(code));
if (isPolyfilled) polyfills.add(feature);
});
if (logger?.isLevelEnabled?.("debug")) {
const hasPolyfills = polyfills.size > 0;
if (hasPolyfills)
logger.debug(
`ES-Check: Detected polyfills: ${Array.from(polyfills).join(", ")}`,
);
else logger.debug("ES-Check: No polyfills detected.");
}
return polyfills;
}
const filterPolyfilled = (unsupportedFeatures, polyfills) => {
const hasPolyfills = polyfills && polyfills.size > 0;
if (!hasPolyfills) return unsupportedFeatures;
return unsupportedFeatures.filter((feature) => !polyfills.has(feature));
};
module.exports = detectFeatures;
module.exports.detectPolyfills = detectPolyfillsForFeatures;
module.exports.filterPolyfilled = filterPolyfilled;