2025-04-02 06:50:39 -04:00

464 lines
11 KiB
JavaScript

'use strict';
var __createBinding =
(this && this.__createBinding) ||
(Object.create ?
function (o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (
!desc ||
('get' in desc ? !m.__esModule : desc.writable || desc.configurable)
) {
desc = {
enumerable: true,
get: function () {
return m[k];
},
};
}
Object.defineProperty(o, k2, desc);
}
: function (o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
});
var __setModuleDefault =
(this && this.__setModuleDefault) ||
(Object.create ?
function (o, v) {
Object.defineProperty(o, 'default', { enumerable: true, value: v });
}
: function (o, v) {
o['default'] = v;
});
var __importStar =
(this && this.__importStar) ||
function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null)
for (var k in mod)
if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k))
__createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault =
(this && this.__importDefault) ||
function (mod) {
return mod && mod.__esModule ? mod : { default: mod };
};
Object.defineProperty(exports, '__esModule', { value: true });
exports.detect =
exports.parse =
exports.visitorUseSCWD =
exports.visitorMalformed =
exports.visitorNonLiteral =
exports.visitorSuccessful =
void 0;
const babelTypes = __importStar(require('@babel/types'));
const babel = __importStar(require('@babel/parser'));
const generator_1 = __importDefault(require('@babel/generator'));
const log_1 = require('./log');
const common_1 = require('./common');
function isLiteral(node) {
if (node == null) {
return false;
}
if (!node.type.endsWith('Literal')) {
return false;
}
if (node.type === 'TemplateLiteral' && node.expressions.length !== 0) {
return false;
}
return true;
}
function getLiteralValue(node) {
if (node.type === 'TemplateLiteral') {
return node.quasis[0].value.raw;
}
if (node.type === 'NullLiteral') {
throw new Error('Unexpected null in require expression');
}
if (node.type === 'RegExpLiteral') {
throw new Error('Unexpected regexp in require expression');
}
return node.value;
}
function reconstructSpecifiers(specs) {
if (!specs || !specs.length) {
return '';
}
const defaults = [];
for (const spec of specs) {
if (babelTypes.isImportDefaultSpecifier(spec)) {
defaults.push(spec.local.name);
}
}
const nonDefaults = [];
for (const spec of specs) {
if (babelTypes.isImportSpecifier(spec)) {
const importedName =
babelTypes.isIdentifier(spec.imported) ?
spec.imported.name
: spec.imported.value;
if (spec.local.name === importedName) {
nonDefaults.push(spec.local.name);
} else {
nonDefaults.push(`${importedName} as ${spec.local.name}`);
}
}
}
if (nonDefaults.length) {
defaults.push(`{ ${nonDefaults.join(', ')} }`);
}
return defaults.join(', ');
}
function reconstruct(node) {
let v = (0, generator_1.default)(node, { comments: false }).code.replace(
/\n/g,
''
);
let v2;
while (true) {
v2 = v.replace(/\[ /g, '[').replace(/ \]/g, ']').replace(/ {2}/g, ' ');
if (v2 === v) {
break;
}
v = v2;
}
return v2;
}
function forge(pattern, was) {
return pattern
.replace('{c1}', ', ')
.replace('{v1}', `"${was.v1}"`)
.replace('{c2}', was.v2 ? ', ' : '')
.replace('{v2}', was.v2 ? `"${was.v2}"` : '')
.replace('{c3}', was.v3 ? ' from ' : '')
.replace('{v3}', was.v3 ? was.v3 : '');
}
function valid2(v2) {
return (
v2 === undefined ||
v2 === null ||
v2 === 'must-exclude' ||
v2 === 'may-exclude'
);
}
function visitorRequireResolve(n) {
if (!babelTypes.isCallExpression(n)) {
return null;
}
if (!babelTypes.isMemberExpression(n.callee)) {
return null;
}
const ci =
n.callee.object.type === 'Identifier' &&
n.callee.object.name === 'require' &&
n.callee.property.type === 'Identifier' &&
n.callee.property.name === 'resolve';
if (!ci) {
return null;
}
if (!n.arguments || !isLiteral(n.arguments[0])) {
return null;
}
return {
v1: getLiteralValue(n.arguments[0]),
v2: isLiteral(n.arguments[1]) ? getLiteralValue(n.arguments[1]) : null,
};
}
function visitorRequire(n) {
if (!babelTypes.isCallExpression(n)) {
return null;
}
if (!babelTypes.isIdentifier(n.callee)) {
return null;
}
if (n.callee.name !== 'require') {
return null;
}
if (!n.arguments || !isLiteral(n.arguments[0])) {
return null;
}
return {
v1: getLiteralValue(n.arguments[0]),
v2: isLiteral(n.arguments[1]) ? getLiteralValue(n.arguments[1]) : null,
};
}
function visitorImport(n) {
if (!babelTypes.isImportDeclaration(n)) {
return null;
}
return { v1: n.source.value, v3: reconstructSpecifiers(n.specifiers) };
}
function visitorPathJoin(n) {
if (!babelTypes.isCallExpression(n)) {
return null;
}
if (!babelTypes.isMemberExpression(n.callee)) {
return null;
}
const ci =
n.callee.object &&
n.callee.object.type === 'Identifier' &&
n.callee.object.name === 'path' &&
n.callee.property &&
n.callee.property.type === 'Identifier' &&
n.callee.property.name === 'join';
if (!ci) {
return null;
}
const dn =
n.arguments[0] &&
n.arguments[0].type === 'Identifier' &&
n.arguments[0].name === '__dirname';
if (!dn) {
return null;
}
const f =
n.arguments && isLiteral(n.arguments[1]) && n.arguments.length === 2; // TODO concat them
if (!f) {
return null;
}
return { v1: getLiteralValue(n.arguments[1]) };
}
function visitorSuccessful(node, test = false) {
let was = visitorRequireResolve(node);
if (was) {
if (test) {
return forge('require.resolve({v1}{c2}{v2})', was);
}
if (!valid2(was.v2)) {
return null;
}
return {
alias: was.v1,
aliasType: common_1.ALIAS_AS_RESOLVABLE,
mustExclude: was.v2 === 'must-exclude',
mayExclude: was.v2 === 'may-exclude',
};
}
was = visitorRequire(node);
if (was) {
if (test) {
return forge('require({v1}{c2}{v2})', was);
}
if (!valid2(was.v2)) {
return null;
}
return {
alias: was.v1,
aliasType: common_1.ALIAS_AS_RESOLVABLE,
mustExclude: was.v2 === 'must-exclude',
mayExclude: was.v2 === 'may-exclude',
};
}
was = visitorImport(node);
if (was) {
if (test) {
return forge('import {v3}{c3}{v1}', was);
}
return { alias: was.v1, aliasType: common_1.ALIAS_AS_RESOLVABLE };
}
was = visitorPathJoin(node);
if (was) {
if (test) {
return forge('path.join(__dirname{c1}{v1})', was);
}
return {
alias: was.v1,
aliasType: common_1.ALIAS_AS_RELATIVE,
mayExclude: false,
};
}
return null;
}
exports.visitorSuccessful = visitorSuccessful;
function nonLiteralRequireResolve(n) {
if (!babelTypes.isCallExpression(n)) {
return null;
}
if (!babelTypes.isMemberExpression(n.callee)) {
return null;
}
const ci =
n.callee.object.type === 'Identifier' &&
n.callee.object.name === 'require' &&
n.callee.property.type === 'Identifier' &&
n.callee.property.name === 'resolve';
if (!ci) {
return null;
}
if (isLiteral(n.arguments[0])) {
return null;
}
const m = n.arguments[1];
if (!m) {
return { v1: reconstruct(n.arguments[0]) };
}
if (!isLiteral(n.arguments[1])) {
return null;
}
return {
v1: reconstruct(n.arguments[0]),
v2: getLiteralValue(n.arguments[1]),
};
}
function nonLiteralRequire(n) {
if (!babelTypes.isCallExpression(n)) {
return null;
}
if (!babelTypes.isIdentifier(n.callee)) {
return null;
}
if (n.callee.name !== 'require') {
return null;
}
if (isLiteral(n.arguments[0])) {
return null;
}
const m = n.arguments[1];
if (!m) {
return { v1: reconstruct(n.arguments[0]) };
}
if (!isLiteral(n.arguments[1])) {
return null;
}
return {
v1: reconstruct(n.arguments[0]),
v2: getLiteralValue(n.arguments[1]),
};
}
function visitorNonLiteral(n) {
const was = nonLiteralRequireResolve(n) || nonLiteralRequire(n);
if (was) {
if (!valid2(was.v2)) {
return null;
}
return {
alias: was.v1,
mustExclude: was.v2 === 'must-exclude',
mayExclude: was.v2 === 'may-exclude',
};
}
return null;
}
exports.visitorNonLiteral = visitorNonLiteral;
function isRequire(n) {
if (!babelTypes.isCallExpression(n)) {
return null;
}
if (!babelTypes.isIdentifier(n.callee)) {
return null;
}
if (n.callee.name !== 'require') {
return null;
}
const f = n.arguments && n.arguments[0];
if (!f) {
return null;
}
return { v1: reconstruct(n.arguments[0]) };
}
function isRequireResolve(n) {
if (!babelTypes.isCallExpression(n)) {
return null;
}
if (!babelTypes.isMemberExpression(n.callee)) {
return null;
}
const ci =
n.callee.object.type === 'Identifier' &&
n.callee.object.name === 'require' &&
n.callee.property.type === 'Identifier' &&
n.callee.property.name === 'resolve';
if (!ci) {
return null;
}
const f = n.type === 'CallExpression' && n.arguments && n.arguments[0];
if (!f) {
return null;
}
return { v1: reconstruct(n.arguments[0]) };
}
function visitorMalformed(n) {
const was = isRequireResolve(n) || isRequire(n);
if (was) {
return { alias: was.v1 };
}
return null;
}
exports.visitorMalformed = visitorMalformed;
function visitorUseSCWD(n) {
if (!babelTypes.isCallExpression(n)) {
return null;
}
if (!babelTypes.isMemberExpression(n.callee)) {
return null;
}
const ci =
n.callee.object.type === 'Identifier' &&
n.callee.object.name === 'path' &&
n.callee.property.type === 'Identifier' &&
n.callee.property.name === 'resolve';
if (!ci) {
return null;
}
const was = { v1: n.arguments.map(reconstruct).join(', ') };
if (was) {
return { alias: was.v1 };
}
return null;
}
exports.visitorUseSCWD = visitorUseSCWD;
function traverse(ast, visitor) {
// modified esprima-walk to support
// visitor return value and "trying" flag
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const stack = [[ast, false]];
for (let i = 0; i < stack.length; i += 1) {
const item = stack[i];
const [node] = item;
if (node) {
const trying = item[1] || babelTypes.isTryStatement(node);
if (visitor(node, trying)) {
for (const key in node) {
if (node[key]) {
const child = node[key];
if (child instanceof Array) {
for (let j = 0; j < child.length; j += 1) {
stack.push([child[j], trying]);
}
} else if (child && typeof child.type === 'string') {
stack.push([child, trying]);
}
}
}
}
}
}
}
function parse(body) {
return babel.parse(body, {
allowImportExportEverywhere: true,
allowReturnOutsideFunction: true,
});
}
exports.parse = parse;
function detect(body, visitor) {
let json;
try {
json = parse(body);
} catch (error) {
log_1.log.warn(`Babel parse has failed: ${error.message}`);
}
if (!json) {
return;
}
traverse(json, visitor);
}
exports.detect = detect;
//# sourceMappingURL=detector.js.map