-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
206 lines (162 loc) · 6.24 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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
const fs = require('fs');
const { resolve, extname } = require('path');
const acorn = require('acorn');
const findGlobals = require('acorn-globals');
// In newer Node.js versions where process is already global this isn't necessary.
const process = require('process');
// utils
const findGlobalsExposed = require('./utils/find-globals-exposed');
// global objects
const constants = require('./static/constants.json');
// transformers
const transformLeakingGlobalsVars = require('./transforms/with-globals/leaking-global-vars');
const transformUnusedAssignedVars = require('./transforms/with-globals/unused-assigned-vars');
const transformNoUnderscoreDangle = require('./transforms/with-globals/no-underscore-dangle');
/* will be ignored in dependencies -- start */
const allExternalDeps = Object.keys(constants).reduce((accumulator, key) => accumulator.concat(constants[key]), []);
let ignoreableExternalDeps = [];
let ignoreFilesRegex;
let ignoreFoldersRegex;
/* will be ignored in dependencies -- end */
let allGlobalDeps = [];
let allGlobalsExposed = [];
let fixOnlyDependencies = false;
function recursiveDirFilesIterator(dirPath, cb) {
const files = fs.readdirSync(resolve(__dirname, dirPath), { withFileTypes: true });
files.forEach((file) => {
const filePath = resolve(dirPath, file.name);
if (file.isFile()) {
if (ignoreFilesRegex.test(file.name) || !['.js', '.jsx'].includes(extname(file.name))) {
console.log("Skipping file: '%s'", filePath);
} else {
cb(filePath);
}
} else if (file.isDirectory()) {
if (!ignoreFoldersRegex.test(filePath)) {
recursiveDirFilesIterator(filePath, cb);
} else {
console.log("Skipping directory: '%s'", filePath);
}
}
});
}
function fillAllGlobalsConstants(filePath) {
const source = fs.readFileSync(resolve(__dirname, filePath), { encoding: 'utf8' });
const ast = acorn.parse(source, {
loc: true
});
const globalsExposed = Object.keys(findGlobalsExposed(ast));
const dependencies = findGlobals(ast)
.filter((dep) => allExternalDeps.indexOf(dep.name) === -1)
.filter((dep) => ignoreableExternalDeps.indexOf(dep.name) === -1);
const depNames = dependencies.map(({ name }) => name);
// set allGlobalsExposed && allGlobalDeps in first iteration
allGlobalsExposed = allGlobalsExposed.concat(globalsExposed);
allGlobalDeps = allGlobalDeps.concat(depNames);
}
function executeTransformer(filePath) {
let results;
const source = fs.readFileSync(resolve(__dirname, filePath), { encoding: 'utf8' });
const passCollectedGlobals = ['transformNoUnderscoreDangle'].includes(this.name);
if (passCollectedGlobals) {
const ast = acorn.parse(source, {
loc: true
});
const globalsExposed = Object.keys(findGlobalsExposed(ast));
let dependencies = findGlobals(ast)
.filter((dep) => allExternalDeps.indexOf(dep.name) === -1)
.filter((dep) => ignoreableExternalDeps.indexOf(dep.name) === -1);
if (fixOnlyDependencies) {
dependencies = [...new Set(dependencies.filter((e) => allGlobalsExposed.indexOf(e.name) === -1))];
results = this(filePath, dependencies);
} else {
dependencies = [...new Set(dependencies)];
results = this(filePath, false, {
globalsExposed,
dependencies
});
}
} else {
results = this(filePath);
}
if (results) {
fs.writeFileSync(resolve(__dirname, filePath), results.replace(/;;/g, ';'));
}
}
function collectAllGlobals(dirPath) {
return new Promise((res, rej) => {
try {
recursiveDirFilesIterator(dirPath, fillAllGlobalsConstants);
allGlobalDeps = [...new Set(allGlobalDeps)];
allGlobalsExposed = [...new Set(allGlobalsExposed)];
res({
allGlobalDeps: [...new Set(allGlobalDeps)],
allGlobalsExposed: [...new Set(allGlobalsExposed)]
});
} catch (err) {
rej(err);
}
});
}
/**
* { fixJSsAtPath: Transforms all the JS files at the dirPath }
*
* @param {<String>} dirPath The directory where you want to run the transform at
* @param {<Function>} transformer The transformer which will modify the JS files
* @param {<Regex>} [paramsIgnoreFilesRegex=/$^/] Regular expression to match filenames
* to ignore during transform
* @param {<Regex>} [paramsIgnoreFoldersRegex=/$^/] Regular expression to match folder names
* to ignore during transform
* @param {<Array>} [paramsIgnoreableExternalDeps=[]] Array of dependencies to ignore during transform
*/
function fixJSsAtPath(
dirPath,
transformer,
paramsIgnoreFilesRegex = /$^/,
paramsIgnoreFoldersRegex = /$^/,
paramsIgnoreableExternalDeps = []
) {
try {
if (dirPath.constructor !== String) {
throw new Error('dirPath should be a String');
}
if (transformer.constructor !== Function) {
throw new Error('transformer should be a Function');
}
if (paramsIgnoreFilesRegex.constructor !== RegExp) {
throw new Error('paramsIgnoreFilesRegex should be a RegExp');
}
if (paramsIgnoreFoldersRegex.constructor !== RegExp) {
throw new Error('paramsIgnoreFoldersRegex should be a RegExp');
}
if (paramsIgnoreableExternalDeps.constructor !== Array) {
throw new Error('paramsIgnoreableExternalDeps should be an Array');
}
ignoreFilesRegex = paramsIgnoreFilesRegex;
ignoreFoldersRegex = paramsIgnoreFoldersRegex;
ignoreableExternalDeps = ignoreableExternalDeps.concat(paramsIgnoreableExternalDeps);
console.log("Executing Transformer: '%s'", transformer.name);
fixOnlyDependencies = ['transformLeakingGlobalsVars', 'transformUnusedAssignedVars'].includes(transformer.name);
if (fixOnlyDependencies) {
collectAllGlobals(dirPath)
.then(() => {
recursiveDirFilesIterator(dirPath, executeTransformer.bind(transformer));
})
.catch((err) => {
// An error occurred
console.error('Some Error Occured: ', err);
process.exit(1);
});
} else {
recursiveDirFilesIterator(dirPath, executeTransformer.bind(transformer));
}
} catch (err) {
console.log(err);
}
}
module.exports = {
fixJSsAtPath,
transformLeakingGlobalsVars,
transformUnusedAssignedVars,
transformNoUnderscoreDangle
};