-
Notifications
You must be signed in to change notification settings - Fork 7
/
index.js
executable file
·109 lines (92 loc) · 4.06 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
#!/usr/bin/env node
const fs = require('fs');
const { SourceMapConsumer } = require('source-map');
const path = require('path');
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');
const argv = yargs(hideBin(process.argv))
.usage('Usage: $0 [options]')
.option('input', {
description: 'The input path to the minified JavaScript file or a directory containing multiple files',
alias: 'i',
type: 'string',
demandOption: true
})
.help()
.alias('help', 'h')
.argv;
const handleFile = async (minifiedFilePath) => {
// Check if the Source Map exists
const sourceMapPath = minifiedFilePath + '.map';
if (!fs.existsSync(sourceMapPath)) {
console.error(`No source map found at ${sourceMapPath}`);
return;
}
// Read the minified file and the Source Map
const minifiedCode = fs.readFileSync(minifiedFilePath, 'utf8');
const rawSourceMap = fs.readFileSync(sourceMapPath);
const rawSourceMapJson = JSON.parse(rawSourceMap);
await SourceMapConsumer.with(rawSourceMapJson, null, (sourceMapConsumer) => {
const sources = sourceMapConsumer.sources;
const sourceContents = sources.reduce((contents, source) => {
contents[source] = sourceMapConsumer.sourceContentFor(source, true);
return contents;
}, {});
if (Object.values(sourceContents).some(content => content !== null)) {
// If sourcesContent exists, write it to the file
for (const source in sourceContents) {
if (sourceContents[source] !== null) {
const originalFilePath = path.join(path.dirname(minifiedFilePath), path.basename(source, '.js') + '');
fs.mkdirSync(path.dirname(originalFilePath), { recursive: true });
fs.writeFileSync(originalFilePath, sourceContents[source]);
console.log(`Source code recovered to ${originalFilePath}`);
}
}
} else {
// If sourcesContent doesn't exist, reconstruct the source code
const lines = minifiedCode.split('\n');
let reconstructedSource = '';
lines.forEach((line, lineIndex) => {
const lineNum = lineIndex + 1;
const columnCount = line.length;
for (let column = 0; column < columnCount; column++) {
const pos = { line: lineNum, column: column };
const originalPosition = sourceMapConsumer.originalPositionFor(pos);
if (originalPosition.source === null) continue;
if (originalPosition.name) {
reconstructedSource += originalPosition.name;
} else {
reconstructedSource += minifiedCode.charAt(column);
}
}
reconstructedSource += '\n';
});
// prettify the code
try {
reconstructedSource = prettier.format(reconstructedSource, { semi: false, parser: "babel" });
} catch (error) {
console.error("An error occurred while prettifying the code:", error);
}
const originalFilePath = path.join(path.dirname(minifiedFilePath), path.basename(minifiedFilePath, '.js') + '-recovered.js');
fs.mkdirSync(path.dirname(originalFilePath), { recursive: true });
fs.writeFileSync(originalFilePath, reconstructedSource);
console.log(`Source code recovered to ${originalFilePath}`);
}
});
};
const handlePath = (inputPath) => {
const files = fs.readdirSync(inputPath);
for (const file of files) {
const absolutePath = path.join(inputPath, file);
if (fs.statSync(absolutePath).isDirectory()) {
handlePath(absolutePath);
} else if (path.extname(absolutePath) === '.js') {
handleFile(absolutePath);
}
}
};
if (fs.statSync(argv.input).isDirectory()) {
handlePath(argv.input);
} else {
handleFile(argv.input);
}