Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/build/lib/mangle/index.js
3520 views
1
"use strict";
2
var __importDefault = (this && this.__importDefault) || function (mod) {
3
return (mod && mod.__esModule) ? mod : { "default": mod };
4
};
5
Object.defineProperty(exports, "__esModule", { value: true });
6
exports.Mangler = void 0;
7
/*---------------------------------------------------------------------------------------------
8
* Copyright (c) Microsoft Corporation. All rights reserved.
9
* Licensed under the MIT License. See License.txt in the project root for license information.
10
*--------------------------------------------------------------------------------------------*/
11
const node_v8_1 = __importDefault(require("node:v8"));
12
const fs_1 = __importDefault(require("fs"));
13
const path_1 = __importDefault(require("path"));
14
const process_1 = require("process");
15
const source_map_1 = require("source-map");
16
const typescript_1 = __importDefault(require("typescript"));
17
const url_1 = require("url");
18
const workerpool_1 = __importDefault(require("workerpool"));
19
const staticLanguageServiceHost_1 = require("./staticLanguageServiceHost");
20
const buildfile = require('../../buildfile');
21
class ShortIdent {
22
prefix;
23
static _keywords = new Set(['await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger',
24
'default', 'delete', 'do', 'else', 'export', 'extends', 'false', 'finally', 'for', 'function', 'if',
25
'import', 'in', 'instanceof', 'let', 'new', 'null', 'return', 'static', 'super', 'switch', 'this', 'throw',
26
'true', 'try', 'typeof', 'var', 'void', 'while', 'with', 'yield']);
27
static _alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890$_'.split('');
28
_value = 0;
29
constructor(prefix) {
30
this.prefix = prefix;
31
}
32
next(isNameTaken) {
33
const candidate = this.prefix + ShortIdent.convert(this._value);
34
this._value++;
35
if (ShortIdent._keywords.has(candidate) || /^[_0-9]/.test(candidate) || isNameTaken?.(candidate)) {
36
// try again
37
return this.next(isNameTaken);
38
}
39
return candidate;
40
}
41
static convert(n) {
42
const base = this._alphabet.length;
43
let result = '';
44
do {
45
const rest = n % base;
46
result += this._alphabet[rest];
47
n = (n / base) | 0;
48
} while (n > 0);
49
return result;
50
}
51
}
52
var FieldType;
53
(function (FieldType) {
54
FieldType[FieldType["Public"] = 0] = "Public";
55
FieldType[FieldType["Protected"] = 1] = "Protected";
56
FieldType[FieldType["Private"] = 2] = "Private";
57
})(FieldType || (FieldType = {}));
58
class ClassData {
59
fileName;
60
node;
61
fields = new Map();
62
replacements;
63
parent;
64
children;
65
constructor(fileName, node) {
66
this.fileName = fileName;
67
this.node = node;
68
// analyse all fields (properties and methods). Find usages of all protected and
69
// private ones and keep track of all public ones (to prevent naming collisions)
70
const candidates = [];
71
for (const member of node.members) {
72
if (typescript_1.default.isMethodDeclaration(member)) {
73
// method `foo() {}`
74
candidates.push(member);
75
}
76
else if (typescript_1.default.isPropertyDeclaration(member)) {
77
// property `foo = 234`
78
candidates.push(member);
79
}
80
else if (typescript_1.default.isGetAccessor(member)) {
81
// getter: `get foo() { ... }`
82
candidates.push(member);
83
}
84
else if (typescript_1.default.isSetAccessor(member)) {
85
// setter: `set foo() { ... }`
86
candidates.push(member);
87
}
88
else if (typescript_1.default.isConstructorDeclaration(member)) {
89
// constructor-prop:`constructor(private foo) {}`
90
for (const param of member.parameters) {
91
if (hasModifier(param, typescript_1.default.SyntaxKind.PrivateKeyword)
92
|| hasModifier(param, typescript_1.default.SyntaxKind.ProtectedKeyword)
93
|| hasModifier(param, typescript_1.default.SyntaxKind.PublicKeyword)
94
|| hasModifier(param, typescript_1.default.SyntaxKind.ReadonlyKeyword)) {
95
candidates.push(param);
96
}
97
}
98
}
99
}
100
for (const member of candidates) {
101
const ident = ClassData._getMemberName(member);
102
if (!ident) {
103
continue;
104
}
105
const type = ClassData._getFieldType(member);
106
this.fields.set(ident, { type, pos: member.name.getStart() });
107
}
108
}
109
static _getMemberName(node) {
110
if (!node.name) {
111
return undefined;
112
}
113
const { name } = node;
114
let ident = name.getText();
115
if (name.kind === typescript_1.default.SyntaxKind.ComputedPropertyName) {
116
if (name.expression.kind !== typescript_1.default.SyntaxKind.StringLiteral) {
117
// unsupported: [Symbol.foo] or [abc + 'field']
118
return;
119
}
120
// ['foo']
121
ident = name.expression.getText().slice(1, -1);
122
}
123
return ident;
124
}
125
static _getFieldType(node) {
126
if (hasModifier(node, typescript_1.default.SyntaxKind.PrivateKeyword)) {
127
return 2 /* FieldType.Private */;
128
}
129
else if (hasModifier(node, typescript_1.default.SyntaxKind.ProtectedKeyword)) {
130
return 1 /* FieldType.Protected */;
131
}
132
else {
133
return 0 /* FieldType.Public */;
134
}
135
}
136
static _shouldMangle(type) {
137
return type === 2 /* FieldType.Private */
138
|| type === 1 /* FieldType.Protected */;
139
}
140
static makeImplicitPublicActuallyPublic(data, reportViolation) {
141
// TS-HACK
142
// A subtype can make an inherited protected field public. To prevent accidential
143
// mangling of public fields we mark the original (protected) fields as public...
144
for (const [name, info] of data.fields) {
145
if (info.type !== 0 /* FieldType.Public */) {
146
continue;
147
}
148
let parent = data.parent;
149
while (parent) {
150
if (parent.fields.get(name)?.type === 1 /* FieldType.Protected */) {
151
const parentPos = parent.node.getSourceFile().getLineAndCharacterOfPosition(parent.fields.get(name).pos);
152
const infoPos = data.node.getSourceFile().getLineAndCharacterOfPosition(info.pos);
153
reportViolation(name, `'${name}' from ${parent.fileName}:${parentPos.line + 1}`, `${data.fileName}:${infoPos.line + 1}`);
154
parent.fields.get(name).type = 0 /* FieldType.Public */;
155
}
156
parent = parent.parent;
157
}
158
}
159
}
160
static fillInReplacement(data) {
161
if (data.replacements) {
162
// already done
163
return;
164
}
165
// fill in parents first
166
if (data.parent) {
167
ClassData.fillInReplacement(data.parent);
168
}
169
data.replacements = new Map();
170
const isNameTaken = (name) => {
171
// locally taken
172
if (data._isNameTaken(name)) {
173
return true;
174
}
175
// parents
176
let parent = data.parent;
177
while (parent) {
178
if (parent._isNameTaken(name)) {
179
return true;
180
}
181
parent = parent.parent;
182
}
183
// children
184
if (data.children) {
185
const stack = [...data.children];
186
while (stack.length) {
187
const node = stack.pop();
188
if (node._isNameTaken(name)) {
189
return true;
190
}
191
if (node.children) {
192
stack.push(...node.children);
193
}
194
}
195
}
196
return false;
197
};
198
const identPool = new ShortIdent('');
199
for (const [name, info] of data.fields) {
200
if (ClassData._shouldMangle(info.type)) {
201
const shortName = identPool.next(isNameTaken);
202
data.replacements.set(name, shortName);
203
}
204
}
205
}
206
// a name is taken when a field that doesn't get mangled exists or
207
// when the name is already in use for replacement
208
_isNameTaken(name) {
209
if (this.fields.has(name) && !ClassData._shouldMangle(this.fields.get(name).type)) {
210
// public field
211
return true;
212
}
213
if (this.replacements) {
214
for (const shortName of this.replacements.values()) {
215
if (shortName === name) {
216
// replaced already (happens wih super types)
217
return true;
218
}
219
}
220
}
221
if (isNameTakenInFile(this.node, name)) {
222
return true;
223
}
224
return false;
225
}
226
lookupShortName(name) {
227
let value = this.replacements.get(name);
228
let parent = this.parent;
229
while (parent) {
230
if (parent.replacements.has(name) && parent.fields.get(name)?.type === 1 /* FieldType.Protected */) {
231
value = parent.replacements.get(name) ?? value;
232
}
233
parent = parent.parent;
234
}
235
return value;
236
}
237
// --- parent chaining
238
addChild(child) {
239
this.children ??= [];
240
this.children.push(child);
241
child.parent = this;
242
}
243
}
244
function isNameTakenInFile(node, name) {
245
const identifiers = node.getSourceFile().identifiers;
246
if (identifiers instanceof Map) {
247
if (identifiers.has(name)) {
248
return true;
249
}
250
}
251
return false;
252
}
253
const skippedExportMangledFiles = [
254
// Monaco
255
'editorCommon',
256
'editorOptions',
257
'editorZoom',
258
'standaloneEditor',
259
'standaloneEnums',
260
'standaloneLanguages',
261
// Generated
262
'extensionsApiProposals',
263
// Module passed around as type
264
'pfs',
265
// entry points
266
...[
267
buildfile.workerEditor,
268
buildfile.workerExtensionHost,
269
buildfile.workerNotebook,
270
buildfile.workerLanguageDetection,
271
buildfile.workerLocalFileSearch,
272
buildfile.workerProfileAnalysis,
273
buildfile.workerOutputLinks,
274
buildfile.workerBackgroundTokenization,
275
buildfile.workbenchDesktop,
276
buildfile.workbenchWeb,
277
buildfile.code,
278
buildfile.codeWeb
279
].flat().map(x => x.name),
280
];
281
const skippedExportMangledProjects = [
282
// Test projects
283
'vscode-api-tests',
284
// These projects use webpack to dynamically rewrite imports, which messes up our mangling
285
'configuration-editing',
286
'microsoft-authentication',
287
'github-authentication',
288
'html-language-features/server',
289
];
290
const skippedExportMangledSymbols = [
291
// Don't mangle extension entry points
292
'activate',
293
'deactivate',
294
];
295
class DeclarationData {
296
fileName;
297
node;
298
replacementName;
299
constructor(fileName, node, fileIdents) {
300
this.fileName = fileName;
301
this.node = node;
302
// Todo: generate replacement names based on usage count, with more used names getting shorter identifiers
303
this.replacementName = fileIdents.next();
304
}
305
getLocations(service) {
306
if (typescript_1.default.isVariableDeclaration(this.node)) {
307
// If the const aliases any types, we need to rename those too
308
const definitionResult = service.getDefinitionAndBoundSpan(this.fileName, this.node.name.getStart());
309
if (definitionResult?.definitions && definitionResult.definitions.length > 1) {
310
return definitionResult.definitions.map(x => ({ fileName: x.fileName, offset: x.textSpan.start }));
311
}
312
}
313
return [{
314
fileName: this.fileName,
315
offset: this.node.name.getStart()
316
}];
317
}
318
shouldMangle(newName) {
319
const currentName = this.node.name.getText();
320
if (currentName.startsWith('$') || skippedExportMangledSymbols.includes(currentName)) {
321
return false;
322
}
323
// New name is longer the existing one :'(
324
if (newName.length >= currentName.length) {
325
return false;
326
}
327
// Don't mangle functions we've explicitly opted out
328
if (this.node.getFullText().includes('@skipMangle')) {
329
return false;
330
}
331
return true;
332
}
333
}
334
/**
335
* TypeScript2TypeScript transformer that mangles all private and protected fields
336
*
337
* 1. Collect all class fields (properties, methods)
338
* 2. Collect all sub and super-type relations between classes
339
* 3. Compute replacement names for each field
340
* 4. Lookup rename locations for these fields
341
* 5. Prepare and apply edits
342
*/
343
class Mangler {
344
projectPath;
345
log;
346
config;
347
allClassDataByKey = new Map();
348
allExportedSymbols = new Set();
349
renameWorkerPool;
350
constructor(projectPath, log = () => { }, config) {
351
this.projectPath = projectPath;
352
this.log = log;
353
this.config = config;
354
this.renameWorkerPool = workerpool_1.default.pool(path_1.default.join(__dirname, 'renameWorker.js'), {
355
maxWorkers: 4,
356
minWorkers: 'max'
357
});
358
}
359
async computeNewFileContents(strictImplicitPublicHandling) {
360
const service = typescript_1.default.createLanguageService(new staticLanguageServiceHost_1.StaticLanguageServiceHost(this.projectPath));
361
// STEP:
362
// - Find all classes and their field info.
363
// - Find exported symbols.
364
const fileIdents = new ShortIdent('$');
365
const visit = (node) => {
366
if (this.config.manglePrivateFields) {
367
if (typescript_1.default.isClassDeclaration(node) || typescript_1.default.isClassExpression(node)) {
368
const anchor = node.name ?? node;
369
const key = `${node.getSourceFile().fileName}|${anchor.getStart()}`;
370
if (this.allClassDataByKey.has(key)) {
371
throw new Error('DUPE?');
372
}
373
this.allClassDataByKey.set(key, new ClassData(node.getSourceFile().fileName, node));
374
}
375
}
376
if (this.config.mangleExports) {
377
// Find exported classes, functions, and vars
378
if ((
379
// Exported class
380
typescript_1.default.isClassDeclaration(node)
381
&& hasModifier(node, typescript_1.default.SyntaxKind.ExportKeyword)
382
&& node.name) || (
383
// Exported function
384
typescript_1.default.isFunctionDeclaration(node)
385
&& typescript_1.default.isSourceFile(node.parent)
386
&& hasModifier(node, typescript_1.default.SyntaxKind.ExportKeyword)
387
&& node.name && node.body // On named function and not on the overload
388
) || (
389
// Exported variable
390
typescript_1.default.isVariableDeclaration(node)
391
&& hasModifier(node.parent.parent, typescript_1.default.SyntaxKind.ExportKeyword) // Variable statement is exported
392
&& typescript_1.default.isSourceFile(node.parent.parent.parent))
393
// Disabled for now because we need to figure out how to handle
394
// enums that are used in monaco or extHost interfaces.
395
/* || (
396
// Exported enum
397
ts.isEnumDeclaration(node)
398
&& ts.isSourceFile(node.parent)
399
&& hasModifier(node, ts.SyntaxKind.ExportKeyword)
400
&& !hasModifier(node, ts.SyntaxKind.ConstKeyword) // Don't bother mangling const enums because these are inlined
401
&& node.name
402
*/
403
) {
404
if (isInAmbientContext(node)) {
405
return;
406
}
407
this.allExportedSymbols.add(new DeclarationData(node.getSourceFile().fileName, node, fileIdents));
408
}
409
}
410
typescript_1.default.forEachChild(node, visit);
411
};
412
for (const file of service.getProgram().getSourceFiles()) {
413
if (!file.isDeclarationFile) {
414
typescript_1.default.forEachChild(file, visit);
415
}
416
}
417
this.log(`Done collecting. Classes: ${this.allClassDataByKey.size}. Exported symbols: ${this.allExportedSymbols.size}`);
418
// STEP: connect sub and super-types
419
const setupParents = (data) => {
420
const extendsClause = data.node.heritageClauses?.find(h => h.token === typescript_1.default.SyntaxKind.ExtendsKeyword);
421
if (!extendsClause) {
422
// no EXTENDS-clause
423
return;
424
}
425
const info = service.getDefinitionAtPosition(data.fileName, extendsClause.types[0].expression.getEnd());
426
if (!info || info.length === 0) {
427
// throw new Error('SUPER type not found');
428
return;
429
}
430
if (info.length !== 1) {
431
// inherits from declared/library type
432
return;
433
}
434
const [definition] = info;
435
const key = `${definition.fileName}|${definition.textSpan.start}`;
436
const parent = this.allClassDataByKey.get(key);
437
if (!parent) {
438
// throw new Error(`SUPER type not found: ${key}`);
439
return;
440
}
441
parent.addChild(data);
442
};
443
for (const data of this.allClassDataByKey.values()) {
444
setupParents(data);
445
}
446
// STEP: make implicit public (actually protected) field really public
447
const violations = new Map();
448
let violationsCauseFailure = false;
449
for (const data of this.allClassDataByKey.values()) {
450
ClassData.makeImplicitPublicActuallyPublic(data, (name, what, why) => {
451
const arr = violations.get(what);
452
if (arr) {
453
arr.push(why);
454
}
455
else {
456
violations.set(what, [why]);
457
}
458
if (strictImplicitPublicHandling && !strictImplicitPublicHandling.has(name)) {
459
violationsCauseFailure = true;
460
}
461
});
462
}
463
for (const [why, whys] of violations) {
464
this.log(`WARN: ${why} became PUBLIC because of: ${whys.join(' , ')}`);
465
}
466
if (violationsCauseFailure) {
467
const message = 'Protected fields have been made PUBLIC. This hurts minification and is therefore not allowed. Review the WARN messages further above';
468
this.log(`ERROR: ${message}`);
469
throw new Error(message);
470
}
471
// STEP: compute replacement names for each class
472
for (const data of this.allClassDataByKey.values()) {
473
ClassData.fillInReplacement(data);
474
}
475
this.log(`Done creating class replacements`);
476
// STEP: prepare rename edits
477
this.log(`Starting prepare rename edits`);
478
const editsByFile = new Map();
479
const appendEdit = (fileName, edit) => {
480
const edits = editsByFile.get(fileName);
481
if (!edits) {
482
editsByFile.set(fileName, [edit]);
483
}
484
else {
485
edits.push(edit);
486
}
487
};
488
const appendRename = (newText, loc) => {
489
appendEdit(loc.fileName, {
490
newText: (loc.prefixText || '') + newText + (loc.suffixText || ''),
491
offset: loc.textSpan.start,
492
length: loc.textSpan.length
493
});
494
};
495
const renameResults = [];
496
const queueRename = (fileName, pos, newName) => {
497
renameResults.push(Promise.resolve(this.renameWorkerPool.exec('findRenameLocations', [this.projectPath, fileName, pos]))
498
.then((locations) => ({ newName, locations })));
499
};
500
for (const data of this.allClassDataByKey.values()) {
501
if (hasModifier(data.node, typescript_1.default.SyntaxKind.DeclareKeyword)) {
502
continue;
503
}
504
fields: for (const [name, info] of data.fields) {
505
if (!ClassData._shouldMangle(info.type)) {
506
continue fields;
507
}
508
// TS-HACK: protected became public via 'some' child
509
// and because of that we might need to ignore this now
510
let parent = data.parent;
511
while (parent) {
512
if (parent.fields.get(name)?.type === 0 /* FieldType.Public */) {
513
continue fields;
514
}
515
parent = parent.parent;
516
}
517
const newName = data.lookupShortName(name);
518
queueRename(data.fileName, info.pos, newName);
519
}
520
}
521
for (const data of this.allExportedSymbols.values()) {
522
if (data.fileName.endsWith('.d.ts')
523
|| skippedExportMangledProjects.some(proj => data.fileName.includes(proj))
524
|| skippedExportMangledFiles.some(file => data.fileName.endsWith(file + '.ts'))) {
525
continue;
526
}
527
if (!data.shouldMangle(data.replacementName)) {
528
continue;
529
}
530
const newText = data.replacementName;
531
for (const { fileName, offset } of data.getLocations(service)) {
532
queueRename(fileName, offset, newText);
533
}
534
}
535
await Promise.all(renameResults).then((result) => {
536
for (const { newName, locations } of result) {
537
for (const loc of locations) {
538
appendRename(newName, loc);
539
}
540
}
541
});
542
await this.renameWorkerPool.terminate();
543
this.log(`Done preparing edits: ${editsByFile.size} files`);
544
// STEP: apply all rename edits (per file)
545
const result = new Map();
546
let savedBytes = 0;
547
for (const item of service.getProgram().getSourceFiles()) {
548
const { mapRoot, sourceRoot } = service.getProgram().getCompilerOptions();
549
const projectDir = path_1.default.dirname(this.projectPath);
550
const sourceMapRoot = mapRoot ?? (0, url_1.pathToFileURL)(sourceRoot ?? projectDir).toString();
551
// source maps
552
let generator;
553
let newFullText;
554
const edits = editsByFile.get(item.fileName);
555
if (!edits) {
556
// just copy
557
newFullText = item.getFullText();
558
}
559
else {
560
// source map generator
561
const relativeFileName = normalize(path_1.default.relative(projectDir, item.fileName));
562
const mappingsByLine = new Map();
563
// apply renames
564
edits.sort((a, b) => b.offset - a.offset);
565
const characters = item.getFullText().split('');
566
let lastEdit;
567
for (const edit of edits) {
568
if (lastEdit && lastEdit.offset === edit.offset) {
569
//
570
if (lastEdit.length !== edit.length || lastEdit.newText !== edit.newText) {
571
this.log('ERROR: Overlapping edit', item.fileName, edit.offset, edits);
572
throw new Error('OVERLAPPING edit');
573
}
574
else {
575
continue;
576
}
577
}
578
lastEdit = edit;
579
const mangledName = characters.splice(edit.offset, edit.length, edit.newText).join('');
580
savedBytes += mangledName.length - edit.newText.length;
581
// source maps
582
const pos = item.getLineAndCharacterOfPosition(edit.offset);
583
let mappings = mappingsByLine.get(pos.line);
584
if (!mappings) {
585
mappings = [];
586
mappingsByLine.set(pos.line, mappings);
587
}
588
mappings.unshift({
589
source: relativeFileName,
590
original: { line: pos.line + 1, column: pos.character },
591
generated: { line: pos.line + 1, column: pos.character },
592
name: mangledName
593
}, {
594
source: relativeFileName,
595
original: { line: pos.line + 1, column: pos.character + edit.length },
596
generated: { line: pos.line + 1, column: pos.character + edit.newText.length },
597
});
598
}
599
// source map generation, make sure to get mappings per line correct
600
generator = new source_map_1.SourceMapGenerator({ file: path_1.default.basename(item.fileName), sourceRoot: sourceMapRoot });
601
generator.setSourceContent(relativeFileName, item.getFullText());
602
for (const [, mappings] of mappingsByLine) {
603
let lineDelta = 0;
604
for (const mapping of mappings) {
605
generator.addMapping({
606
...mapping,
607
generated: { line: mapping.generated.line, column: mapping.generated.column - lineDelta }
608
});
609
lineDelta += mapping.original.column - mapping.generated.column;
610
}
611
}
612
newFullText = characters.join('');
613
}
614
result.set(item.fileName, { out: newFullText, sourceMap: generator?.toString() });
615
}
616
service.dispose();
617
this.renameWorkerPool.terminate();
618
this.log(`Done: ${savedBytes / 1000}kb saved, memory-usage: ${JSON.stringify(node_v8_1.default.getHeapStatistics())}`);
619
return result;
620
}
621
}
622
exports.Mangler = Mangler;
623
// --- ast utils
624
function hasModifier(node, kind) {
625
const modifiers = typescript_1.default.canHaveModifiers(node) ? typescript_1.default.getModifiers(node) : undefined;
626
return Boolean(modifiers?.find(mode => mode.kind === kind));
627
}
628
function isInAmbientContext(node) {
629
for (let p = node.parent; p; p = p.parent) {
630
if (typescript_1.default.isModuleDeclaration(p)) {
631
return true;
632
}
633
}
634
return false;
635
}
636
function normalize(path) {
637
return path.replace(/\\/g, '/');
638
}
639
async function _run() {
640
const root = path_1.default.join(__dirname, '..', '..', '..');
641
const projectBase = path_1.default.join(root, 'src');
642
const projectPath = path_1.default.join(projectBase, 'tsconfig.json');
643
const newProjectBase = path_1.default.join(path_1.default.dirname(projectBase), path_1.default.basename(projectBase) + '2');
644
fs_1.default.cpSync(projectBase, newProjectBase, { recursive: true });
645
const mangler = new Mangler(projectPath, console.log, {
646
mangleExports: true,
647
manglePrivateFields: true,
648
});
649
for (const [fileName, contents] of await mangler.computeNewFileContents(new Set(['saveState']))) {
650
const newFilePath = path_1.default.join(newProjectBase, path_1.default.relative(projectBase, fileName));
651
await fs_1.default.promises.mkdir(path_1.default.dirname(newFilePath), { recursive: true });
652
await fs_1.default.promises.writeFile(newFilePath, contents.out);
653
if (contents.sourceMap) {
654
await fs_1.default.promises.writeFile(newFilePath + '.map', contents.sourceMap);
655
}
656
}
657
}
658
if (__filename === process_1.argv[1]) {
659
_run();
660
}
661
//# sourceMappingURL=index.js.map
662