-
Notifications
You must be signed in to change notification settings - Fork 38
/
index.js
135 lines (120 loc) · 4.47 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
"use strict";
// Require Third-party Dependencies
const { walk } = require("estree-walker");
const meriyah = require("meriyah");
const safeRegex = require("safe-regex");
// Require Internal Dependencies
const helpers = require("./helpers");
const ASTDeps = require("./ASTDeps");
// CONSTANTS
const kMainModuleStr = "process.mainModule.";
function warn(kind = "unsafe-import", { start, end }) {
return { kind, start, end };
}
/**
* @typedef {object} ASTSummary
* @property {ASTDeps} dependencies
* @property {any[]} warnings
* @property {boolean} isOneLineRequire
*/
/**
* @function searchRuntimeDependencies
* @description Parse a script, get an AST and search for require occurence!
* @param {!string} str file content (encoded as utf-8)
* @param {object} [options]
* @param {boolean} [options.module=false] enable sourceType module
* @returns {ASTSummary}
*/
function searchRuntimeDependencies(str, options = Object.create(null)) {
const { module = false } = options;
const identifiers = new Map();
const dependencies = new ASTDeps();
const warnings = [];
if (str.charAt(0) === "#") {
// eslint-disable-next-line
str = str.slice(str.indexOf("\n"));
}
const { body } = meriyah.parseScript(str, {
next: true,
module: Boolean(module),
loc: true
});
walk(body, {
enter(node) {
if (node.type === "TryStatement") {
dependencies.isInTryStmt = true;
}
else if (node.type === "CatchClause") {
dependencies.isInTryStmt = false;
}
if (helpers.isLiteralRegex(node)) {
if (!safeRegex(node.regex.pattern)) {
warnings.push(warn("unsafe-regex", node.loc));
}
}
else if (helpers.isRegexConstructor(node)) {
const arg = node.arguments[0];
const pattern = helpers.isLiteralRegex(arg) ? arg.regex.pattern : arg.value;
if (!safeRegex(pattern)) {
warnings.push(warn("unsafe-regex", node.loc));
}
}
if (helpers.isVariableDeclarator(node)) {
identifiers.set(node.id.name, node.init.value);
}
if (!module && (helpers.isRequireStatment(node) || helpers.isRequireResolve(node))) {
const arg = node.arguments[0];
if (arg.type === "Identifier") {
if (identifiers.has(arg.name)) {
dependencies.add(identifiers.get(arg.name));
}
else {
warnings.push(warn("unsafe-import", node.loc));
}
}
else if (arg.type === "Literal") {
dependencies.add(arg.value);
}
else if (arg.type === "ArrayExpression") {
const value = helpers.arrExprToString(arg.elements, identifiers);
if (value.trim() === "") {
warnings.push(warn("unsafe-import", node.loc));
}
else {
dependencies.add(value);
}
}
else if (arg.type === "BinaryExpression" && arg.operator === "+") {
const value = helpers.concatBinaryExpr(arg, identifiers);
if (value === null) {
warnings.push(warn("unsafe-import", node.loc));
}
else {
dependencies.add(value);
}
}
else {
warnings.push(warn("unsafe-import", node.loc));
}
}
else if (module && node.type === "ImportDeclaration") {
const source = node.source;
if (source.type === "Literal") {
dependencies.add(source.value);
}
}
else if (node.type === "MemberExpression") {
const memberName = helpers.getMemberExprName(node);
if (memberName.startsWith(kMainModuleStr)) {
dependencies.add(memberName.slice(kMainModuleStr.length));
}
}
}
});
return {
dependencies,
warnings,
isOneLineRequire: !module && body.length === 1 && dependencies.size === 1
};
}
module.exports = { searchRuntimeDependencies };