Skip to content

Commit 36eae04

Browse files
committed
Handle emit helpers in --out scenario
1 parent c739def commit 36eae04

16 files changed

Lines changed: 808 additions & 930 deletions

src/compiler/emitter.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,16 +1136,16 @@ namespace ts {
11361136
if (bundle && moduleKind === ModuleKind.None) {
11371137
return;
11381138
}
1139-
1140-
const numNodes = bundle ? bundle.sourceFiles.length : 1;
1139+
const numPrepends = bundle ? bundle.prepends.length : 0;
1140+
const numNodes = bundle ? bundle.sourceFiles.length + numPrepends : 1;
11411141
for (let i = 0; i < numNodes; i++) {
1142-
const currentNode = bundle ? bundle.sourceFiles[i] : node;
1143-
const sourceFile = isSourceFile(currentNode) ? currentNode : currentSourceFile!;
1144-
const shouldSkip = printerOptions.noEmitHelpers || getExternalHelpersModuleName(sourceFile) !== undefined;
1145-
const shouldBundle = isSourceFile(currentNode) && !isOwnFileEmit;
1146-
const helpers = getEmitHelpers(currentNode);
1142+
const currentNode = bundle ? i < numPrepends ? bundle.prepends[i] : bundle.sourceFiles[i - numPrepends] : node;
1143+
const sourceFile = isSourceFile(currentNode) ? currentNode : isUnparsedSource(currentNode) ? undefined : currentSourceFile!;
1144+
const shouldSkip = printerOptions.noEmitHelpers || (!!sourceFile && getExternalHelpersModuleName(sourceFile) !== undefined);
1145+
const shouldBundle = (isSourceFile(currentNode) || isUnparsedSource(currentNode)) && !isOwnFileEmit;
1146+
const helpers = isUnparsedSource(currentNode) ? currentNode.helpers : getSortedEmitHelpers(currentNode);
11471147
if (helpers) {
1148-
for (const helper of stableSort(helpers, compareEmitHelpers)) {
1148+
for (const helper of helpers) {
11491149
if (!helper.scoped) {
11501150
// Skip the helper if it can be skipped and the noEmitHelpers compiler
11511151
// option is set, or if it can be imported and the importHelpers compiler
@@ -1181,6 +1181,11 @@ namespace ts {
11811181
return helpersEmitted;
11821182
}
11831183

1184+
function getSortedEmitHelpers(node: Node) {
1185+
const helpers = getEmitHelpers(node);
1186+
return helpers && stableSort(helpers, compareEmitHelpers);
1187+
}
1188+
11841189
//
11851190
// Literals/Pseudo-literals
11861191
//

src/compiler/factory.ts

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2629,6 +2629,71 @@ namespace ts {
26292629
return node;
26302630
}
26312631

2632+
interface UnscopedEmitHelpersWithLines {
2633+
helper: UnscopedEmitHelpers;
2634+
lines: ReadonlyArray<string>;
2635+
}
2636+
2637+
let allUnscopedEmitHelpers: ReadonlyArray<UnscopedEmitHelpersWithLines> | undefined;
2638+
function getAllUnscopedEmitHelpers() {
2639+
return allUnscopedEmitHelpers ||
2640+
(allUnscopedEmitHelpers = [
2641+
getUnscopedEmitHelperWithLines(valuesHelper),
2642+
getUnscopedEmitHelperWithLines(readHelper),
2643+
getUnscopedEmitHelperWithLines(spreadHelper),
2644+
getUnscopedEmitHelperWithLines(restHelper),
2645+
getUnscopedEmitHelperWithLines(decorateHelper),
2646+
getUnscopedEmitHelperWithLines(metadataHelper),
2647+
getUnscopedEmitHelperWithLines(paramHelper),
2648+
getUnscopedEmitHelperWithLines(awaiterHelper),
2649+
getUnscopedEmitHelperWithLines(assignHelper),
2650+
getUnscopedEmitHelperWithLines(awaitHelper),
2651+
getUnscopedEmitHelperWithLines(asyncGeneratorHelper),
2652+
getUnscopedEmitHelperWithLines(asyncDelegator),
2653+
getUnscopedEmitHelperWithLines(asyncValues),
2654+
getUnscopedEmitHelperWithLines(extendsHelper),
2655+
getUnscopedEmitHelperWithLines(templateObjectHelper),
2656+
getUnscopedEmitHelperWithLines(generatorHelper),
2657+
getUnscopedEmitHelperWithLines(importStarHelper),
2658+
getUnscopedEmitHelperWithLines(importDefaultHelper)
2659+
]);
2660+
}
2661+
2662+
function getUnscopedEmitHelperWithLines(helper: UnscopedEmitHelpers): UnscopedEmitHelpersWithLines {
2663+
const helperLines = helper.text.split(/\r\n?|\n/g);
2664+
const indentation = guessIndentation(helperLines);
2665+
const lines: string[] = [];
2666+
for (const lineText of helperLines) {
2667+
const line = indentation ? lineText.slice(indentation) : lineText;
2668+
if (line.length) {
2669+
lines.push(line);
2670+
}
2671+
}
2672+
return { helper, lines };
2673+
}
2674+
2675+
function tryGetUnscopedEmitHelper(text: string, pos: number) {
2676+
const allHelpers = getAllUnscopedEmitHelpers();
2677+
if (pos >= text.length) return undefined;
2678+
for (const { helper, lines } of allHelpers) {
2679+
let newPos = pos;
2680+
for (const line of lines) {
2681+
const startIndex = text.indexOf(line, newPos);
2682+
if (startIndex !== newPos) {
2683+
newPos = -1;
2684+
break;
2685+
}
2686+
newPos = skipTrivia(text, newPos + line.length, /*stopAfterLineBreak*/ true);
2687+
}
2688+
2689+
// Found match
2690+
if (newPos !== -1) {
2691+
return { helper, newPos };
2692+
}
2693+
}
2694+
return undefined;
2695+
}
2696+
26322697
export function createUnparsedSourceFile(text: string): UnparsedSource;
26332698
export function createUnparsedSourceFile(inputFile: InputFiles, type: "js" | "dts"): UnparsedSource;
26342699
export function createUnparsedSourceFile(text: string, mapPath: string | undefined, map: string | undefined): UnparsedSource;
@@ -2649,7 +2714,11 @@ namespace ts {
26492714
node.sourceMapText = map;
26502715
}
26512716
const text = node.text;
2717+
2718+
// Shebang
26522719
let pos = isShebangTrivia(text, 0) ? skipTrivia(text, 0, /*stopAfterLineBreak*/ true) : 0;
2720+
2721+
// Prologue
26532722
const scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true, /*languageVariant*/ undefined, text, /*onError*/ undefined, pos);
26542723
let prologues: UnparsedPrologue[] | undefined;
26552724
while (scanner.scan() === SyntaxKind.StringLiteral) {
@@ -2663,8 +2732,20 @@ namespace ts {
26632732
prologue.text = prologueText;
26642733
(prologues || (prologues = [])).push(prologue);
26652734
}
2735+
2736+
// Helpers
2737+
let helpers: UnscopedEmitHelpers[] | undefined;
2738+
while (true) {
2739+
const helperInfo = tryGetUnscopedEmitHelper(text, pos);
2740+
if (!helperInfo) break;
2741+
pos = helperInfo.newPos;
2742+
(helpers || (helpers = [])).push(helperInfo.helper);
2743+
}
2744+
2745+
// Rest of the text
26662746
node.pos = pos;
26672747
node.prologues = prologues || emptyArray;
2748+
node.helpers = helpers;
26682749
node.getLineAndCharacterOfPosition = pos => getLineAndCharacterOfPosition(node, pos);
26692750
return node;
26702751
}
@@ -3390,7 +3471,7 @@ namespace ts {
33903471
return setEmitFlags(createIdentifier(name), EmitFlags.HelperName | EmitFlags.AdviseOnEmitNode);
33913472
}
33923473

3393-
const valuesHelper: EmitHelper = {
3474+
export const valuesHelper: UnscopedEmitHelpers = {
33943475
name: "typescript:values",
33953476
scoped: false,
33963477
text: `
@@ -3418,7 +3499,7 @@ namespace ts {
34183499
);
34193500
}
34203501

3421-
const readHelper: EmitHelper = {
3502+
export const readHelper: UnscopedEmitHelpers = {
34223503
name: "typescript:read",
34233504
scoped: false,
34243505
text: `
@@ -3454,7 +3535,7 @@ namespace ts {
34543535
);
34553536
}
34563537

3457-
const spreadHelper: EmitHelper = {
3538+
export const spreadHelper: UnscopedEmitHelpers = {
34583539
name: "typescript:spread",
34593540
scoped: false,
34603541
text: `

src/compiler/transformers/destructuring.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ namespace ts {
512512
return name;
513513
}
514514

515-
const restHelper: EmitHelper = {
515+
export const restHelper: UnscopedEmitHelpers = {
516516
name: "typescript:rest",
517517
scoped: false,
518518
text: `

src/compiler/transformers/es2015.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4383,7 +4383,7 @@ namespace ts {
43834383
);
43844384
}
43854385

4386-
const extendsHelper: EmitHelper = {
4386+
export const extendsHelper: UnscopedEmitHelpers = {
43874387
name: "typescript:extends",
43884388
scoped: false,
43894389
priority: 0,
@@ -4404,7 +4404,7 @@ namespace ts {
44044404
})();`
44054405
};
44064406

4407-
const templateObjectHelper: EmitHelper = {
4407+
export const templateObjectHelper: UnscopedEmitHelpers = {
44084408
name: "typescript:makeTemplateObject",
44094409
scoped: false,
44104410
priority: 0,

src/compiler/transformers/es2017.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,7 @@ namespace ts {
750750
NodeFlags.Const));
751751
}
752752

753-
const awaiterHelper: EmitHelper = {
753+
export const awaiterHelper: UnscopedEmitHelpers = {
754754
name: "typescript:awaiter",
755755
scoped: false,
756756
priority: 5,

src/compiler/transformers/esnext.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,7 @@ namespace ts {
929929
}
930930
}
931931

932-
const assignHelper: EmitHelper = {
932+
export const assignHelper: UnscopedEmitHelpers = {
933933
name: "typescript:assign",
934934
scoped: false,
935935
priority: 1,
@@ -961,7 +961,7 @@ namespace ts {
961961
);
962962
}
963963

964-
const awaitHelper: EmitHelper = {
964+
export const awaitHelper: UnscopedEmitHelpers = {
965965
name: "typescript:await",
966966
scoped: false,
967967
text: `
@@ -973,7 +973,7 @@ namespace ts {
973973
return createCall(getHelperName("__await"), /*typeArguments*/ undefined, [expression]);
974974
}
975975

976-
const asyncGeneratorHelper: EmitHelper = {
976+
export const asyncGeneratorHelper: UnscopedEmitHelpers = {
977977
name: "typescript:asyncGenerator",
978978
scoped: false,
979979
text: `
@@ -1008,7 +1008,7 @@ namespace ts {
10081008
);
10091009
}
10101010

1011-
const asyncDelegator: EmitHelper = {
1011+
export const asyncDelegator: UnscopedEmitHelpers = {
10121012
name: "typescript:asyncDelegator",
10131013
scoped: false,
10141014
text: `
@@ -1032,7 +1032,7 @@ namespace ts {
10321032
);
10331033
}
10341034

1035-
const asyncValues: EmitHelper = {
1035+
export const asyncValues: UnscopedEmitHelpers = {
10361036
name: "typescript:asyncValues",
10371037
scoped: false,
10381038
text: `

src/compiler/transformers/generators.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3240,7 +3240,7 @@ namespace ts {
32403240
// entering a finally block.
32413241
//
32423242
// For examples of how these are used, see the comments in ./transformers/generators.ts
3243-
const generatorHelper: EmitHelper = {
3243+
export const generatorHelper: UnscopedEmitHelpers = {
32443244
name: "typescript:generator",
32453245
scoped: false,
32463246
priority: 6,

src/compiler/transformers/module/module.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,7 +1806,7 @@ namespace ts {
18061806
};
18071807

18081808
// emit helper for `import * as Name from "foo"`
1809-
const importStarHelper: EmitHelper = {
1809+
export const importStarHelper: UnscopedEmitHelpers = {
18101810
name: "typescript:commonjsimportstar",
18111811
scoped: false,
18121812
text: `
@@ -1820,7 +1820,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
18201820
};
18211821

18221822
// emit helper for `import Name from "foo"`
1823-
const importDefaultHelper: EmitHelper = {
1823+
export const importDefaultHelper: UnscopedEmitHelpers = {
18241824
name: "typescript:commonjsimportdefault",
18251825
scoped: false,
18261826
text: `

src/compiler/transformers/ts.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3675,7 +3675,7 @@ namespace ts {
36753675
);
36763676
}
36773677

3678-
const decorateHelper: EmitHelper = {
3678+
export const decorateHelper: UnscopedEmitHelpers = {
36793679
name: "typescript:decorate",
36803680
scoped: false,
36813681
priority: 2,
@@ -3700,7 +3700,7 @@ namespace ts {
37003700
);
37013701
}
37023702

3703-
const metadataHelper: EmitHelper = {
3703+
export const metadataHelper: UnscopedEmitHelpers = {
37043704
name: "typescript:metadata",
37053705
scoped: false,
37063706
priority: 3,
@@ -3725,7 +3725,7 @@ namespace ts {
37253725
);
37263726
}
37273727

3728-
const paramHelper: EmitHelper = {
3728+
export const paramHelper: UnscopedEmitHelpers = {
37293729
name: "typescript:param",
37303730
scoped: false,
37313731
priority: 4,

src/compiler/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2777,6 +2777,7 @@ namespace ts {
27772777
fileName?: string;
27782778
text: string;
27792779
prologues: ReadonlyArray<UnparsedPrologue>;
2780+
helpers: ReadonlyArray<UnscopedEmitHelpers> | undefined;
27802781
sourceMapPath?: string;
27812782
sourceMapText?: string;
27822783
/*@internal*/ parsedSourceMap?: RawSourceMap | false | undefined;
@@ -5189,6 +5190,11 @@ namespace ts {
51895190
readonly priority?: number; // Helpers with a higher priority are emitted earlier than other helpers on the node.
51905191
}
51915192

5193+
export interface UnscopedEmitHelpers extends EmitHelper {
5194+
readonly scoped: false; // Indicates whether the helper MUST be emitted in the current scope.
5195+
readonly text: string; // ES3-compatible raw script text, or a function yielding such a string
5196+
}
5197+
51925198
/* @internal */
51935199
export type UniqueNameHandler = (baseName: string, checkFn?: (name: string) => boolean, optimistic?: boolean) => string;
51945200

0 commit comments

Comments
 (0)