mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Reduce stack depth from transforms
This commit is contained in:
+62
-17
@@ -105,7 +105,9 @@ namespace ts {
|
||||
hasGlobalName: resolver.hasGlobalName,
|
||||
|
||||
// transform hooks
|
||||
onEmitNode: transform.emitNodeWithNotification,
|
||||
onEmitNode: transform.useEmitNodeWithNotification ? transform.emitNodeWithNotification : undefined,
|
||||
onBeforeEmitNode: transform.useEmitNodeWithNotification ? undefined : transform.beforeEmitNode,
|
||||
onAfterEmitNode: transform.useEmitNodeWithNotification ? undefined : transform.afterEmitNode,
|
||||
substituteNode: transform.substituteNode,
|
||||
|
||||
// sourcemap hooks
|
||||
@@ -260,11 +262,15 @@ namespace ts {
|
||||
}
|
||||
|
||||
const enum PipelinePhase {
|
||||
BeforeEmit,
|
||||
LeadingComments,
|
||||
LeadingSourceMap,
|
||||
Emit,
|
||||
TrailingSourceMap,
|
||||
TrailingComments
|
||||
TrailingComments,
|
||||
AfterEmit,
|
||||
|
||||
Start = BeforeEmit
|
||||
}
|
||||
|
||||
export function createPrinter(printerOptions: PrinterOptions = {}, handlers: PrintHandlers = {}): Printer {
|
||||
@@ -275,6 +281,8 @@ namespace ts {
|
||||
onEmitSourceMapOfToken,
|
||||
onEmitSourceMapOfPosition,
|
||||
onEmitNode,
|
||||
onBeforeEmitNode,
|
||||
onAfterEmitNode,
|
||||
onEmitHelpers,
|
||||
onSetSourceFile,
|
||||
substituteNode,
|
||||
@@ -284,6 +292,8 @@ namespace ts {
|
||||
onAfterEmitToken
|
||||
} = handlers;
|
||||
|
||||
Debug.assert(!(onEmitNode && (onBeforeEmitNode || onAfterEmitNode)), "Do not provide 'onEmitNode' of either of 'onBeforeEmitNode' or 'onAfterEmitNode' are provided.");
|
||||
|
||||
const newLine = getNewLineCharacter(printerOptions);
|
||||
const comments = createCommentWriter(printerOptions, onEmitSourceMapOfPosition);
|
||||
const {
|
||||
@@ -428,7 +438,13 @@ namespace ts {
|
||||
setSourceFile(sourceFile);
|
||||
}
|
||||
|
||||
pipelineEmitWithNotification(hint, node);
|
||||
// NOTE: this has been manually inlined to reduce overall stack depth
|
||||
if (onEmitNode) {
|
||||
onEmitNode(hint, node, pipelineEmit);
|
||||
}
|
||||
else {
|
||||
pipelineEmitWorker(hint, node, PipelinePhase.Start);
|
||||
}
|
||||
}
|
||||
|
||||
function setSourceFile(sourceFile: SourceFile) {
|
||||
@@ -456,33 +472,49 @@ namespace ts {
|
||||
}
|
||||
|
||||
function emit(node: Node | undefined) {
|
||||
pipelineEmitWithNotification(EmitHint.Unspecified, node);
|
||||
// NOTE: this has been manually inlined to reduce overall stack depth
|
||||
if (onEmitNode) {
|
||||
onEmitNode(EmitHint.Unspecified, node, pipelineEmit);
|
||||
}
|
||||
else {
|
||||
pipelineEmitWorker(EmitHint.Unspecified, node, PipelinePhase.Start);
|
||||
}
|
||||
}
|
||||
|
||||
function emitIdentifierName(node: Identifier | undefined) {
|
||||
pipelineEmitWithNotification(EmitHint.IdentifierName, node);
|
||||
// NOTE: this has been manually inlined to reduce overall stack depth
|
||||
if (onEmitNode) {
|
||||
onEmitNode(EmitHint.IdentifierName, node, pipelineEmit);
|
||||
}
|
||||
else {
|
||||
pipelineEmitWorker(EmitHint.IdentifierName, node, PipelinePhase.Start);
|
||||
}
|
||||
}
|
||||
|
||||
function emitExpression(node: Expression | undefined) {
|
||||
pipelineEmitWithNotification(EmitHint.Expression, node);
|
||||
}
|
||||
|
||||
function pipelineEmitWithNotification(hint: EmitHint, node: Node) {
|
||||
// NOTE: this has been manually inlined to reduce overall stack depth
|
||||
if (onEmitNode) {
|
||||
onEmitNode(hint, node, pipelineEmitWithComments);
|
||||
onEmitNode(EmitHint.Expression, node, pipelineEmit);
|
||||
}
|
||||
else {
|
||||
pipelineEmitWithComments(hint, node);
|
||||
pipelineEmitWorker(EmitHint.Expression, node, PipelinePhase.Start);
|
||||
}
|
||||
}
|
||||
|
||||
function pipelineEmitWithComments(hint: EmitHint, node: Node) {
|
||||
pipelineEmit(hint, node, PipelinePhase.LeadingComments);
|
||||
function pipelineEmit(hint: EmitHint, node: Node) {
|
||||
pipelineEmitWorker(hint, node, PipelinePhase.Start);
|
||||
}
|
||||
|
||||
function pipelineEmit(hint: EmitHint, node: Node | undefined, start: PipelinePhase) {
|
||||
function pipelineEmitWorker(hint: EmitHint, node: Node | undefined, phase: PipelinePhase) {
|
||||
if (!node) return;
|
||||
switch (start) {
|
||||
switch (phase) {
|
||||
case PipelinePhase.BeforeEmit:
|
||||
if (onBeforeEmitNode) {
|
||||
onBeforeEmitNode(hint, node);
|
||||
}
|
||||
|
||||
// falls through
|
||||
|
||||
case PipelinePhase.LeadingComments:
|
||||
node = trySubstituteNode(hint, node);
|
||||
if (hint !== EmitHint.SourceFile) {
|
||||
@@ -514,7 +546,12 @@ namespace ts {
|
||||
emitTrailingCommentsOfNode(node);
|
||||
}
|
||||
|
||||
break;
|
||||
// falls through
|
||||
|
||||
case PipelinePhase.AfterEmit:
|
||||
if (onAfterEmitNode) {
|
||||
onAfterEmitNode(hint, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1260,7 +1297,15 @@ namespace ts {
|
||||
}
|
||||
|
||||
writePunctuation("[");
|
||||
pipelineEmitWithNotification(EmitHint.MappedTypeParameter, node.typeParameter);
|
||||
|
||||
// NOTE: this has been manually inlined to reduce overall stack depth
|
||||
if (onEmitNode) {
|
||||
onEmitNode(EmitHint.MappedTypeParameter, node.typeParameter, pipelineEmit);
|
||||
}
|
||||
else {
|
||||
pipelineEmitWorker(EmitHint.MappedTypeParameter, node.typeParameter, PipelinePhase.Start);
|
||||
}
|
||||
|
||||
writePunctuation("]");
|
||||
|
||||
emit(node.questionToken);
|
||||
|
||||
@@ -37,15 +37,6 @@ namespace ts {
|
||||
emitLeadingSourceMapOfNode(node: Node): void;
|
||||
emitTrailingSourceMapOfNode(node: Node): void;
|
||||
|
||||
/**
|
||||
* Emits a node with possible leading and trailing source maps.
|
||||
*
|
||||
* @param hint The current emit context
|
||||
* @param node The node to emit.
|
||||
* @param emitCallback The callback used to emit the node.
|
||||
*/
|
||||
emitNodeWithSourceMap(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
|
||||
|
||||
/**
|
||||
* Emits a token of a node node with possible leading and trailing source maps.
|
||||
*
|
||||
@@ -108,7 +99,6 @@ namespace ts {
|
||||
emitPos,
|
||||
emitLeadingSourceMapOfNode,
|
||||
emitTrailingSourceMapOfNode,
|
||||
emitNodeWithSourceMap,
|
||||
emitTokenWithSourceMap,
|
||||
getText,
|
||||
getSourceMappingURL,
|
||||
@@ -317,20 +307,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits a node with possible leading and trailing source maps.
|
||||
*
|
||||
* @param hint A hint as to the intended usage of the node.
|
||||
* @param node The node to emit.
|
||||
* @param emitCallback The callback used to emit the node.
|
||||
*/
|
||||
function emitNodeWithSourceMap(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
|
||||
if (!node) return;
|
||||
emitLeadingSourceMapOfNode(node);
|
||||
emitCallback(hint, node);
|
||||
emitTrailingSourceMapOfNode(node);
|
||||
}
|
||||
|
||||
function emitLeadingSourceMapOfNode(node: Node) {
|
||||
if (!node) return;
|
||||
|
||||
|
||||
@@ -82,6 +82,13 @@ namespace ts {
|
||||
return transformers;
|
||||
}
|
||||
|
||||
const defaultOnSubstituteNode: TransformationContext["onSubstituteNode"] = (_, node) => node;
|
||||
const defaultOnEmitNode: TransformationContext["onEmitNode"] = (hint, node, callback) => callback(hint, node);
|
||||
// NOTE: not using `noop` here to avoid deoptimizations due to inlining and argument/parameter
|
||||
// count mismatches. Deoptimization for this would be severely negative as these functions are
|
||||
// used in a hot path.
|
||||
const defaultOnBeforeOrAfterEmitNode: TransformationContext["onBeforeEmitNode"] = (_hint, _node) => { /*empty*/ };
|
||||
|
||||
/**
|
||||
* Transforms an array of SourceFiles by passing them through each transformer.
|
||||
*
|
||||
@@ -101,8 +108,10 @@ namespace ts {
|
||||
let lexicalEnvironmentStackOffset = 0;
|
||||
let lexicalEnvironmentSuspended = false;
|
||||
let emitHelpers: EmitHelper[];
|
||||
let onSubstituteNode: TransformationContext["onSubstituteNode"] = (_, node) => node;
|
||||
let onEmitNode: TransformationContext["onEmitNode"] = (hint, node, callback) => callback(hint, node);
|
||||
let onSubstituteNode: TransformationContext["onSubstituteNode"] = defaultOnSubstituteNode;
|
||||
let onEmitNode: TransformationContext["onEmitNode"];
|
||||
let onBeforeEmitNode: TransformationContext["onBeforeEmitNode"];
|
||||
let onAfterEmitNode: TransformationContext["onBeforeEmitNode"];
|
||||
let state = TransformationState.Uninitialized;
|
||||
|
||||
// The transformation context is provided to each transformer as part of transformer
|
||||
@@ -129,12 +138,32 @@ namespace ts {
|
||||
Debug.assert(value !== undefined, "Value must not be 'undefined'");
|
||||
onSubstituteNode = value;
|
||||
},
|
||||
get onEmitNode() { return onEmitNode; },
|
||||
get onEmitNode() {
|
||||
// for backwards compatibility, we push any current before/after events into the current callback.
|
||||
if (onBeforeEmitNode || onAfterEmitNode) {
|
||||
onEmitNode = wrapNotification(onEmitNode || defaultOnEmitNode, onBeforeEmitNode, onAfterEmitNode);
|
||||
onBeforeEmitNode = undefined;
|
||||
onAfterEmitNode = undefined;
|
||||
}
|
||||
return onEmitNode || defaultOnEmitNode;
|
||||
},
|
||||
set onEmitNode(value) {
|
||||
Debug.assert(state < TransformationState.Initialized, "Cannot modify transformation hooks after initialization has completed.");
|
||||
Debug.assert(value !== undefined, "Value must not be 'undefined'");
|
||||
onEmitNode = value;
|
||||
}
|
||||
},
|
||||
get onBeforeEmitNode() { return onBeforeEmitNode || defaultOnBeforeOrAfterEmitNode; },
|
||||
set onBeforeEmitNode(value) {
|
||||
Debug.assert(state < TransformationState.Initialized, "Cannot modify transformation hooks after initialization has completed.");
|
||||
Debug.assert(value !== undefined, "Value must not be 'undefined'");
|
||||
onBeforeEmitNode = value;
|
||||
},
|
||||
get onAfterEmitNode() { return onAfterEmitNode || defaultOnBeforeOrAfterEmitNode; },
|
||||
set onAfterEmitNode(value) {
|
||||
Debug.assert(state < TransformationState.Initialized, "Cannot modify transformation hooks after initialization has completed.");
|
||||
Debug.assert(value !== undefined, "Value must not be 'undefined'");
|
||||
onAfterEmitNode = value;
|
||||
},
|
||||
};
|
||||
|
||||
// Ensure the parse tree is clean before applying transformations
|
||||
@@ -159,11 +188,21 @@ namespace ts {
|
||||
performance.mark("afterTransform");
|
||||
performance.measure("transformTime", "beforeTransform", "afterTransform");
|
||||
|
||||
// for backwards compatibility, we push any current before/after events into the current callback.
|
||||
if (onEmitNode && (onBeforeEmitNode || onAfterEmitNode)) {
|
||||
onEmitNode = wrapNotification(onEmitNode, onBeforeEmitNode, onAfterEmitNode);
|
||||
onBeforeEmitNode = undefined;
|
||||
onAfterEmitNode = undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
transformed,
|
||||
substituteNode,
|
||||
useEmitNodeWithNotification: onEmitNode !== undefined,
|
||||
emitNodeWithNotification,
|
||||
dispose
|
||||
beforeEmitNode: onBeforeEmitNode ? beforeEmitNode : undefined,
|
||||
afterEmitNode: onAfterEmitNode ? afterEmitNode : undefined,
|
||||
dispose,
|
||||
};
|
||||
|
||||
function transformRoot(node: T) {
|
||||
@@ -215,6 +254,14 @@ namespace ts {
|
||||
|| (getEmitFlags(node) & EmitFlags.AdviseOnEmitNode) !== 0;
|
||||
}
|
||||
|
||||
function wrapNotification(onEmitNode: TransformationContext["onEmitNode"], onBeforeEmitNode: TransformationContext["onBeforeEmitNode"], onAfterEmitNode: TransformationContext["onAfterEmitNode"]): TransformationContext["onEmitNode"] {
|
||||
return (hint, node, emitCallback) => {
|
||||
if (onBeforeEmitNode) onBeforeEmitNode(hint, node);
|
||||
onEmitNode(hint, node, emitCallback);
|
||||
if (onAfterEmitNode) onAfterEmitNode(hint, node);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits a node with possible emit notification.
|
||||
*
|
||||
@@ -226,7 +273,7 @@ namespace ts {
|
||||
Debug.assert(state < TransformationState.Disposed, "Cannot invoke TransformationResult callbacks after the result is disposed.");
|
||||
if (node) {
|
||||
if (isEmitNotificationEnabled(node)) {
|
||||
onEmitNode(hint, node, emitCallback);
|
||||
if (onEmitNode) onEmitNode(hint, node, emitCallback);
|
||||
}
|
||||
else {
|
||||
emitCallback(hint, node);
|
||||
@@ -234,6 +281,20 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function beforeEmitNode(hint: EmitHint, node: Node) {
|
||||
Debug.assert(state < TransformationState.Disposed, "Cannot invoke TransformationResult callbacks after the result is disposed.");
|
||||
if (node && onBeforeEmitNode && isEmitNotificationEnabled(node)) {
|
||||
onBeforeEmitNode(hint, node);
|
||||
}
|
||||
}
|
||||
|
||||
function afterEmitNode(hint: EmitHint, node: Node) {
|
||||
Debug.assert(state < TransformationState.Disposed, "Cannot invoke TransformationResult callbacks after the result is disposed.");
|
||||
if (node && onAfterEmitNode && isEmitNotificationEnabled(node)) {
|
||||
onAfterEmitNode(hint, node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Records a hoisted variable declaration for the provided name within a lexical environment.
|
||||
*/
|
||||
|
||||
@@ -272,12 +272,15 @@ namespace ts {
|
||||
const compilerOptions = context.getCompilerOptions();
|
||||
const resolver = context.getEmitResolver();
|
||||
const previousOnSubstituteNode = context.onSubstituteNode;
|
||||
const previousOnEmitNode = context.onEmitNode;
|
||||
context.onEmitNode = onEmitNode;
|
||||
const previousOnBeforeEmitNode = context.onBeforeEmitNode;
|
||||
const previousOnAfterEmitNode = context.onAfterEmitNode;
|
||||
context.onSubstituteNode = onSubstituteNode;
|
||||
context.onBeforeEmitNode = onBeforeEmitNode;
|
||||
context.onAfterEmitNode = onAfterEmitNode;
|
||||
|
||||
let currentSourceFile: SourceFile;
|
||||
let currentText: string;
|
||||
const hierarchyFactsStack: HierarchyFacts[] = [];
|
||||
let hierarchyFacts: HierarchyFacts;
|
||||
let taggedTemplateStringDeclarations: VariableDeclaration[];
|
||||
|
||||
@@ -3840,9 +3843,8 @@ namespace ts {
|
||||
*
|
||||
* @param hint A hint as to the intended usage of the node.
|
||||
* @param node The node to be printed.
|
||||
* @param emitCallback The callback used to emit the node.
|
||||
*/
|
||||
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
|
||||
function onBeforeEmitNode(hint: EmitHint, node: Node) {
|
||||
if (enabledSubstitutions & ES2015SubstitutionFlags.CapturedThis && isFunctionLike(node)) {
|
||||
// If we are tracking a captured `this`, keep track of the enclosing function.
|
||||
const ancestorFacts = enterSubtree(
|
||||
@@ -3850,11 +3852,19 @@ namespace ts {
|
||||
getEmitFlags(node) & EmitFlags.CapturesThis
|
||||
? HierarchyFacts.FunctionIncludes | HierarchyFacts.CapturesThis
|
||||
: HierarchyFacts.FunctionIncludes);
|
||||
previousOnEmitNode(hint, node, emitCallback);
|
||||
hierarchyFactsStack.push(ancestorFacts);
|
||||
}
|
||||
|
||||
previousOnBeforeEmitNode(hint, node);
|
||||
}
|
||||
|
||||
function onAfterEmitNode(hint: EmitHint, node: Node) {
|
||||
previousOnAfterEmitNode(hint, node);
|
||||
|
||||
if (enabledSubstitutions & ES2015SubstitutionFlags.CapturedThis && isFunctionLike(node)) {
|
||||
const ancestorFacts = hierarchyFactsStack.pop();
|
||||
exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
|
||||
return;
|
||||
}
|
||||
previousOnEmitNode(hint, node, emitCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,15 +32,18 @@ namespace ts {
|
||||
* just-in-time substitution for `super` expressions inside of async methods.
|
||||
*/
|
||||
let enclosingSuperContainerFlags: NodeCheckFlags = 0;
|
||||
const enclosingSuperContainerFlagsStack: NodeCheckFlags[] = [];
|
||||
|
||||
let enclosingFunctionParameterNames: UnderscoreEscapedMap<true>;
|
||||
|
||||
// Save the previous transformation hooks.
|
||||
const previousOnEmitNode = context.onEmitNode;
|
||||
const previousOnBeforeEmitNode = context.onBeforeEmitNode;
|
||||
const previousOnAfterEmitNode = context.onAfterEmitNode;
|
||||
const previousOnSubstituteNode = context.onSubstituteNode;
|
||||
|
||||
// Set new transformation hooks.
|
||||
context.onEmitNode = onEmitNode;
|
||||
context.onBeforeEmitNode = onBeforeEmitNode;
|
||||
context.onAfterEmitNode = onAfterEmitNode;
|
||||
context.onSubstituteNode = onSubstituteNode;
|
||||
|
||||
return transformSourceFile;
|
||||
@@ -503,22 +506,23 @@ namespace ts {
|
||||
*
|
||||
* @param hint A hint as to the intended usage of the node.
|
||||
* @param node The node to emit.
|
||||
* @param emit A callback used to emit the node in the printer.
|
||||
*/
|
||||
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
|
||||
// If we need to support substitutions for `super` in an async method,
|
||||
// we should track it here.
|
||||
|
||||
function onBeforeEmitNode(hint: EmitHint, node: Node) {
|
||||
if (enabledSubstitutions & ES2017SubstitutionFlags.AsyncMethodsWithSuper && isSuperContainer(node)) {
|
||||
const superContainerFlags = resolver.getNodeCheckFlags(node) & (NodeCheckFlags.AsyncMethodWithSuper | NodeCheckFlags.AsyncMethodWithSuperBinding);
|
||||
if (superContainerFlags !== enclosingSuperContainerFlags) {
|
||||
const savedEnclosingSuperContainerFlags = enclosingSuperContainerFlags;
|
||||
enclosingSuperContainerFlags = superContainerFlags;
|
||||
previousOnEmitNode(hint, node, emitCallback);
|
||||
enclosingSuperContainerFlags = savedEnclosingSuperContainerFlags;
|
||||
return;
|
||||
}
|
||||
enclosingSuperContainerFlagsStack.push(enclosingSuperContainerFlags);
|
||||
enclosingSuperContainerFlags = resolver.getNodeCheckFlags(node) & (NodeCheckFlags.AsyncMethodWithSuper | NodeCheckFlags.AsyncMethodWithSuperBinding);
|
||||
}
|
||||
|
||||
previousOnBeforeEmitNode(hint, node);
|
||||
}
|
||||
|
||||
function onAfterEmitNode(hint: EmitHint, node: Node) {
|
||||
previousOnAfterEmitNode(hint, node);
|
||||
|
||||
if (enabledSubstitutions & ES2017SubstitutionFlags.AsyncMethodsWithSuper && isSuperContainer(node)) {
|
||||
enclosingSuperContainerFlags = enclosingSuperContainerFlagsStack.pop();
|
||||
}
|
||||
previousOnEmitNode(hint, node, emitCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,11 +12,11 @@ namespace ts {
|
||||
const compilerOptions = context.getCompilerOptions();
|
||||
|
||||
// enable emit notification only if using --jsx preserve or react-native
|
||||
let previousOnEmitNode: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
|
||||
let previousOnBeforeEmitNode: TransformationContext["onBeforeEmitNode"];
|
||||
let noSubstitution: boolean[];
|
||||
if (compilerOptions.jsx === JsxEmit.Preserve || compilerOptions.jsx === JsxEmit.ReactNative) {
|
||||
previousOnEmitNode = context.onEmitNode;
|
||||
context.onEmitNode = onEmitNode;
|
||||
previousOnBeforeEmitNode = context.onBeforeEmitNode;
|
||||
context.onBeforeEmitNode = onBeforeEmitNode;
|
||||
context.enableEmitNotification(SyntaxKind.JsxOpeningElement);
|
||||
context.enableEmitNotification(SyntaxKind.JsxClosingElement);
|
||||
context.enableEmitNotification(SyntaxKind.JsxSelfClosingElement);
|
||||
@@ -43,9 +43,8 @@ namespace ts {
|
||||
*
|
||||
* @param hint A hint as to the intended usage of the node.
|
||||
* @param node The node to emit.
|
||||
* @param emitCallback A callback used to emit the node.
|
||||
*/
|
||||
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (emitContext: EmitHint, node: Node) => void) {
|
||||
function onBeforeEmitNode(hint: EmitHint, node: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.JsxOpeningElement:
|
||||
case SyntaxKind.JsxClosingElement:
|
||||
@@ -55,7 +54,7 @@ namespace ts {
|
||||
break;
|
||||
}
|
||||
|
||||
previousOnEmitNode(hint, node, emitCallback);
|
||||
previousOnBeforeEmitNode(hint, node);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,8 +20,10 @@ namespace ts {
|
||||
const compilerOptions = context.getCompilerOptions();
|
||||
const languageVersion = getEmitScriptTarget(compilerOptions);
|
||||
|
||||
const previousOnEmitNode = context.onEmitNode;
|
||||
context.onEmitNode = onEmitNode;
|
||||
const previousOnBeforeEmitNode = context.onBeforeEmitNode;
|
||||
const previousOnAfterEmitNode = context.onAfterEmitNode;
|
||||
context.onBeforeEmitNode = onBeforeEmitNode;
|
||||
context.onAfterEmitNode = onAfterEmitNode;
|
||||
|
||||
const previousOnSubstituteNode = context.onSubstituteNode;
|
||||
context.onSubstituteNode = onSubstituteNode;
|
||||
@@ -29,6 +31,7 @@ namespace ts {
|
||||
let enabledSubstitutions: ESNextSubstitutionFlags;
|
||||
let enclosingFunctionFlags: FunctionFlags;
|
||||
let enclosingSuperContainerFlags: NodeCheckFlags = 0;
|
||||
const enclosingSuperContainerFlagsStack: NodeCheckFlags[] = [];
|
||||
|
||||
return transformSourceFile;
|
||||
|
||||
@@ -744,21 +747,23 @@ namespace ts {
|
||||
* @param node The node to be printed.
|
||||
* @param emitCallback The callback used to emit the node.
|
||||
*/
|
||||
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
|
||||
function onBeforeEmitNode(hint: EmitHint, node: Node) {
|
||||
// If we need to support substitutions for `super` in an async method,
|
||||
// we should track it here.
|
||||
if (enabledSubstitutions & ESNextSubstitutionFlags.AsyncMethodsWithSuper && isSuperContainer(node)) {
|
||||
const superContainerFlags = resolver.getNodeCheckFlags(node) & (NodeCheckFlags.AsyncMethodWithSuper | NodeCheckFlags.AsyncMethodWithSuperBinding);
|
||||
if (superContainerFlags !== enclosingSuperContainerFlags) {
|
||||
const savedEnclosingSuperContainerFlags = enclosingSuperContainerFlags;
|
||||
enclosingSuperContainerFlags = superContainerFlags;
|
||||
previousOnEmitNode(hint, node, emitCallback);
|
||||
enclosingSuperContainerFlags = savedEnclosingSuperContainerFlags;
|
||||
return;
|
||||
}
|
||||
enclosingSuperContainerFlagsStack.push(enclosingSuperContainerFlags);
|
||||
enclosingSuperContainerFlags = resolver.getNodeCheckFlags(node) & (NodeCheckFlags.AsyncMethodWithSuper | NodeCheckFlags.AsyncMethodWithSuperBinding);
|
||||
}
|
||||
|
||||
previousOnEmitNode(hint, node, emitCallback);
|
||||
previousOnBeforeEmitNode(hint, node);
|
||||
}
|
||||
|
||||
function onAfterEmitNode(hint: EmitHint, node: Node) {
|
||||
previousOnAfterEmitNode(hint, node);
|
||||
|
||||
if (enabledSubstitutions & ESNextSubstitutionFlags.AsyncMethodsWithSuper && isSuperContainer(node)) {
|
||||
enclosingSuperContainerFlags = enclosingSuperContainerFlagsStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
namespace ts {
|
||||
export function transformES2015Module(context: TransformationContext) {
|
||||
const compilerOptions = context.getCompilerOptions();
|
||||
const previousOnEmitNode = context.onEmitNode;
|
||||
const previousOnBeforeEmitNode = context.onBeforeEmitNode;
|
||||
const previousOnAfterEmitNode = context.onAfterEmitNode;
|
||||
const previousOnSubstituteNode = context.onSubstituteNode;
|
||||
context.onEmitNode = onEmitNode;
|
||||
context.onBeforeEmitNode = onBeforeEmitNode;
|
||||
context.onAfterEmitNode = onAfterEmitNode;
|
||||
context.onSubstituteNode = onSubstituteNode;
|
||||
context.enableEmitNotification(SyntaxKind.SourceFile);
|
||||
context.enableSubstitution(SyntaxKind.Identifier);
|
||||
@@ -73,16 +75,18 @@ namespace ts {
|
||||
*
|
||||
* @param hint A hint as to the intended usage of the node.
|
||||
* @param node The node to emit.
|
||||
* @param emit A callback used to emit the node in the printer.
|
||||
*/
|
||||
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
|
||||
function onBeforeEmitNode(hint: EmitHint, node: Node): void {
|
||||
if (isSourceFile(node)) {
|
||||
currentSourceFile = node;
|
||||
previousOnEmitNode(hint, node, emitCallback);
|
||||
currentSourceFile = undefined;
|
||||
}
|
||||
else {
|
||||
previousOnEmitNode(hint, node, emitCallback);
|
||||
previousOnBeforeEmitNode(hint, node);
|
||||
}
|
||||
|
||||
function onAfterEmitNode(hint: EmitHint, node: Node): void {
|
||||
previousOnAfterEmitNode(hint, node);
|
||||
if (isSourceFile(node)) {
|
||||
currentSourceFile = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,10 +30,12 @@ namespace ts {
|
||||
const host = context.getEmitHost();
|
||||
const languageVersion = getEmitScriptTarget(compilerOptions);
|
||||
const moduleKind = getEmitModuleKind(compilerOptions);
|
||||
const previousOnBeforeEmitNode = context.onBeforeEmitNode;
|
||||
const previousOnAfterEmitNode = context.onAfterEmitNode;
|
||||
const previousOnSubstituteNode = context.onSubstituteNode;
|
||||
const previousOnEmitNode = context.onEmitNode;
|
||||
context.onBeforeEmitNode = onBeforeEmitNode;
|
||||
context.onAfterEmitNode = onAfterEmitNode;
|
||||
context.onSubstituteNode = onSubstituteNode;
|
||||
context.onEmitNode = onEmitNode;
|
||||
context.enableSubstitution(SyntaxKind.Identifier); // Substitutes expression identifiers with imported/exported symbols.
|
||||
context.enableSubstitution(SyntaxKind.BinaryExpression); // Substitutes assignments to exported symbols.
|
||||
context.enableSubstitution(SyntaxKind.PrefixUnaryExpression); // Substitutes updates to exported symbols.
|
||||
@@ -1455,23 +1457,25 @@ namespace ts {
|
||||
*
|
||||
* @param hint A hint as to the intended usage of the node.
|
||||
* @param node The node to emit.
|
||||
* @param emit A callback used to emit the node in the printer.
|
||||
*/
|
||||
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
|
||||
if (node.kind === SyntaxKind.SourceFile) {
|
||||
currentSourceFile = <SourceFile>node;
|
||||
function onBeforeEmitNode(hint: EmitHint, node: Node): void {
|
||||
if (isSourceFile(node)) {
|
||||
currentSourceFile = node;
|
||||
currentModuleInfo = moduleInfoMap[getOriginalNodeId(currentSourceFile)];
|
||||
noSubstitution = [];
|
||||
}
|
||||
|
||||
previousOnEmitNode(hint, node, emitCallback);
|
||||
previousOnBeforeEmitNode(hint, node);
|
||||
}
|
||||
|
||||
function onAfterEmitNode(hint: EmitHint, node: Node): void {
|
||||
previousOnAfterEmitNode(hint, node);
|
||||
|
||||
if (isSourceFile(node)) {
|
||||
currentSourceFile = undefined;
|
||||
currentModuleInfo = undefined;
|
||||
noSubstitution = undefined;
|
||||
}
|
||||
else {
|
||||
previousOnEmitNode(hint, node, emitCallback);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -19,10 +19,12 @@ namespace ts {
|
||||
const compilerOptions = context.getCompilerOptions();
|
||||
const resolver = context.getEmitResolver();
|
||||
const host = context.getEmitHost();
|
||||
const previousOnBeforeEmitNode = context.onBeforeEmitNode;
|
||||
const previousOnAfterEmitNode = context.onAfterEmitNode;
|
||||
const previousOnSubstituteNode = context.onSubstituteNode;
|
||||
const previousOnEmitNode = context.onEmitNode;
|
||||
context.onBeforeEmitNode = onBeforeEmitNode;
|
||||
context.onAfterEmitNode = onAfterEmitNode;
|
||||
context.onSubstituteNode = onSubstituteNode;
|
||||
context.onEmitNode = onEmitNode;
|
||||
context.enableSubstitution(SyntaxKind.Identifier); // Substitutes expression identifiers for imported symbols.
|
||||
context.enableSubstitution(SyntaxKind.ShorthandPropertyAssignment); // Substitutes expression identifiers for imported symbols
|
||||
context.enableSubstitution(SyntaxKind.BinaryExpression); // Substitutes assignments to exported symbols.
|
||||
@@ -1581,30 +1583,29 @@ namespace ts {
|
||||
*
|
||||
* @param hint A hint as to the intended usage of the node.
|
||||
* @param node The node to emit.
|
||||
* @param emitCallback A callback used to emit the node in the printer.
|
||||
*/
|
||||
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
|
||||
if (node.kind === SyntaxKind.SourceFile) {
|
||||
function onBeforeEmitNode(hint: EmitHint, node: Node): void {
|
||||
if (isSourceFile(node)) {
|
||||
const id = getOriginalNodeId(node);
|
||||
currentSourceFile = <SourceFile>node;
|
||||
currentSourceFile = node;
|
||||
moduleInfo = moduleInfoMap[id];
|
||||
exportFunction = exportFunctionsMap[id];
|
||||
noSubstitution = noSubstitutionMap[id];
|
||||
|
||||
if (noSubstitution) {
|
||||
delete noSubstitutionMap[id];
|
||||
}
|
||||
}
|
||||
previousOnBeforeEmitNode(hint, node);
|
||||
}
|
||||
|
||||
previousOnEmitNode(hint, node, emitCallback);
|
||||
|
||||
function onAfterEmitNode(hint: EmitHint, node: Node) {
|
||||
previousOnAfterEmitNode(hint, node);
|
||||
if (isSourceFile(node)) {
|
||||
currentSourceFile = undefined;
|
||||
moduleInfo = undefined;
|
||||
exportFunction = undefined;
|
||||
noSubstitution = undefined;
|
||||
}
|
||||
else {
|
||||
previousOnEmitNode(hint, node, emitCallback);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -50,11 +50,13 @@ namespace ts {
|
||||
const moduleKind = getEmitModuleKind(compilerOptions);
|
||||
|
||||
// Save the previous transformation hooks.
|
||||
const previousOnEmitNode = context.onEmitNode;
|
||||
const previousOnBeforeEmitNode = context.onBeforeEmitNode;
|
||||
const previousOnAfterEmitNode = context.onAfterEmitNode;
|
||||
const previousOnSubstituteNode = context.onSubstituteNode;
|
||||
|
||||
// Set new transformation hooks.
|
||||
context.onEmitNode = onEmitNode;
|
||||
context.onBeforeEmitNode = onBeforeEmitNode;
|
||||
context.onAfterEmitNode = onAfterEmitNode;
|
||||
context.onSubstituteNode = onSubstituteNode;
|
||||
|
||||
// Enable substitution for property/element access to emit const enum values.
|
||||
@@ -85,6 +87,7 @@ namespace ts {
|
||||
* just-in-time substitution while printing an expression identifier.
|
||||
*/
|
||||
let applicableSubstitutions: TypeScriptSubstitutionFlags;
|
||||
const applicableSubstitutionsStack: TypeScriptSubstitutionFlags[] = [];
|
||||
|
||||
/**
|
||||
* Tracks what computed name expressions originating from elided names must be inlined
|
||||
@@ -3389,28 +3392,39 @@ namespace ts {
|
||||
*
|
||||
* @param hint A hint as to the intended usage of the node.
|
||||
* @param node The node to emit.
|
||||
* @param emit A callback used to emit the node in the printer.
|
||||
*/
|
||||
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
|
||||
const savedApplicableSubstitutions = applicableSubstitutions;
|
||||
const savedCurrentSourceFile = currentSourceFile;
|
||||
|
||||
function onBeforeEmitNode(hint: EmitHint, node: Node) {
|
||||
if (isSourceFile(node)) {
|
||||
currentSourceFile = node;
|
||||
}
|
||||
|
||||
if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && isTransformedModuleDeclaration(node)) {
|
||||
applicableSubstitutions |= TypeScriptSubstitutionFlags.NamespaceExports;
|
||||
const requiresNamespaceExports = enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && isTransformedModuleDeclaration(node);
|
||||
const requiresNonQualifiedEnumMembers = enabledSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && isTransformedEnumDeclaration(node);
|
||||
if (requiresNamespaceExports || requiresNonQualifiedEnumMembers) {
|
||||
applicableSubstitutionsStack.push(applicableSubstitutions);
|
||||
if (requiresNamespaceExports) {
|
||||
applicableSubstitutions |= TypeScriptSubstitutionFlags.NamespaceExports;
|
||||
}
|
||||
|
||||
if (requiresNonQualifiedEnumMembers) {
|
||||
applicableSubstitutions |= TypeScriptSubstitutionFlags.NonQualifiedEnumMembers;
|
||||
}
|
||||
}
|
||||
|
||||
if (enabledSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && isTransformedEnumDeclaration(node)) {
|
||||
applicableSubstitutions |= TypeScriptSubstitutionFlags.NonQualifiedEnumMembers;
|
||||
previousOnBeforeEmitNode(hint, node);
|
||||
}
|
||||
|
||||
function onAfterEmitNode(hint: EmitHint, node: Node) {
|
||||
previousOnAfterEmitNode(hint, node);
|
||||
|
||||
if (isSourceFile(node)) {
|
||||
currentSourceFile = undefined;
|
||||
}
|
||||
|
||||
previousOnEmitNode(hint, node, emitCallback);
|
||||
|
||||
applicableSubstitutions = savedApplicableSubstitutions;
|
||||
currentSourceFile = savedCurrentSourceFile;
|
||||
if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && isTransformedModuleDeclaration(node) ||
|
||||
enabledSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && isTransformedEnumDeclaration(node)) {
|
||||
applicableSubstitutions = applicableSubstitutionsStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4817,6 +4817,8 @@ namespace ts {
|
||||
* before returning the `NodeTransformer` callback.
|
||||
*/
|
||||
onEmitNode: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
|
||||
/*@internal*/ onBeforeEmitNode?: (hint: EmitHint, node: Node) => void;
|
||||
/*@internal*/ onAfterEmitNode?: (hint: EmitHint, node: Node) => void;
|
||||
}
|
||||
|
||||
export interface TransformationResult<T extends Node> {
|
||||
@@ -4847,6 +4849,10 @@ namespace ts {
|
||||
* Clean up EmitNode entries on any parse-tree nodes.
|
||||
*/
|
||||
dispose(): void;
|
||||
|
||||
/*@internal*/ useEmitNodeWithNotification: boolean;
|
||||
/*@internal*/ beforeEmitNode?(hint: EmitHint, node: Node): void;
|
||||
/*@internal*/ afterEmitNode?(hint: EmitHint, node: Node): void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4942,6 +4948,8 @@ namespace ts {
|
||||
* ```
|
||||
*/
|
||||
substituteNode?(hint: EmitHint, node: Node): Node;
|
||||
/*@internal*/ onBeforeEmitNode?: (hint: EmitHint, node: Node) => void;
|
||||
/*@internal*/ onAfterEmitNode?: (hint: EmitHint, node: Node) => void;
|
||||
/*@internal*/ onEmitLeadingSourceMapOfNode?: (node: Node) => void;
|
||||
/*@internal*/ onEmitTrailingSourceMapOfNode?: (node: Node) => void;
|
||||
/*@internal*/ onEmitSourceMapOfToken?: (node: Node, token: SyntaxKind, writer: (s: string) => void, pos: number, emitCallback: (token: SyntaxKind, writer: (s: string) => void, pos: number) => number) => number;
|
||||
|
||||
Reference in New Issue
Block a user