Merge pull request #13940 from Microsoft/publicTransformers

Expose public API for transformation.
This commit is contained in:
Ron Buckton 2017-02-16 18:07:51 -08:00 committed by GitHub
commit ef25b25c1f
33 changed files with 1578 additions and 1047 deletions

View file

@ -41,7 +41,7 @@ const {runTestsInParallel} = mochaParallel;
Error.stackTraceLimit = 1000;
const cmdLineOptions = minimist(process.argv.slice(2), {
boolean: ["debug", "light", "colors", "lint", "soft"],
boolean: ["debug", "inspect", "light", "colors", "lint", "soft"],
string: ["browser", "tests", "host", "reporter", "stackTraceLimit"],
alias: {
d: "debug",
@ -57,6 +57,7 @@ const cmdLineOptions = minimist(process.argv.slice(2), {
soft: false,
colors: process.env.colors || process.env.color || true,
debug: process.env.debug || process.env.d,
inspect: process.env.inspect,
host: process.env.TYPESCRIPT_HOST || process.env.host || "node",
browser: process.env.browser || process.env.b || "IE",
tests: process.env.test || process.env.tests || process.env.t,
@ -597,6 +598,7 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done:
cleanTestDirs((err) => {
if (err) { console.error(err); failWithStatus(err, 1); }
const debug = cmdLineOptions["debug"];
const inspect = cmdLineOptions["inspect"];
const tests = cmdLineOptions["tests"];
const light = cmdLineOptions["light"];
const stackTraceLimit = cmdLineOptions["stackTraceLimit"];
@ -633,7 +635,10 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done:
// default timeout is 2sec which really should be enough, but maybe we just need a small amount longer
if (!runInParallel) {
const args = [];
if (debug) {
if (inspect) {
args.push("--inspect");
}
if (inspect || debug) {
args.push("--debug-brk");
}
args.push("-R", reporter);

View file

@ -131,6 +131,8 @@ var harnessSources = harnessCoreSources.concat([
"matchFiles.ts",
"initializeTSConfig.ts",
"printer.ts",
"transform.ts",
"customTransforms.ts",
].map(function (f) {
return path.join(unittestsDirectory, f);
})).concat([
@ -792,6 +794,7 @@ function runConsoleTests(defaultReporter, runInParallel) {
}
var debug = process.env.debug || process.env.d;
var inspect = process.env.inspect;
tests = process.env.test || process.env.tests || process.env.t;
var light = process.env.light || false;
var stackTraceLimit = process.env.stackTraceLimit;
@ -821,18 +824,39 @@ function runConsoleTests(defaultReporter, runInParallel) {
testTimeout = 800000;
}
colors = process.env.colors || process.env.color;
colors = colors ? ' --no-colors ' : ' --colors ';
reporter = process.env.reporter || process.env.r || defaultReporter;
var bail = (process.env.bail || process.env.b) ? "--bail" : "";
var colors = process.env.colors || process.env.color || true;
var reporter = process.env.reporter || process.env.r || defaultReporter;
var bail = process.env.bail || process.env.b;
var lintFlag = process.env.lint !== 'false';
// timeout normally isn't necessary but Travis-CI has been timing out on compiler baselines occasionally
// default timeout is 2sec which really should be enough, but maybe we just need a small amount longer
if (!runInParallel) {
var startTime = mark();
tests = tests ? ' -g "' + tests + '"' : '';
var cmd = "mocha" + (debug ? " --debug-brk" : "") + " -R " + reporter + tests + colors + bail + ' -t ' + testTimeout + ' ' + run;
var args = [];
if (inspect) {
args.push("--inspect");
}
if (inspect || debug) {
args.push("--debug-brk");
}
args.push("-R", reporter);
if (tests) {
args.push("-g", `"${tests}"`);
}
if (colors) {
args.push("--colors");
}
else {
args.push("--no-colors");
}
if (bail) {
args.push("--bail");
}
args.push("-t", testTimeout);
args.push(run);
var cmd = "mocha " + args.join(" ");
console.log(cmd);
var savedNodeEnv = process.env.NODE_ENV;
@ -853,7 +877,7 @@ function runConsoleTests(defaultReporter, runInParallel) {
var savedNodeEnv = process.env.NODE_ENV;
process.env.NODE_ENV = "development";
var startTime = mark();
runTestsInParallel(taskConfigsFolder, run, { testTimeout: testTimeout, noColors: colors === " --no-colors " }, function (err) {
runTestsInParallel(taskConfigsFolder, run, { testTimeout: testTimeout, noColors: !colors }, function (err) {
process.env.NODE_ENV = savedNodeEnv;
measure(startTime);
// last worker clean everything and runs linter in case if there were no errors

View file

@ -64,6 +64,11 @@ namespace ts {
undefinedSymbol.declarations = [];
const argumentsSymbol = createSymbol(SymbolFlags.Property, "arguments");
// for public members that accept a Node or one of its subtypes, we must guard against
// synthetic nodes created during transformations by calling `getParseTreeNode`.
// for most of these, we perform the guard only on `checker` to avoid any possible
// extra cost of calling `getParseTreeNode` when calling these functions from inside the
// checker.
const checker: TypeChecker = {
getNodeCount: () => sum(host.getSourceFiles(), "nodeCount"),
getIdentifierCount: () => sum(host.getSourceFiles(), "identifierCount"),
@ -74,8 +79,15 @@ namespace ts {
isUnknownSymbol: symbol => symbol === unknownSymbol,
getDiagnostics,
getGlobalDiagnostics,
getTypeOfSymbolAtLocation,
getSymbolsOfParameterPropertyDeclaration,
getTypeOfSymbolAtLocation: (symbol, location) => {
location = getParseTreeNode(location);
return location ? getTypeOfSymbolAtLocation(symbol, location) : unknownType;
},
getSymbolsOfParameterPropertyDeclaration: (parameter, parameterName) => {
parameter = getParseTreeNode(parameter, isParameter);
Debug.assert(parameter !== undefined, "Cannot get symbols of a synthetic parameter that cannot be resolved to a parse-tree node.");
return getSymbolsOfParameterPropertyDeclaration(parameter, parameterName);
},
getDeclaredTypeOfSymbol,
getPropertiesOfType,
getPropertyOfType,
@ -85,37 +97,88 @@ namespace ts {
getBaseTypes,
getBaseTypeOfLiteralType,
getWidenedType,
getTypeFromTypeNode,
getTypeFromTypeNode: node => {
node = getParseTreeNode(node, isTypeNode);
return node ? getTypeFromTypeNode(node) : unknownType;
},
getParameterType: getTypeAtPosition,
getReturnTypeOfSignature,
getNonNullableType,
getSymbolsInScope,
getSymbolAtLocation,
getShorthandAssignmentValueSymbol,
getExportSpecifierLocalTargetSymbol,
getTypeAtLocation: getTypeOfNode,
getPropertySymbolOfDestructuringAssignment,
signatureToString,
typeToString,
getSymbolsInScope: (location, meaning) => {
location = getParseTreeNode(location);
return location ? getSymbolsInScope(location, meaning) : [];
},
getSymbolAtLocation: node => {
node = getParseTreeNode(node);
return node ? getSymbolAtLocation(node) : undefined;
},
getShorthandAssignmentValueSymbol: node => {
node = getParseTreeNode(node);
return node ? getShorthandAssignmentValueSymbol(node) : undefined;
},
getExportSpecifierLocalTargetSymbol: node => {
node = getParseTreeNode(node, isExportSpecifier);
return node ? getExportSpecifierLocalTargetSymbol(node) : undefined;
},
getTypeAtLocation: node => {
node = getParseTreeNode(node);
return node ? getTypeOfNode(node) : unknownType;
},
getPropertySymbolOfDestructuringAssignment: location => {
location = getParseTreeNode(location, isIdentifier);
return location ? getPropertySymbolOfDestructuringAssignment(location) : undefined;
},
signatureToString: (signature, enclosingDeclaration?, flags?, kind?) => {
return signatureToString(signature, getParseTreeNode(enclosingDeclaration), flags, kind);
},
typeToString: (type, enclosingDeclaration?, flags?) => {
return typeToString(type, getParseTreeNode(enclosingDeclaration), flags);
},
getSymbolDisplayBuilder,
symbolToString,
symbolToString: (symbol, enclosingDeclaration?, meaning?) => {
return symbolToString(symbol, getParseTreeNode(enclosingDeclaration), meaning);
},
getAugmentedPropertiesOfType,
getRootSymbols,
getContextualType,
getContextualType: node => {
node = getParseTreeNode(node, isExpression)
return node ? getContextualType(node) : undefined;
},
getFullyQualifiedName,
getResolvedSignature,
getConstantValue,
isValidPropertyAccess,
getSignatureFromDeclaration,
isImplementationOfOverload,
getResolvedSignature: (node, candidatesOutArray?) => {
node = getParseTreeNode(node, isCallLikeExpression);
return node ? getResolvedSignature(node, candidatesOutArray) : undefined;
},
getConstantValue: node => {
node = getParseTreeNode(node, canHaveConstantValue);
return node ? getConstantValue(node) : undefined;
},
isValidPropertyAccess: (node, propertyName) => {
node = getParseTreeNode(node, isPropertyAccessOrQualifiedName);
return node ? isValidPropertyAccess(node, propertyName) : false;
},
getSignatureFromDeclaration: declaration => {
declaration = getParseTreeNode(declaration, isFunctionLike);
return declaration ? getSignatureFromDeclaration(declaration) : undefined;
},
isImplementationOfOverload: node => {
node = getParseTreeNode(node, isFunctionLike);
return node ? isImplementationOfOverload(node) : undefined;
},
getAliasedSymbol: resolveAlias,
getEmitResolver,
getExportsOfModule: getExportsOfModuleAsArray,
getExportsAndPropertiesOfModule,
getAmbientModules,
getAllAttributesTypeFromJsxOpeningLikeElement,
getAllAttributesTypeFromJsxOpeningLikeElement: node => {
node = getParseTreeNode(node, isJsxOpeningLikeElement);
return node ? getAllAttributesTypeFromJsxOpeningLikeElement(node) : undefined;
},
getJsxIntrinsicTagNames,
isOptionalParameter,
isOptionalParameter: node => {
node = getParseTreeNode(node, isParameter);
return node ? isOptionalParameter(node) : false;
},
tryGetMemberInModuleExports,
tryFindAmbientModuleWithoutAugmentations: moduleName => {
// we deliberately exclude augmentations
@ -20657,14 +20720,14 @@ namespace ts {
}
function getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[] {
const symbols = createMap<Symbol>();
let memberFlags: ModifierFlags = ModifierFlags.None;
if (isInsideWithStatementBody(location)) {
// We cannot answer semantic questions within a with block, do not proceed any further
return [];
}
const symbols = createMap<Symbol>();
let memberFlags: ModifierFlags = ModifierFlags.None;
populateSymbols();
return symbolsToArray(symbols);
@ -20931,6 +20994,7 @@ namespace ts {
if (node.kind === SyntaxKind.SourceFile) {
return isExternalModule(<SourceFile>node) ? getMergedSymbol(node.symbol) : undefined;
}
if (isInsideWithStatementBody(node)) {
// We cannot answer semantic questions within a with block, do not proceed any further
return undefined;
@ -21381,12 +21445,6 @@ namespace ts {
}
function isValueAliasDeclaration(node: Node): boolean {
node = getParseTreeNode(node);
if (node === undefined) {
// A synthesized node comes from an emit transformation and is always a value.
return true;
}
switch (node.kind) {
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.ImportClause:
@ -21433,12 +21491,6 @@ namespace ts {
}
function isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean {
node = getParseTreeNode(node);
// Purely synthesized nodes are always emitted.
if (node === undefined) {
return true;
}
if (isAliasSymbolDeclaration(node)) {
const symbol = getSymbolOfNode(node);
if (symbol && getSymbolLinks(symbol).referenced) {
@ -21481,8 +21533,7 @@ namespace ts {
}
function getNodeCheckFlags(node: Node): NodeCheckFlags {
node = getParseTreeNode(node);
return node ? getNodeLinks(node).flags : undefined;
return getNodeLinks(node).flags;
}
function getEnumMemberValue(node: EnumMember): number {
@ -21490,6 +21541,16 @@ namespace ts {
return getNodeLinks(node).enumMemberValue;
}
function canHaveConstantValue(node: Node): node is EnumMember | PropertyAccessExpression | ElementAccessExpression {
switch (node.kind) {
case SyntaxKind.EnumMember:
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
return true;
}
return false;
}
function getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number {
if (node.kind === SyntaxKind.EnumMember) {
return getEnumMemberValue(<EnumMember>node);
@ -21671,10 +21732,21 @@ namespace ts {
getReferencedImportDeclaration,
getReferencedDeclarationWithCollidingName,
isDeclarationWithCollidingName,
isValueAliasDeclaration,
isValueAliasDeclaration: node => {
node = getParseTreeNode(node);
// Synthesized nodes are always treated like values.
return node ? isValueAliasDeclaration(node) : true;
},
hasGlobalName,
isReferencedAliasDeclaration,
getNodeCheckFlags,
isReferencedAliasDeclaration: (node, checkChildren?) => {
node = getParseTreeNode(node);
// Synthesized nodes are always treated as referenced.
return node ? isReferencedAliasDeclaration(node, checkChildren) : true;
},
getNodeCheckFlags: node => {
node = getParseTreeNode(node);
return node ? getNodeCheckFlags(node) : undefined;
},
isTopLevelValueImportEqualsWithEntityName,
isDeclarationVisible,
isImplementationOfOverload,
@ -21685,7 +21757,10 @@ namespace ts {
writeBaseConstructorTypeOfClass,
isSymbolAccessible,
isEntityNameVisible,
getConstantValue,
getConstantValue: node => {
node = getParseTreeNode(node, canHaveConstantValue);
return node ? getConstantValue(node) : undefined;
},
collectLinkedAliases,
getReferencedValueDeclaration,
getTypeReferenceSerializationKind,

View file

@ -43,18 +43,14 @@ namespace ts {
}
if (node) {
const { pos, end } = getCommentRange(node);
const emitFlags = getEmitFlags(node);
hasWrittenComment = false;
const emitNode = node.emitNode;
const emitFlags = emitNode && emitNode.flags;
const { pos, end } = emitNode && emitNode.commentRange || node;
if ((pos < 0 && end < 0) || (pos === end)) {
// Both pos and end are synthesized, so just emit the node without comments.
if (emitFlags & EmitFlags.NoNestedComments) {
disabled = true;
emitCallback(hint, node);
disabled = false;
}
else {
emitCallback(hint, node);
}
emitNodeWithSynthesizedComments(hint, node, emitNode, emitFlags, emitCallback);
}
else {
if (extendedDiagnostics) {
@ -94,17 +90,10 @@ namespace ts {
performance.measure("commentTime", "preEmitNodeWithComment");
}
if (emitFlags & EmitFlags.NoNestedComments) {
disabled = true;
emitCallback(hint, node);
disabled = false;
}
else {
emitCallback(hint, node);
}
emitNodeWithSynthesizedComments(hint, node, emitNode, emitFlags, emitCallback);
if (extendedDiagnostics) {
performance.mark("beginEmitNodeWithComment");
performance.mark("postEmitNodeWithComment");
}
// Restore previous container state.
@ -119,12 +108,88 @@ namespace ts {
}
if (extendedDiagnostics) {
performance.measure("commentTime", "beginEmitNodeWithComment");
performance.measure("commentTime", "postEmitNodeWithComment");
}
}
}
}
function emitNodeWithSynthesizedComments(hint: EmitHint, node: Node, emitNode: EmitNode, emitFlags: EmitFlags, emitCallback: (hint: EmitHint, node: Node) => void) {
const leadingComments = emitNode && emitNode.leadingComments;
if (some(leadingComments)) {
if (extendedDiagnostics) {
performance.mark("preEmitNodeWithSynthesizedComments");
}
forEach(leadingComments, emitLeadingSynthesizedComment);
if (extendedDiagnostics) {
performance.measure("commentTime", "preEmitNodeWithSynthesizedComments");
}
}
emitNodeWithNestedComments(hint, node, emitFlags, emitCallback);
const trailingComments = emitNode && emitNode.trailingComments;
if (some(trailingComments)) {
if (extendedDiagnostics) {
performance.mark("postEmitNodeWithSynthesizedComments");
}
forEach(trailingComments, emitTrailingSynthesizedComment);
if (extendedDiagnostics) {
performance.measure("commentTime", "postEmitNodeWithSynthesizedComments");
}
}
}
function emitLeadingSynthesizedComment(comment: SynthesizedComment) {
if (comment.kind === SyntaxKind.SingleLineCommentTrivia) {
writer.writeLine();
}
writeSynthesizedComment(comment);
if (comment.hasTrailingNewLine || comment.kind === SyntaxKind.SingleLineCommentTrivia) {
writer.writeLine();
}
else {
writer.write(" ");
}
}
function emitTrailingSynthesizedComment(comment: SynthesizedComment) {
if (!writer.isAtStartOfLine()) {
writer.write(" ");
}
writeSynthesizedComment(comment);
if (comment.hasTrailingNewLine) {
writer.writeLine();
}
}
function writeSynthesizedComment(comment: SynthesizedComment) {
const text = formatSynthesizedComment(comment);
const lineMap = comment.kind === SyntaxKind.MultiLineCommentTrivia ? computeLineStarts(text) : undefined;
writeCommentRange(text, lineMap, writer, 0, text.length, newLine);
}
function formatSynthesizedComment(comment: SynthesizedComment) {
return comment.kind === SyntaxKind.MultiLineCommentTrivia
? `/*${comment.text}*/`
: `//${comment.text}`;
}
function emitNodeWithNestedComments(hint: EmitHint, node: Node, emitFlags: EmitFlags, emitCallback: (hint: EmitHint, node: Node) => void) {
if (emitFlags & EmitFlags.NoNestedComments) {
disabled = true;
emitCallback(hint, node);
disabled = false;
}
else {
emitCallback(hint, node);
}
}
function emitBodyWithDetachedComments(node: Node, detachedRange: TextRange, emitCallback: (node: Node) => void) {
if (extendedDiagnostics) {
performance.mark("preEmitBodyWithDetachedComments");

View file

@ -10,14 +10,13 @@ namespace ts {
/*@internal*/
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile, emitOnlyDtsFiles?: boolean): EmitResult {
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile, emitOnlyDtsFiles?: boolean, transformers?: TransformerFactory<SourceFile>[]): EmitResult {
const compilerOptions = host.getCompilerOptions();
const moduleKind = getEmitModuleKind(compilerOptions);
const sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? [] : undefined;
const emittedFilesList: string[] = compilerOptions.listEmittedFiles ? [] : undefined;
const emitterDiagnostics = createDiagnosticCollection();
const newLine = host.getNewLine();
const transformers = emitOnlyDtsFiles ? [] : getTransformers(compilerOptions);
const writer = createTextWriter(newLine);
const sourceMap = createSourceMapWriter(host, writer);
@ -29,7 +28,7 @@ namespace ts {
const sourceFiles = getSourceFilesToEmit(host, targetSourceFile);
// Transform the source files
const transform = transformFiles(resolver, host, sourceFiles, transformers);
const transform = transformNodes(resolver, host, compilerOptions, sourceFiles, transformers, /*allowDtsFiles*/ false);
// Create a printer to print the nodes
const printer = createPrinter(compilerOptions, {
@ -38,7 +37,7 @@ namespace ts {
// transform hooks
onEmitNode: transform.emitNodeWithNotification,
onSubstituteNode: transform.emitNodeWithSubstitution,
substituteNode: transform.substituteNode,
// sourcemap hooks
onEmitSourceMapOfNode: sourceMap.emitNodeWithSourceMap,
@ -56,9 +55,7 @@ namespace ts {
performance.measure("printTime", "beforePrint");
// Clean up emit nodes on parse tree
for (const sourceFile of sourceFiles) {
disposeEmitNodes(sourceFile);
}
transform.dispose();
return {
emitSkipped,
@ -201,7 +198,7 @@ namespace ts {
onEmitNode,
onEmitHelpers,
onSetSourceFile,
onSubstituteNode,
substituteNode,
} = handlers;
const newLine = getNewLineCharacter(printerOptions);
@ -331,8 +328,8 @@ namespace ts {
setWriter(/*output*/ undefined);
}
function emit(node: Node, hint = EmitHint.Unspecified) {
pipelineEmitWithNotification(hint, node);
function emit(node: Node) {
pipelineEmitWithNotification(EmitHint.Unspecified, node);
}
function emitIdentifierName(node: Identifier) {
@ -353,6 +350,7 @@ namespace ts {
}
function pipelineEmitWithComments(hint: EmitHint, node: Node) {
node = trySubstituteNode(hint, node);
if (emitNodeWithComments && hint !== EmitHint.SourceFile) {
emitNodeWithComments(hint, node, pipelineEmitWithSourceMap);
}
@ -363,16 +361,7 @@ namespace ts {
function pipelineEmitWithSourceMap(hint: EmitHint, node: Node) {
if (onEmitSourceMapOfNode && hint !== EmitHint.SourceFile && hint !== EmitHint.IdentifierName) {
onEmitSourceMapOfNode(hint, node, pipelineEmitWithSubstitution);
}
else {
pipelineEmitWithSubstitution(hint, node);
}
}
function pipelineEmitWithSubstitution(hint: EmitHint, node: Node) {
if (onSubstituteNode) {
onSubstituteNode(hint, node, pipelineEmitWithHint);
onEmitSourceMapOfNode(hint, node, pipelineEmitWithHint);
}
else {
pipelineEmitWithHint(hint, node);
@ -640,7 +629,7 @@ namespace ts {
// If the node is an expression, try to emit it as an expression with
// substitution.
if (isExpression(node)) {
return pipelineEmitWithSubstitution(EmitHint.Expression, node);
return pipelineEmitExpression(trySubstituteNode(EmitHint.Expression, node));
}
}
@ -737,6 +726,10 @@ namespace ts {
}
}
function trySubstituteNode(hint: EmitHint, node: Node) {
return node && substituteNode && substituteNode(hint, node) || node;
}
function emitBodyIndirect(node: Node, elements: NodeArray<Node>, emitCallback: (node: Node) => void): void {
if (emitBodyWithDetachedComments) {
emitBodyWithDetachedComments(node, elements, emitCallback);
@ -759,9 +752,6 @@ namespace ts {
// SyntaxKind.NumericLiteral
function emitNumericLiteral(node: NumericLiteral) {
emitLiteral(node);
if (node.trailingComment) {
write(` /*${node.trailingComment}*/`);
}
}
// SyntaxKind.StringLiteral

View file

@ -215,7 +215,7 @@ namespace ts {
// Signature elements
export function createParameter(decorators: Decorator[], modifiers: Modifier[], dotDotDotToken: DotDotDotToken, name: string | Identifier | BindingPattern, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression) {
export function createParameter(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression) {
const node = <ParameterDeclaration>createSynthesizedNode(SyntaxKind.Parameter);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
@ -227,7 +227,7 @@ namespace ts {
return node;
}
export function updateParameter(node: ParameterDeclaration, decorators: Decorator[], modifiers: Modifier[], dotDotDotToken: DotDotDotToken, name: BindingName, type: TypeNode, initializer: Expression) {
export function updateParameter(node: ParameterDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: BindingName, type: TypeNode | undefined, initializer: Expression | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.dotDotDotToken !== dotDotDotToken
@ -252,7 +252,7 @@ namespace ts {
// Type members
export function createProperty(decorators: Decorator[], modifiers: Modifier[], name: string | PropertyName, questionToken: QuestionToken, type: TypeNode, initializer: Expression) {
export function createProperty(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression) {
const node = <PropertyDeclaration>createSynthesizedNode(SyntaxKind.PropertyDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
@ -263,7 +263,7 @@ namespace ts {
return node;
}
export function updateProperty(node: PropertyDeclaration, decorators: Decorator[], modifiers: Modifier[], name: PropertyName, type: TypeNode, initializer: Expression) {
export function updateProperty(node: PropertyDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: PropertyName, type: TypeNode | undefined, initializer: Expression) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.name !== name
@ -273,7 +273,7 @@ namespace ts {
: node;
}
export function createMethod(decorators: Decorator[], modifiers: Modifier[], asteriskToken: AsteriskToken, name: string | PropertyName, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
export function createMethod(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | PropertyName, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
const node = <MethodDeclaration>createSynthesizedNode(SyntaxKind.MethodDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
@ -286,7 +286,7 @@ namespace ts {
return node;
}
export function updateMethod(node: MethodDeclaration, decorators: Decorator[], modifiers: Modifier[], asteriskToken: AsteriskToken, name: PropertyName, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
export function updateMethod(node: MethodDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: PropertyName, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.asteriskToken !== asteriskToken
@ -299,7 +299,7 @@ namespace ts {
: node;
}
export function createConstructor(decorators: Decorator[], modifiers: Modifier[], parameters: ParameterDeclaration[], body: Block) {
export function createConstructor(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, parameters: ParameterDeclaration[], body: Block | undefined) {
const node = <ConstructorDeclaration>createSynthesizedNode(SyntaxKind.Constructor);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
@ -310,7 +310,7 @@ namespace ts {
return node;
}
export function updateConstructor(node: ConstructorDeclaration, decorators: Decorator[], modifiers: Modifier[], parameters: ParameterDeclaration[], body: Block) {
export function updateConstructor(node: ConstructorDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, parameters: ParameterDeclaration[], body: Block | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.parameters !== parameters
@ -319,7 +319,7 @@ namespace ts {
: node;
}
export function createGetAccessor(decorators: Decorator[], modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
export function createGetAccessor(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: string | PropertyName, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
const node = <GetAccessorDeclaration>createSynthesizedNode(SyntaxKind.GetAccessor);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
@ -331,7 +331,7 @@ namespace ts {
return node;
}
export function updateGetAccessor(node: GetAccessorDeclaration, decorators: Decorator[], modifiers: Modifier[], name: PropertyName, parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
export function updateGetAccessor(node: GetAccessorDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: PropertyName, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.name !== name
@ -342,7 +342,7 @@ namespace ts {
: node;
}
export function createSetAccessor(decorators: Decorator[], modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], body: Block) {
export function createSetAccessor(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: string | PropertyName, parameters: ParameterDeclaration[], body: Block | undefined) {
const node = <SetAccessorDeclaration>createSynthesizedNode(SyntaxKind.SetAccessor);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
@ -353,7 +353,7 @@ namespace ts {
return node;
}
export function updateSetAccessor(node: SetAccessorDeclaration, decorators: Decorator[], modifiers: Modifier[], name: PropertyName, parameters: ParameterDeclaration[], body: Block) {
export function updateSetAccessor(node: SetAccessorDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: PropertyName, parameters: ParameterDeclaration[], body: Block | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.name !== name
@ -389,21 +389,21 @@ namespace ts {
: node;
}
export function createBindingElement(propertyName: string | PropertyName, dotDotDotToken: DotDotDotToken, name: string | BindingName, initializer?: Expression) {
export function createBindingElement(dotDotDotToken: DotDotDotToken | undefined, propertyName: string | PropertyName | undefined, name: string | BindingName, initializer?: Expression) {
const node = <BindingElement>createSynthesizedNode(SyntaxKind.BindingElement);
node.propertyName = asName(propertyName);
node.dotDotDotToken = dotDotDotToken;
node.propertyName = asName(propertyName);
node.name = asName(name);
node.initializer = initializer;
return node;
}
export function updateBindingElement(node: BindingElement, dotDotDotToken: DotDotDotToken, propertyName: PropertyName, name: BindingName, initializer: Expression) {
export function updateBindingElement(node: BindingElement, dotDotDotToken: DotDotDotToken | undefined, propertyName: PropertyName | undefined, name: BindingName, initializer: Expression | undefined) {
return node.propertyName !== propertyName
|| node.dotDotDotToken !== dotDotDotToken
|| node.name !== name
|| node.initializer !== initializer
? updateNode(createBindingElement(propertyName, dotDotDotToken, name, initializer), node)
? updateNode(createBindingElement(dotDotDotToken, propertyName, name, initializer), node)
: node;
}
@ -471,7 +471,7 @@ namespace ts {
: node;
}
export function createCall(expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[]) {
export function createCall(expression: Expression, typeArguments: TypeNode[] | undefined, argumentsArray: Expression[]) {
const node = <CallExpression>createSynthesizedNode(SyntaxKind.CallExpression);
node.expression = parenthesizeForAccess(expression);
node.typeArguments = asNodeArray(typeArguments);
@ -479,7 +479,7 @@ namespace ts {
return node;
}
export function updateCall(node: CallExpression, expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[]) {
export function updateCall(node: CallExpression, expression: Expression, typeArguments: TypeNode[] | undefined, argumentsArray: Expression[]) {
return expression !== node.expression
|| typeArguments !== node.typeArguments
|| argumentsArray !== node.arguments
@ -487,7 +487,7 @@ namespace ts {
: node;
}
export function createNew(expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[]) {
export function createNew(expression: Expression, typeArguments: TypeNode[] | undefined, argumentsArray: Expression[] | undefined) {
const node = <NewExpression>createSynthesizedNode(SyntaxKind.NewExpression);
node.expression = parenthesizeForNew(expression);
node.typeArguments = asNodeArray(typeArguments);
@ -495,7 +495,7 @@ namespace ts {
return node;
}
export function updateNew(node: NewExpression, expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[]) {
export function updateNew(node: NewExpression, expression: Expression, typeArguments: TypeNode[] | undefined, argumentsArray: Expression[] | undefined) {
return node.expression !== expression
|| node.typeArguments !== typeArguments
|| node.arguments !== argumentsArray
@ -543,7 +543,7 @@ namespace ts {
: node;
}
export function createFunctionExpression(modifiers: Modifier[], asteriskToken: AsteriskToken, name: string | Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
export function createFunctionExpression(modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block) {
const node = <FunctionExpression>createSynthesizedNode(SyntaxKind.FunctionExpression);
node.modifiers = asNodeArray(modifiers);
node.asteriskToken = asteriskToken;
@ -555,7 +555,7 @@ namespace ts {
return node;
}
export function updateFunctionExpression(node: FunctionExpression, modifiers: Modifier[], asteriskToken: AsteriskToken, name: Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
export function updateFunctionExpression(node: FunctionExpression, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block) {
return node.name !== name
|| node.modifiers !== modifiers
|| node.asteriskToken !== asteriskToken
@ -567,7 +567,7 @@ namespace ts {
: node;
}
export function createArrowFunction(modifiers: Modifier[], typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, equalsGreaterThanToken: EqualsGreaterThanToken, body: ConciseBody) {
export function createArrowFunction(modifiers: Modifier[] | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody) {
const node = <ArrowFunction>createSynthesizedNode(SyntaxKind.ArrowFunction);
node.modifiers = asNodeArray(modifiers);
node.typeParameters = asNodeArray(typeParameters);
@ -578,7 +578,7 @@ namespace ts {
return node;
}
export function updateArrowFunction(node: ArrowFunction, modifiers: Modifier[], typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: ConciseBody) {
export function updateArrowFunction(node: ArrowFunction, modifiers: Modifier[] | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: ConciseBody) {
return node.modifiers !== modifiers
|| node.typeParameters !== typeParameters
|| node.parameters !== parameters
@ -722,9 +722,10 @@ namespace ts {
return node;
}
export function updateYield(node: YieldExpression, expression: Expression) {
export function updateYield(node: YieldExpression, asteriskToken: AsteriskToken | undefined, expression: Expression) {
return node.expression !== expression
? updateNode(createYield(node.asteriskToken, expression), node)
|| node.asteriskToken !== asteriskToken
? updateNode(createYield(asteriskToken, expression), node)
: node;
}
@ -740,7 +741,7 @@ namespace ts {
: node;
}
export function createClassExpression(modifiers: Modifier[], name: string | Identifier, typeParameters: TypeParameterDeclaration[], heritageClauses: HeritageClause[], members: ClassElement[]) {
export function createClassExpression(modifiers: Modifier[] | undefined, name: string | Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, heritageClauses: HeritageClause[], members: ClassElement[]) {
const node = <ClassExpression>createSynthesizedNode(SyntaxKind.ClassExpression);
node.decorators = undefined;
node.modifiers = asNodeArray(modifiers);
@ -751,7 +752,7 @@ namespace ts {
return node;
}
export function updateClassExpression(node: ClassExpression, modifiers: Modifier[], name: Identifier, typeParameters: TypeParameterDeclaration[], heritageClauses: HeritageClause[], members: ClassElement[]) {
export function updateClassExpression(node: ClassExpression, modifiers: Modifier[] | undefined, name: Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, heritageClauses: HeritageClause[], members: ClassElement[]) {
return node.modifiers !== modifiers
|| node.name !== name
|| node.typeParameters !== typeParameters
@ -836,7 +837,7 @@ namespace ts {
: node;
}
export function createVariableStatement(modifiers: Modifier[], declarationList: VariableDeclarationList | VariableDeclaration[]): VariableStatement {
export function createVariableStatement(modifiers: Modifier[] | undefined, declarationList: VariableDeclarationList | VariableDeclaration[]) {
const node = <VariableStatement>createSynthesizedNode(SyntaxKind.VariableStatement);
node.decorators = undefined;
node.modifiers = asNodeArray(modifiers);
@ -844,14 +845,14 @@ namespace ts {
return node;
}
export function updateVariableStatement(node: VariableStatement, modifiers: Modifier[], declarationList: VariableDeclarationList): VariableStatement {
export function updateVariableStatement(node: VariableStatement, modifiers: Modifier[] | undefined, declarationList: VariableDeclarationList) {
return node.modifiers !== modifiers
|| node.declarationList !== declarationList
? updateNode(createVariableStatement(modifiers, declarationList), node)
: node;
}
export function createVariableDeclarationList(declarations: VariableDeclaration[], flags?: NodeFlags): VariableDeclarationList {
export function createVariableDeclarationList(declarations: VariableDeclaration[], flags?: NodeFlags) {
const node = <VariableDeclarationList>createSynthesizedNode(SyntaxKind.VariableDeclarationList);
node.flags |= flags;
node.declarations = createNodeArray(declarations);
@ -864,7 +865,7 @@ namespace ts {
: node;
}
export function createVariableDeclaration(name: string | BindingName, type?: TypeNode, initializer?: Expression): VariableDeclaration {
export function createVariableDeclaration(name: string | BindingName, type?: TypeNode, initializer?: Expression) {
const node = <VariableDeclaration>createSynthesizedNode(SyntaxKind.VariableDeclaration);
node.name = asName(name);
node.type = type;
@ -872,7 +873,7 @@ namespace ts {
return node;
}
export function updateVariableDeclaration(node: VariableDeclaration, name: BindingName, type: TypeNode, initializer: Expression) {
export function updateVariableDeclaration(node: VariableDeclaration, name: BindingName, type: TypeNode | undefined, initializer: Expression | undefined) {
return node.name !== name
|| node.type !== type
|| node.initializer !== initializer
@ -884,7 +885,7 @@ namespace ts {
return <EmptyStatement>createSynthesizedNode(SyntaxKind.EmptyStatement);
}
export function createStatement(expression: Expression): ExpressionStatement {
export function createStatement(expression: Expression) {
const node = <ExpressionStatement>createSynthesizedNode(SyntaxKind.ExpressionStatement);
node.expression = parenthesizeExpressionForExpressionStatement(expression);
return node;
@ -904,7 +905,7 @@ namespace ts {
return node;
}
export function updateIf(node: IfStatement, expression: Expression, thenStatement: Statement, elseStatement: Statement) {
export function updateIf(node: IfStatement, expression: Expression, thenStatement: Statement, elseStatement: Statement | undefined) {
return node.expression !== expression
|| node.thenStatement !== thenStatement
|| node.elseStatement !== elseStatement
@ -940,7 +941,7 @@ namespace ts {
: node;
}
export function createFor(initializer: ForInitializer, condition: Expression, incrementor: Expression, statement: Statement) {
export function createFor(initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement) {
const node = <ForStatement>createSynthesizedNode(SyntaxKind.ForStatement);
node.initializer = initializer;
node.condition = condition;
@ -949,7 +950,7 @@ namespace ts {
return node;
}
export function updateFor(node: ForStatement, initializer: ForInitializer, condition: Expression, incrementor: Expression, statement: Statement) {
export function updateFor(node: ForStatement, initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement) {
return node.initializer !== initializer
|| node.condition !== condition
|| node.incrementor !== incrementor
@ -998,7 +999,7 @@ namespace ts {
return node;
}
export function updateContinue(node: ContinueStatement, label: Identifier) {
export function updateContinue(node: ContinueStatement, label: Identifier | undefined) {
return node.label !== label
? updateNode(createContinue(label), node)
: node;
@ -1010,7 +1011,7 @@ namespace ts {
return node;
}
export function updateBreak(node: BreakStatement, label: Identifier) {
export function updateBreak(node: BreakStatement, label: Identifier | undefined) {
return node.label !== label
? updateNode(createBreak(label), node)
: node;
@ -1022,7 +1023,7 @@ namespace ts {
return node;
}
export function updateReturn(node: ReturnStatement, expression: Expression) {
export function updateReturn(node: ReturnStatement, expression: Expression | undefined) {
return node.expression !== expression
? updateNode(createReturn(expression), node)
: node;
@ -1082,7 +1083,7 @@ namespace ts {
: node;
}
export function createTry(tryBlock: Block, catchClause: CatchClause, finallyBlock: Block) {
export function createTry(tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined) {
const node = <TryStatement>createSynthesizedNode(SyntaxKind.TryStatement);
node.tryBlock = tryBlock;
node.catchClause = catchClause;
@ -1090,7 +1091,7 @@ namespace ts {
return node;
}
export function updateTry(node: TryStatement, tryBlock: Block, catchClause: CatchClause, finallyBlock: Block) {
export function updateTry(node: TryStatement, tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined) {
return node.tryBlock !== tryBlock
|| node.catchClause !== catchClause
|| node.finallyBlock !== finallyBlock
@ -1098,7 +1099,7 @@ namespace ts {
: node;
}
export function createFunctionDeclaration(decorators: Decorator[], modifiers: Modifier[], asteriskToken: AsteriskToken, name: string | Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
export function createFunctionDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
const node = <FunctionDeclaration>createSynthesizedNode(SyntaxKind.FunctionDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
@ -1111,7 +1112,7 @@ namespace ts {
return node;
}
export function updateFunctionDeclaration(node: FunctionDeclaration, decorators: Decorator[], modifiers: Modifier[], asteriskToken: AsteriskToken, name: Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) {
export function updateFunctionDeclaration(node: FunctionDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.asteriskToken !== asteriskToken
@ -1124,7 +1125,7 @@ namespace ts {
: node;
}
export function createClassDeclaration(decorators: Decorator[], modifiers: Modifier[], name: string | Identifier, typeParameters: TypeParameterDeclaration[], heritageClauses: HeritageClause[], members: ClassElement[]) {
export function createClassDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: string | Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, heritageClauses: HeritageClause[], members: ClassElement[]) {
const node = <ClassDeclaration>createSynthesizedNode(SyntaxKind.ClassDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
@ -1135,7 +1136,7 @@ namespace ts {
return node;
}
export function updateClassDeclaration(node: ClassDeclaration, decorators: Decorator[], modifiers: Modifier[], name: Identifier, typeParameters: TypeParameterDeclaration[], heritageClauses: HeritageClause[], members: ClassElement[]) {
export function updateClassDeclaration(node: ClassDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, heritageClauses: HeritageClause[], members: ClassElement[]) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.name !== name
@ -1146,7 +1147,7 @@ namespace ts {
: node;
}
export function createEnumDeclaration(decorators: Decorator[], modifiers: Modifier[], name: string | Identifier, members: EnumMember[]) {
export function createEnumDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: string | Identifier, members: EnumMember[]) {
const node = <EnumDeclaration>createSynthesizedNode(SyntaxKind.EnumDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
@ -1155,7 +1156,7 @@ namespace ts {
return node;
}
export function updateEnumDeclaration(node: EnumDeclaration, decorators: Decorator[], modifiers: Modifier[], name: Identifier, members: EnumMember[]) {
export function updateEnumDeclaration(node: EnumDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: Identifier, members: EnumMember[]) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.name !== name
@ -1164,7 +1165,7 @@ namespace ts {
: node;
}
export function createModuleDeclaration(decorators: Decorator[], modifiers: Modifier[], name: ModuleName, body: ModuleBody, flags?: NodeFlags) {
export function createModuleDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined, flags?: NodeFlags) {
const node = <ModuleDeclaration>createSynthesizedNode(SyntaxKind.ModuleDeclaration);
node.flags |= flags;
node.decorators = asNodeArray(decorators);
@ -1174,7 +1175,7 @@ namespace ts {
return node;
}
export function updateModuleDeclaration(node: ModuleDeclaration, decorators: Decorator[], modifiers: Modifier[], name: ModuleName, body: ModuleBody) {
export function updateModuleDeclaration(node: ModuleDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.name !== name
@ -1207,7 +1208,7 @@ namespace ts {
: node;
}
export function createImportEqualsDeclaration(decorators: Decorator[], modifiers: Modifier[], name: string | Identifier, moduleReference: ModuleReference) {
export function createImportEqualsDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: string | Identifier, moduleReference: ModuleReference) {
const node = <ImportEqualsDeclaration>createSynthesizedNode(SyntaxKind.ImportEqualsDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
@ -1216,7 +1217,7 @@ namespace ts {
return node;
}
export function updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: Decorator[], modifiers: Modifier[], name: Identifier, moduleReference: ModuleReference) {
export function updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, name: Identifier, moduleReference: ModuleReference) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.name !== name
@ -1225,7 +1226,7 @@ namespace ts {
: node;
}
export function createImportDeclaration(decorators: Decorator[], modifiers: Modifier[], importClause: ImportClause, moduleSpecifier?: Expression): ImportDeclaration {
export function createImportDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier?: Expression): ImportDeclaration {
const node = <ImportDeclaration>createSynthesizedNode(SyntaxKind.ImportDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
@ -1234,7 +1235,7 @@ namespace ts {
return node;
}
export function updateImportDeclaration(node: ImportDeclaration, decorators: Decorator[], modifiers: Modifier[], importClause: ImportClause, moduleSpecifier: Expression) {
export function updateImportDeclaration(node: ImportDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.importClause !== importClause || node.moduleSpecifier !== moduleSpecifier
@ -1280,21 +1281,21 @@ namespace ts {
: node;
}
export function createImportSpecifier(propertyName: Identifier, name: Identifier) {
export function createImportSpecifier(propertyName: Identifier | undefined, name: Identifier) {
const node = <ImportSpecifier>createSynthesizedNode(SyntaxKind.ImportSpecifier);
node.propertyName = propertyName;
node.name = name;
return node;
}
export function updateImportSpecifier(node: ImportSpecifier, propertyName: Identifier, name: Identifier) {
export function updateImportSpecifier(node: ImportSpecifier, propertyName: Identifier | undefined, name: Identifier) {
return node.propertyName !== propertyName
|| node.name !== name
? updateNode(createImportSpecifier(propertyName, name), node)
: node;
}
export function createExportAssignment(decorators: Decorator[], modifiers: Modifier[], isExportEquals: boolean, expression: Expression) {
export function createExportAssignment(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, isExportEquals: boolean, expression: Expression) {
const node = <ExportAssignment>createSynthesizedNode(SyntaxKind.ExportAssignment);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
@ -1303,7 +1304,7 @@ namespace ts {
return node;
}
export function updateExportAssignment(node: ExportAssignment, decorators: Decorator[], modifiers: Modifier[], expression: Expression) {
export function updateExportAssignment(node: ExportAssignment, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, expression: Expression) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.expression !== expression
@ -1311,7 +1312,7 @@ namespace ts {
: node;
}
export function createExportDeclaration(decorators: Decorator[], modifiers: Modifier[], exportClause: NamedExports, moduleSpecifier?: Expression) {
export function createExportDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, exportClause: NamedExports | undefined, moduleSpecifier?: Expression) {
const node = <ExportDeclaration>createSynthesizedNode(SyntaxKind.ExportDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
@ -1320,7 +1321,7 @@ namespace ts {
return node;
}
export function updateExportDeclaration(node: ExportDeclaration, decorators: Decorator[], modifiers: Modifier[], exportClause: NamedExports, moduleSpecifier: Expression) {
export function updateExportDeclaration(node: ExportDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, exportClause: NamedExports | undefined, moduleSpecifier: Expression | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.exportClause !== exportClause
@ -1341,16 +1342,17 @@ namespace ts {
: node;
}
export function createExportSpecifier(name: string | Identifier, propertyName?: string | Identifier) {
export function createExportSpecifier(propertyName: string | Identifier | undefined, name: string | Identifier) {
const node = <ExportSpecifier>createSynthesizedNode(SyntaxKind.ExportSpecifier);
node.name = asName(name);
node.propertyName = asName(propertyName);
node.name = asName(name);
return node;
}
export function updateExportSpecifier(node: ExportSpecifier, name: Identifier, propertyName: Identifier) {
return node.name !== name || node.propertyName !== propertyName
? updateNode(createExportSpecifier(name, propertyName), node)
export function updateExportSpecifier(node: ExportSpecifier, propertyName: Identifier | undefined, name: Identifier) {
return node.propertyName !== propertyName
|| node.name !== name
? updateNode(createExportSpecifier(propertyName, name), node)
: node;
}
@ -1465,16 +1467,16 @@ namespace ts {
: node;
}
export function createJsxExpression(expression: Expression, dotDotDotToken: DotDotDotToken) {
export function createJsxExpression(dotDotDotToken: DotDotDotToken | undefined, expression: Expression | undefined) {
const node = <JsxExpression>createSynthesizedNode(SyntaxKind.JsxExpression);
node.dotDotDotToken = dotDotDotToken;
node.expression = expression;
return node;
}
export function updateJsxExpression(node: JsxExpression, expression: Expression) {
export function updateJsxExpression(node: JsxExpression, expression: Expression | undefined) {
return node.expression !== expression
? updateNode(createJsxExpression(expression, node.dotDotDotToken), node)
? updateNode(createJsxExpression(node.dotDotDotToken, expression), node)
: node;
}
@ -1552,26 +1554,26 @@ namespace ts {
return node;
}
export function createShorthandPropertyAssignment(name: string | Identifier, objectAssignmentInitializer: Expression) {
export function createShorthandPropertyAssignment(name: string | Identifier, objectAssignmentInitializer?: Expression) {
const node = <ShorthandPropertyAssignment>createSynthesizedNode(SyntaxKind.ShorthandPropertyAssignment);
node.name = asName(name);
node.objectAssignmentInitializer = objectAssignmentInitializer !== undefined ? parenthesizeExpressionForList(objectAssignmentInitializer) : undefined;
return node;
}
export function createSpreadAssignment(expression: Expression) {
const node = <SpreadAssignment>createSynthesizedNode(SyntaxKind.SpreadAssignment);
node.expression = expression !== undefined ? parenthesizeExpressionForList(expression) : undefined;
return node;
}
export function updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression) {
export function updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression | undefined) {
if (node.name !== name || node.objectAssignmentInitializer !== objectAssignmentInitializer) {
return updateNode(createShorthandPropertyAssignment(name, objectAssignmentInitializer), node);
}
return node;
}
export function createSpreadAssignment(expression: Expression) {
const node = <SpreadAssignment>createSynthesizedNode(SyntaxKind.SpreadAssignment);
node.expression = expression !== undefined ? parenthesizeExpressionForList(expression) : undefined;
return node;
}
export function updateSpreadAssignment(node: SpreadAssignment, expression: Expression) {
if (node.expression !== expression) {
return updateNode(createSpreadAssignment(expression), node);
@ -1779,7 +1781,7 @@ namespace ts {
}
export function createExternalModuleExport(exportName: Identifier) {
return createExportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createNamedExports([createExportSpecifier(exportName)]));
return createExportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createNamedExports([createExportSpecifier(/*propertyName*/ undefined, exportName)]));
}
// Utilities
@ -1860,7 +1862,7 @@ namespace ts {
/**
* Gets flags that control emit behavior of a node.
*/
export function getEmitFlags(node: Node) {
export function getEmitFlags(node: Node): EmitFlags | undefined {
const emitNode = node.emitNode;
return emitNode && emitNode.flags;
}
@ -1884,7 +1886,7 @@ namespace ts {
/**
* Sets a custom text range to use when emitting source maps.
*/
export function setSourceMapRange<T extends Node>(node: T, range: TextRange) {
export function setSourceMapRange<T extends Node>(node: T, range: TextRange | undefined) {
getOrCreateEmitNode(node).sourceMapRange = range;
return node;
}
@ -1892,7 +1894,7 @@ namespace ts {
/**
* Gets the TextRange to use for source maps for a token of a node.
*/
export function getTokenSourceMapRange(node: Node, token: SyntaxKind) {
export function getTokenSourceMapRange(node: Node, token: SyntaxKind): TextRange | undefined {
const emitNode = node.emitNode;
const tokenSourceMapRanges = emitNode && emitNode.tokenSourceMapRanges;
return tokenSourceMapRanges && tokenSourceMapRanges[token];
@ -1901,7 +1903,7 @@ namespace ts {
/**
* Sets the TextRange to use for source maps for a token of a node.
*/
export function setTokenSourceMapRange<T extends Node>(node: T, token: SyntaxKind, range: TextRange) {
export function setTokenSourceMapRange<T extends Node>(node: T, token: SyntaxKind, range: TextRange | undefined) {
const emitNode = getOrCreateEmitNode(node);
const tokenSourceMapRanges = emitNode.tokenSourceMapRanges || (emitNode.tokenSourceMapRanges = []);
tokenSourceMapRanges[token] = range;
@ -1924,6 +1926,34 @@ namespace ts {
return node;
}
export function getSyntheticLeadingComments(node: Node): SynthesizedComment[] | undefined {
const emitNode = node.emitNode;
return emitNode && emitNode.leadingComments;
}
export function setSyntheticLeadingComments<T extends Node>(node: T, comments: SynthesizedComment[]) {
getOrCreateEmitNode(node).leadingComments = comments;
return node;
}
export function addSyntheticLeadingComment<T extends Node>(node: T, kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, text: string, hasTrailingNewLine?: boolean) {
return setSyntheticLeadingComments(node, append(getSyntheticLeadingComments(node), <SynthesizedComment>{ kind, pos: -1, end: -1, hasTrailingNewLine, text }));
}
export function getSyntheticTrailingComments(node: Node): SynthesizedComment[] | undefined {
const emitNode = node.emitNode;
return emitNode && emitNode.trailingComments;
}
export function setSyntheticTrailingComments<T extends Node>(node: T, comments: SynthesizedComment[]) {
getOrCreateEmitNode(node).trailingComments = comments;
return node;
}
export function addSyntheticTrailingComment<T extends Node>(node: T, kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, text: string, hasTrailingNewLine?: boolean) {
return setSyntheticTrailingComments(node, append(getSyntheticTrailingComments(node), <SynthesizedComment>{ kind, pos: -1, end: -1, hasTrailingNewLine, text }));
}
/**
* Gets the constant value to emit for an expression.
*/
@ -2024,7 +2054,7 @@ namespace ts {
return compareValues(x.priority, y.priority);
}
export function setOriginalNode<T extends Node>(node: T, original: Node): T {
export function setOriginalNode<T extends Node>(node: T, original: Node | undefined): T {
node.original = original;
if (original) {
const emitNode = original.emitNode;
@ -2036,6 +2066,8 @@ namespace ts {
function mergeEmitNode(sourceEmitNode: EmitNode, destEmitNode: EmitNode) {
const {
flags,
leadingComments,
trailingComments,
commentRange,
sourceMapRange,
tokenSourceMapRanges,
@ -2043,6 +2075,8 @@ namespace ts {
helpers
} = sourceEmitNode;
if (!destEmitNode) destEmitNode = {};
if (leadingComments) destEmitNode.leadingComments = addRange(leadingComments.slice(), destEmitNode.leadingComments);
if (trailingComments) destEmitNode.trailingComments = addRange(trailingComments.slice(), destEmitNode.trailingComments);
if (flags) destEmitNode.flags = flags;
if (commentRange) destEmitNode.commentRange = commentRange;
if (sourceMapRange) destEmitNode.sourceMapRange = sourceMapRange;

View file

@ -5832,7 +5832,11 @@ namespace ts {
}
}
const range = { pos: triviaScanner.getTokenPos(), end: triviaScanner.getTextPos(), kind: triviaScanner.getToken() };
const range = {
kind: <SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia>triviaScanner.getToken(),
pos: triviaScanner.getTokenPos(),
end: triviaScanner.getTextPos(),
};
const comment = sourceText.substring(range.pos, range.end);
const referencePathMatchResult = getFileReferenceFromReferencePath(comment, range);

View file

@ -754,15 +754,15 @@ namespace ts {
return noDiagnosticsTypeChecker || (noDiagnosticsTypeChecker = createTypeChecker(program, /*produceDiagnostics:*/ false));
}
function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean): EmitResult {
return runWithCancellationToken(() => emitWorker(program, sourceFile, writeFileCallback, cancellationToken, emitOnlyDtsFiles));
function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, transformers?: CustomTransformers): EmitResult {
return runWithCancellationToken(() => emitWorker(program, sourceFile, writeFileCallback, cancellationToken, emitOnlyDtsFiles, transformers));
}
function isEmitBlocked(emitFileName: string): boolean {
return hasEmitBlockingDiagnostics.contains(toPath(emitFileName, currentDirectory, getCanonicalFileName));
}
function emitWorker(program: Program, sourceFile: SourceFile, writeFileCallback: WriteFileCallback, cancellationToken: CancellationToken, emitOnlyDtsFiles?: boolean): EmitResult {
function emitWorker(program: Program, sourceFile: SourceFile, writeFileCallback: WriteFileCallback, cancellationToken: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult {
let declarationDiagnostics: Diagnostic[] = [];
if (options.noEmit) {
@ -804,11 +804,13 @@ namespace ts {
performance.mark("beforeEmit");
const transformers = emitOnlyDtsFiles ? [] : getTransformers(options, customTransformers);
const emitResult = emitFiles(
emitResolver,
getEmitHost(writeFileCallback),
sourceFile,
emitOnlyDtsFiles);
emitOnlyDtsFiles,
transformers);
performance.mark("afterEmit");
performance.measure("Emit", "beforeEmit", "afterEmit");

View file

@ -608,10 +608,10 @@ namespace ts {
* @returns If "reduce" is true, the accumulated value. If "reduce" is false, the first truthy
* return value of the callback.
*/
function iterateCommentRanges<T, U>(reduce: boolean, text: string, pos: number, trailing: boolean, cb: (pos: number, end: number, kind: SyntaxKind, hasTrailingNewLine: boolean, state: T, memo: U) => U, state: T, initial?: U): U {
function iterateCommentRanges<T, U>(reduce: boolean, text: string, pos: number, trailing: boolean, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U) => U, state: T, initial?: U): U {
let pendingPos: number;
let pendingEnd: number;
let pendingKind: SyntaxKind;
let pendingKind: CommentKind;
let pendingHasTrailingNewLine: boolean;
let hasPendingCommentRange = false;
let collecting = trailing || pos === 0;
@ -707,28 +707,28 @@ namespace ts {
return accumulator;
}
export function forEachLeadingCommentRange<T, U>(text: string, pos: number, cb: (pos: number, end: number, kind: SyntaxKind, hasTrailingNewLine: boolean, state: T) => U, state?: T) {
export function forEachLeadingCommentRange<T, U>(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state?: T) {
return iterateCommentRanges(/*reduce*/ false, text, pos, /*trailing*/ false, cb, state);
}
export function forEachTrailingCommentRange<T, U>(text: string, pos: number, cb: (pos: number, end: number, kind: SyntaxKind, hasTrailingNewLine: boolean, state: T) => U, state?: T) {
export function forEachTrailingCommentRange<T, U>(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state?: T) {
return iterateCommentRanges(/*reduce*/ false, text, pos, /*trailing*/ true, cb, state);
}
export function reduceEachLeadingCommentRange<T, U>(text: string, pos: number, cb: (pos: number, end: number, kind: SyntaxKind, hasTrailingNewLine: boolean, state: T, memo: U) => U, state: T, initial: U) {
export function reduceEachLeadingCommentRange<T, U>(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U) => U, state: T, initial: U) {
return iterateCommentRanges(/*reduce*/ true, text, pos, /*trailing*/ false, cb, state, initial);
}
export function reduceEachTrailingCommentRange<T, U>(text: string, pos: number, cb: (pos: number, end: number, kind: SyntaxKind, hasTrailingNewLine: boolean, state: T, memo: U) => U, state: T, initial: U) {
export function reduceEachTrailingCommentRange<T, U>(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U) => U, state: T, initial: U) {
return iterateCommentRanges(/*reduce*/ true, text, pos, /*trailing*/ true, cb, state, initial);
}
function appendCommentRange(pos: number, end: number, kind: SyntaxKind, hasTrailingNewLine: boolean, _state: any, comments: CommentRange[]) {
function appendCommentRange(pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, _state: any, comments: CommentRange[]) {
if (!comments) {
comments = [];
}
comments.push({ pos, end, hasTrailingNewLine, kind });
comments.push({ kind, pos, end, hasTrailingNewLine });
return comments;
}

View file

@ -13,7 +13,7 @@
/* @internal */
namespace ts {
function getModuleTransformer(moduleKind: ModuleKind): Transformer {
function getModuleTransformer(moduleKind: ModuleKind): TransformerFactory<SourceFile> {
switch (moduleKind) {
case ModuleKind.ES2015:
return transformES2015Module;
@ -24,16 +24,25 @@ namespace ts {
}
}
const enum TransformationState {
Uninitialized,
Initialized,
Completed,
Disposed
}
const enum SyntaxKindFeatureFlags {
Substitution = 1 << 0,
EmitNotifications = 1 << 1,
}
export function getTransformers(compilerOptions: CompilerOptions) {
export function getTransformers(compilerOptions: CompilerOptions, customTransformers?: CustomTransformers) {
const jsx = compilerOptions.jsx;
const languageVersion = getEmitScriptTarget(compilerOptions);
const moduleKind = getEmitModuleKind(compilerOptions);
const transformers: Transformer[] = [];
const transformers: TransformerFactory<SourceFile>[] = [];
addRange(transformers, customTransformers && customTransformers.before);
transformers.push(transformTypeScript);
@ -66,6 +75,8 @@ namespace ts {
transformers.push(transformES5);
}
addRange(transformers, customTransformers && customTransformers.after);
return transformers;
}
@ -73,28 +84,29 @@ namespace ts {
* Transforms an array of SourceFiles by passing them through each transformer.
*
* @param resolver The emit resolver provided by the checker.
* @param host The emit host.
* @param sourceFiles An array of source files
* @param transforms An array of Transformers.
* @param host The emit host object used to interact with the file system.
* @param options Compiler options to surface in the `TransformationContext`.
* @param nodes An array of nodes to transform.
* @param transforms An array of `TransformerFactory` callbacks.
* @param allowDtsFiles A value indicating whether to allow the transformation of .d.ts files.
*/
export function transformFiles(resolver: EmitResolver, host: EmitHost, sourceFiles: SourceFile[], transformers: Transformer[]): TransformationResult {
export function transformNodes<T extends Node>(resolver: EmitResolver, host: EmitHost, options: CompilerOptions, nodes: T[], transformers: TransformerFactory<T>[], allowDtsFiles: boolean): TransformationResult<T> {
const enabledSyntaxKindFeatures = new Array<SyntaxKindFeatureFlags>(SyntaxKind.Count);
let lexicalEnvironmentDisabled = false;
let lexicalEnvironmentVariableDeclarations: VariableDeclaration[];
let lexicalEnvironmentFunctionDeclarations: FunctionDeclaration[];
let lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = [];
let lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = [];
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 state = TransformationState.Uninitialized;
// The transformation context is provided to each transformer as part of transformer
// initialization.
const context: TransformationContext = {
getCompilerOptions: () => host.getCompilerOptions(),
getCompilerOptions: () => options,
getEmitResolver: () => resolver,
getEmitHost: () => host,
startLexicalEnvironment,
@ -105,51 +117,62 @@ namespace ts {
hoistFunctionDeclaration,
requestEmitHelper,
readEmitHelpers,
onSubstituteNode: (_, node) => node,
enableSubstitution,
isSubstitutionEnabled,
onEmitNode: (hint, node, callback) => callback(hint, node),
enableEmitNotification,
isEmitNotificationEnabled
isSubstitutionEnabled,
isEmitNotificationEnabled,
get onSubstituteNode() { return onSubstituteNode },
set onSubstituteNode(value) {
Debug.assert(state < TransformationState.Initialized, "Cannot modify transformation hooks after initialization has completed.");
Debug.assert(value !== undefined, "Value must not be 'undefined'");
onSubstituteNode = value;
},
get onEmitNode() { return onEmitNode },
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;
}
};
// Ensure the parse tree is clean before applying transformations
for (const node of nodes) {
disposeEmitNodes(getSourceFileOfNode(getParseTreeNode(node)));
}
performance.mark("beforeTransform");
// Chain together and initialize each transformer.
const transformation = chain(...transformers)(context);
// Transform each source file.
const transformed = map(sourceFiles, transformSourceFile);
// prevent modification of transformation hooks.
state = TransformationState.Initialized;
// Disable modification of the lexical environment.
lexicalEnvironmentDisabled = true;
// Transform each node.
const transformed = map(nodes, allowDtsFiles ? transformation : transformRoot);
// prevent modification of the lexical environment.
state = TransformationState.Completed;
performance.mark("afterTransform");
performance.measure("transformTime", "beforeTransform", "afterTransform");
return {
transformed,
emitNodeWithSubstitution,
emitNodeWithNotification
substituteNode,
emitNodeWithNotification,
dispose
};
/**
* Transforms a source file.
*
* @param sourceFile The source file to transform.
*/
function transformSourceFile(sourceFile: SourceFile) {
if (isDeclarationFile(sourceFile)) {
return sourceFile;
}
return transformation(sourceFile);
function transformRoot(node: T) {
return node && (!isSourceFile(node) || !isDeclarationFile(node)) ? transformation(node) : node;
}
/**
* Enables expression substitutions in the pretty printer for the provided SyntaxKind.
*/
function enableSubstitution(kind: SyntaxKind) {
Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed.");
enabledSyntaxKindFeatures[kind] |= SyntaxKindFeatureFlags.Substitution;
}
@ -168,19 +191,16 @@ namespace ts {
* @param node The node to emit.
* @param emitCallback The callback used to emit the node or its substitute.
*/
function emitNodeWithSubstitution(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
if (node) {
if (isSubstitutionEnabled(node)) {
node = context.onSubstituteNode(hint, node) || node;
}
emitCallback(hint, node);
}
function substituteNode(hint: EmitHint, node: Node) {
Debug.assert(state < TransformationState.Disposed, "Cannot substitute a node after the result is disposed.");
return node && isSubstitutionEnabled(node) && onSubstituteNode(hint, node) || node;
}
/**
* Enables before/after emit notifications in the pretty printer for the provided SyntaxKind.
*/
function enableEmitNotification(kind: SyntaxKind) {
Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed.");
enabledSyntaxKindFeatures[kind] |= SyntaxKindFeatureFlags.EmitNotifications;
}
@ -201,9 +221,10 @@ namespace ts {
* @param emitCallback The callback used to emit the node.
*/
function emitNodeWithNotification(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
Debug.assert(state < TransformationState.Disposed, "Cannot invoke TransformationResult callbacks after the result is disposed.");
if (node) {
if (isEmitNotificationEnabled(node)) {
context.onEmitNode(hint, node, emitCallback);
onEmitNode(hint, node, emitCallback);
}
else {
emitCallback(hint, node);
@ -215,7 +236,8 @@ namespace ts {
* Records a hoisted variable declaration for the provided name within a lexical environment.
*/
function hoistVariableDeclaration(name: Identifier): void {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot modify the lexical environment during the print phase.");
Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization.");
Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed.");
const decl = createVariableDeclaration(name);
if (!lexicalEnvironmentVariableDeclarations) {
lexicalEnvironmentVariableDeclarations = [decl];
@ -229,7 +251,8 @@ namespace ts {
* Records a hoisted function declaration within a lexical environment.
*/
function hoistFunctionDeclaration(func: FunctionDeclaration): void {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot modify the lexical environment during the print phase.");
Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization.");
Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed.");
if (!lexicalEnvironmentFunctionDeclarations) {
lexicalEnvironmentFunctionDeclarations = [func];
}
@ -243,7 +266,8 @@ namespace ts {
* are pushed onto a stack, and the related storage variables are reset.
*/
function startLexicalEnvironment(): void {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot start a lexical environment during the print phase.");
Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization.");
Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed.");
Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended.");
// Save the current lexical environment. Rather than resizing the array we adjust the
@ -259,14 +283,16 @@ namespace ts {
/** Suspends the current lexical environment, usually after visiting a parameter list. */
function suspendLexicalEnvironment(): void {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot suspend a lexical environment during the print phase.");
Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization.");
Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed.");
Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is already suspended.");
lexicalEnvironmentSuspended = true;
}
/** Resumes a suspended lexical environment, usually before visiting a function body. */
function resumeLexicalEnvironment(): void {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot resume a lexical environment during the print phase.");
Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization.");
Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed.");
Debug.assert(lexicalEnvironmentSuspended, "Lexical environment is not suspended.");
lexicalEnvironmentSuspended = false;
}
@ -276,7 +302,8 @@ namespace ts {
* any hoisted declarations added in this environment are returned.
*/
function endLexicalEnvironment(): Statement[] {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot end a lexical environment during the print phase.");
Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization.");
Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed.");
Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended.");
let statements: Statement[];
@ -312,16 +339,39 @@ namespace ts {
}
function requestEmitHelper(helper: EmitHelper): void {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot modify the lexical environment during the print phase.");
Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the transformation context during initialization.");
Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed.");
Debug.assert(!helper.scoped, "Cannot request a scoped emit helper.");
emitHelpers = append(emitHelpers, helper);
}
function readEmitHelpers(): EmitHelper[] | undefined {
Debug.assert(!lexicalEnvironmentDisabled, "Cannot modify the lexical environment during the print phase.");
Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the transformation context during initialization.");
Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed.");
const helpers = emitHelpers;
emitHelpers = undefined;
return helpers;
}
function dispose() {
if (state < TransformationState.Disposed) {
// Clean up emit nodes on parse tree
for (const node of nodes) {
disposeEmitNodes(getSourceFileOfNode(getParseTreeNode(node)));
}
// Release references to external entries for GC purposes.
lexicalEnvironmentVariableDeclarations = undefined;
lexicalEnvironmentVariableDeclarationsStack = undefined;
lexicalEnvironmentFunctionDeclarations = undefined;
lexicalEnvironmentFunctionDeclarationsStack = undefined;
onSubstituteNode = undefined;
onEmitNode = undefined;
emitHelpers = undefined;
// Prevent further use of the transformation result.
state = TransformationState.Disposed;
}
}
}
}

View file

@ -467,7 +467,7 @@ namespace ts {
}
function makeBindingElement(name: Identifier) {
return createBindingElement(/*propertyName*/ undefined, /*dotDotDotToken*/ undefined, name);
return createBindingElement(/*dotDotDotToken*/ undefined, /*propertyName*/ undefined, name);
}
function makeAssignmentElement(name: Identifier) {

View file

@ -2321,7 +2321,7 @@ namespace ts {
addRange(statements, convertedLoopBodyStatements);
}
else {
const statement = visitNode(node.statement, visitor, isStatement, /*optional*/ false, liftToBlock);
const statement = visitNode(node.statement, visitor, isStatement, liftToBlock);
if (isBlock(statement)) {
addRange(statements, statement.statements);
bodyLocation = statement;
@ -2679,7 +2679,7 @@ namespace ts {
}
startLexicalEnvironment();
let loopBody = visitNode(node.statement, visitor, isStatement, /*optional*/ false, liftToBlock);
let loopBody = visitNode(node.statement, visitor, isStatement, liftToBlock);
const lexicalEnvironment = endLexicalEnvironment();
const currentState = convertedLoopState;
@ -3674,7 +3674,7 @@ namespace ts {
if (enabledSubstitutions & ES2015SubstitutionFlags.BlockScopedBindings) {
const original = getParseTreeNode(node, isIdentifier);
if (original && isNameOfDeclarationWithCollidingName(original)) {
return getGeneratedNameForNode(original);
return setTextRange(getGeneratedNameForNode(original), node);
}
}
@ -3727,7 +3727,7 @@ namespace ts {
if (enabledSubstitutions & ES2015SubstitutionFlags.BlockScopedBindings) {
const declaration = resolver.getReferencedDeclarationWithCollidingName(node);
if (declaration) {
return getGeneratedNameForNode(declaration.name);
return setTextRange(getGeneratedNameForNode(declaration.name), node);
}
}

View file

@ -128,6 +128,7 @@ namespace ts {
const expression = visitNode(node.expression, visitor, isExpression);
return updateYield(
node,
node.asteriskToken,
node.asteriskToken
? createAsyncDelegatorHelper(context, expression, expression)
: createArrayLiteral(

View file

@ -1230,7 +1230,7 @@ namespace ts {
case SyntaxKind.TryStatement:
return transformAndEmitTryStatement(<TryStatement>node);
default:
return emitStatement(visitNode(node, visitor, isStatement, /*optional*/ true));
return emitStatement(visitNode(node, visitor, isStatement));
}
}
@ -1488,9 +1488,9 @@ namespace ts {
variables.length > 0
? inlineExpressions(map(variables, transformInitializedVariable))
: undefined,
visitNode(node.condition, visitor, isExpression, /*optional*/ true),
visitNode(node.incrementor, visitor, isExpression, /*optional*/ true),
visitNode(node.statement, visitor, isStatement, /*optional*/ false, liftToBlock)
visitNode(node.condition, visitor, isExpression),
visitNode(node.incrementor, visitor, isExpression),
visitNode(node.statement, visitor, isStatement, liftToBlock)
);
}
else {
@ -1612,7 +1612,7 @@ namespace ts {
node = updateForIn(node,
<Identifier>initializer.declarations[0].name,
visitNode(node.expression, visitor, isExpression),
visitNode(node.statement, visitor, isStatement, /*optional*/ false, liftToBlock)
visitNode(node.statement, visitor, isStatement, liftToBlock)
);
}
else {
@ -1662,14 +1662,14 @@ namespace ts {
function transformAndEmitReturnStatement(node: ReturnStatement): void {
emitReturn(
visitNode(node.expression, visitor, isExpression, /*optional*/ true),
visitNode(node.expression, visitor, isExpression),
/*location*/ node
);
}
function visitReturnStatement(node: ReturnStatement) {
return createInlineReturn(
visitNode(node.expression, visitor, isExpression, /*optional*/ true),
visitNode(node.expression, visitor, isExpression),
/*location*/ node
);
}
@ -2422,7 +2422,7 @@ namespace ts {
*/
function createInstruction(instruction: Instruction): NumericLiteral {
const literal = createLiteral(instruction);
literal.trailingComment = getInstructionName(instruction);
addSyntheticTrailingComment(literal, SyntaxKind.MultiLineCommentTrivia, getInstructionName(instruction));
return literal;
}

View file

@ -89,7 +89,7 @@ namespace ts {
append(statements, createUnderscoreUnderscoreESModule());
}
append(statements, visitNode(currentModuleInfo.externalHelpersImportDeclaration, sourceElementVisitor, isStatement, /*optional*/ true));
append(statements, visitNode(currentModuleInfo.externalHelpersImportDeclaration, sourceElementVisitor, isStatement));
addRange(statements, visitNodes(node.statements, sourceElementVisitor, isStatement, statementOffset));
addExportEqualsIfNeeded(statements, /*emitAsReturn*/ false);
addRange(statements, endLexicalEnvironment());
@ -383,7 +383,7 @@ namespace ts {
}
// Visit each statement of the module body.
append(statements, visitNode(currentModuleInfo.externalHelpersImportDeclaration, sourceElementVisitor, isStatement, /*optional*/ true));
append(statements, visitNode(currentModuleInfo.externalHelpersImportDeclaration, sourceElementVisitor, isStatement));
addRange(statements, visitNodes(node.statements, sourceElementVisitor, isStatement, statementOffset));
// Append the 'export =' statement if provided.

View file

@ -245,7 +245,7 @@ namespace ts {
);
// Visit the synthetic external helpers import declaration if present
visitNode(moduleInfo.externalHelpersImportDeclaration, sourceElementVisitor, isStatement, /*optional*/ true);
visitNode(moduleInfo.externalHelpersImportDeclaration, sourceElementVisitor, isStatement);
// Visit the statements of the source file, emitting any transformations into
// the `executeStatements` array. We do this *before* we fill the `setters` array
@ -1219,8 +1219,8 @@ namespace ts {
node = updateFor(
node,
visitForInitializer(node.initializer),
visitNode(node.condition, destructuringVisitor, isExpression, /*optional*/ true),
visitNode(node.incrementor, destructuringVisitor, isExpression, /*optional*/ true),
visitNode(node.condition, destructuringVisitor, isExpression),
visitNode(node.incrementor, destructuringVisitor, isExpression),
visitNode(node.statement, nestedElementVisitor, isStatement)
);
@ -1241,7 +1241,7 @@ namespace ts {
node,
visitForInitializer(node.initializer),
visitNode(node.expression, destructuringVisitor, isExpression),
visitNode(node.statement, nestedElementVisitor, isStatement, /*optional*/ false, liftToBlock)
visitNode(node.statement, nestedElementVisitor, isStatement, liftToBlock)
);
enclosingBlockScopedContainer = savedEnclosingBlockScopedContainer;
@ -1262,7 +1262,7 @@ namespace ts {
node.awaitModifier,
visitForInitializer(node.initializer),
visitNode(node.expression, destructuringVisitor, isExpression),
visitNode(node.statement, nestedElementVisitor, isStatement, /*optional*/ false, liftToBlock)
visitNode(node.statement, nestedElementVisitor, isStatement, liftToBlock)
);
enclosingBlockScopedContainer = savedEnclosingBlockScopedContainer;
@ -1307,7 +1307,7 @@ namespace ts {
function visitDoStatement(node: DoStatement): VisitResult<Statement> {
return updateDo(
node,
visitNode(node.statement, nestedElementVisitor, isStatement, /*optional*/ false, liftToBlock),
visitNode(node.statement, nestedElementVisitor, isStatement, liftToBlock),
visitNode(node.expression, destructuringVisitor, isExpression)
);
}
@ -1321,7 +1321,7 @@ namespace ts {
return updateWhile(
node,
visitNode(node.expression, destructuringVisitor, isExpression),
visitNode(node.statement, nestedElementVisitor, isStatement, /*optional*/ false, liftToBlock)
visitNode(node.statement, nestedElementVisitor, isStatement, liftToBlock)
);
}
@ -1334,7 +1334,7 @@ namespace ts {
return updateLabel(
node,
node.label,
visitNode(node.statement, nestedElementVisitor, isStatement, /*optional*/ false, liftToBlock)
visitNode(node.statement, nestedElementVisitor, isStatement, liftToBlock)
);
}
@ -1347,7 +1347,7 @@ namespace ts {
return updateWith(
node,
visitNode(node.expression, destructuringVisitor, isExpression),
visitNode(node.statement, nestedElementVisitor, isStatement, /*optional*/ false, liftToBlock)
visitNode(node.statement, nestedElementVisitor, isStatement, liftToBlock)
);
}

View file

@ -2842,7 +2842,7 @@ namespace ts {
}
// Elide the declaration if the import clause was elided.
const importClause = visitNode(node.importClause, visitImportClause, isImportClause, /*optional*/ true);
const importClause = visitNode(node.importClause, visitImportClause, isImportClause);
return importClause
? updateImportDeclaration(
node,
@ -2861,7 +2861,7 @@ namespace ts {
function visitImportClause(node: ImportClause): VisitResult<ImportClause> {
// Elide the import clause if we elide both its name and its named bindings.
const name = resolver.isReferencedAliasDeclaration(node) ? node.name : undefined;
const namedBindings = visitNode(node.namedBindings, visitNamedImportBindings, isNamedImportBindings, /*optional*/ true);
const namedBindings = visitNode(node.namedBindings, visitNamedImportBindings, isNamedImportBindings);
return (name || namedBindings) ? updateImportClause(node, name, namedBindings) : undefined;
}
@ -2923,7 +2923,7 @@ namespace ts {
}
// Elide the export declaration if all of its named exports are elided.
const exportClause = visitNode(node.exportClause, visitNamedExports, isNamedExports, /*optional*/ true);
const exportClause = visitNode(node.exportClause, visitNamedExports, isNamedExports);
return exportClause
? updateExportDeclaration(
node,
@ -3327,17 +3327,18 @@ namespace ts {
function substituteConstantValue(node: PropertyAccessExpression | ElementAccessExpression): LeftHandSideExpression {
const constantValue = tryGetConstEnumValue(node);
if (constantValue !== undefined) {
// track the constant value on the node for the printer in needsDotDotForPropertyAccess
setConstantValue(node, constantValue);
const substitute = createLiteral(constantValue);
setSourceMapRange(substitute, node);
setCommentRange(substitute, node);
if (!compilerOptions.removeComments) {
const propertyName = isPropertyAccessExpression(node)
? declarationNameToString(node.name)
: getTextOfNode(node.argumentExpression);
substitute.trailingComment = ` ${propertyName} `;
addSyntheticTrailingComment(substitute, SyntaxKind.MultiLineCommentTrivia, ` ${propertyName} `);
}
setConstantValue(node, constantValue);
return substitute;
}

View file

@ -1323,7 +1323,6 @@
export interface NumericLiteral extends LiteralExpression {
kind: SyntaxKind.NumericLiteral;
trailingComment?: string;
}
export interface TemplateHead extends LiteralLikeNode {
@ -1907,9 +1906,17 @@
fileName: string;
}
export type CommentKind = SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia;
export interface CommentRange extends TextRange {
hasTrailingNewLine?: boolean;
kind: SyntaxKind;
kind: CommentKind;
}
export interface SynthesizedComment extends CommentRange {
text: string;
pos: -1;
end: -1;
}
// represents a top level: { type } expression in a JSDoc comment.
@ -2294,7 +2301,7 @@
* used for writing the JavaScript and declaration files. Otherwise, the writeFile parameter
* will be invoked when writing the JavaScript and declaration files.
*/
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean): EmitResult;
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult;
getOptionsDiagnostics(cancellationToken?: CancellationToken): Diagnostic[];
getGlobalDiagnostics(cancellationToken?: CancellationToken): Diagnostic[];
@ -2328,6 +2335,13 @@
/* @internal */ structureIsReused?: boolean;
}
export interface CustomTransformers {
/** Custom transformers to evaluate before built-in transformations. */
before?: TransformerFactory<SourceFile>[];
/** Custom transformers to evaluate after built-in transformations. */
after?: TransformerFactory<SourceFile>[];
}
export interface SourceMapSpan {
/** Line number in the .js file. */
emittedLine: number;
@ -3789,9 +3803,11 @@
export interface EmitNode {
annotatedNodes?: Node[]; // Tracks Parse-tree nodes with EmitNodes for eventual cleanup.
flags?: EmitFlags; // Flags that customize emit
leadingComments?: SynthesizedComment[]; // Synthesized leading comments
trailingComments?: SynthesizedComment[]; // Synthesized trailing comments
commentRange?: TextRange; // The text range to use when emitting leading or trailing comments
sourceMapRange?: TextRange; // The text range to use when emitting leading or trailing source mappings
tokenSourceMapRanges?: TextRange[]; // The text range to use when emitting source mappings for tokens
tokenSourceMapRanges?: TextRange[]; // The text range to use when emitting source mappings for tokens
constantValue?: number; // The constant value of an expression
externalHelpersModuleName?: Identifier; // The local name for an imported helpers module
helpers?: EmitHelper[]; // Emit helpers for the node
@ -3827,7 +3843,7 @@
export interface EmitHelper {
readonly name: string; // A unique name for this helper.
readonly scoped: boolean; // Indicates whether ther helper MUST be emitted in the current scope.
readonly scoped: boolean; // Indicates whether the helper MUST be emitted in the current scope.
readonly text: string; // ES3-compatible raw script text.
readonly priority?: number; // Helpers with a higher priority are emitted earlier than other helpers on the node.
}
@ -3889,11 +3905,12 @@
writeFile: WriteFileCallback;
}
/* @internal */
export interface TransformationContext {
/*@internal*/ getEmitResolver(): EmitResolver;
/*@internal*/ getEmitHost(): EmitHost;
/** Gets the compiler options supplied to the transformer. */
getCompilerOptions(): CompilerOptions;
getEmitResolver(): EmitResolver;
getEmitHost(): EmitHost;
/** Starts a new lexical environment. */
startLexicalEnvironment(): void;
@ -3907,41 +3924,32 @@
/** Ends a lexical environment, returning any declarations. */
endLexicalEnvironment(): Statement[];
/**
* Hoists a function declaration to the containing scope.
*/
/** Hoists a function declaration to the containing scope. */
hoistFunctionDeclaration(node: FunctionDeclaration): void;
/**
* Hoists a variable declaration to the containing scope.
*/
/** Hoists a variable declaration to the containing scope. */
hoistVariableDeclaration(node: Identifier): void;
/**
* Records a request for a non-scoped emit helper in the current context.
*/
/** Records a request for a non-scoped emit helper in the current context. */
requestEmitHelper(helper: EmitHelper): void;
/**
* Gets and resets the requested non-scoped emit helpers.
*/
/** Gets and resets the requested non-scoped emit helpers. */
readEmitHelpers(): EmitHelper[] | undefined;
/**
* Enables expression substitutions in the pretty printer for the provided SyntaxKind.
*/
/** Enables expression substitutions in the pretty printer for the provided SyntaxKind. */
enableSubstitution(kind: SyntaxKind): void;
/**
* Determines whether expression substitutions are enabled for the provided node.
*/
/** Determines whether expression substitutions are enabled for the provided node. */
isSubstitutionEnabled(node: Node): boolean;
/**
* Hook used by transformers to substitute expressions just before they
* are emitted by the pretty printer.
*
* NOTE: Transformation hooks should only be modified during `Transformer` initialization,
* before returning the `NodeTransformer` callback.
*/
onSubstituteNode?: (hint: EmitHint, node: Node) => Node;
onSubstituteNode: (hint: EmitHint, node: Node) => Node;
/**
* Enables before/after emit notifications in the pretty printer for the provided
@ -3958,25 +3966,27 @@
/**
* Hook used to allow transformers to capture state before or after
* the printer emits a node.
*
* NOTE: Transformation hooks should only be modified during `Transformer` initialization,
* before returning the `NodeTransformer` callback.
*/
onEmitNode?: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
onEmitNode: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
}
/* @internal */
export interface TransformationResult {
/**
* Gets the transformed source files.
*/
transformed: SourceFile[];
export interface TransformationResult<T extends Node> {
/** Gets the transformed source files. */
transformed: T[];
/** Gets diagnostics for the transformation. */
diagnostics?: Diagnostic[];
/**
* Emits the substitute for a node, if one is available; otherwise, emits the node.
* Gets a substitute for a node, if one is available; otherwise, returns the original node.
*
* @param hint A hint as to the intended usage of the node.
* @param node The node to substitute.
* @param emitCallback A callback used to emit the node or its substitute.
*/
emitNodeWithSubstitution(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
substituteNode(hint: EmitHint, node: Node): Node;
/**
* Emits a node with possible notification.
@ -3986,10 +3996,30 @@
* @param emitCallback A callback used to emit the node.
*/
emitNodeWithNotification(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
/**
* Clean up EmitNode entries on any parse-tree nodes.
*/
dispose(): void;
}
/* @internal */
export type Transformer = (context: TransformationContext) => (node: SourceFile) => SourceFile;
/**
* A function that is used to initialize and return a `Transformer` callback, which in turn
* will be used to transform one or more nodes.
*/
export type TransformerFactory<T extends Node> = (context: TransformationContext) => Transformer<T>;
/**
* A function that transforms a node.
*/
export type Transformer<T extends Node> = (node: T) => T;
/**
* A function that accepts and possible transforms a node.
*/
export type Visitor = (node: Node) => VisitResult<Node>;
export type VisitResult<T extends Node> = T | T[];
export interface Printer {
/**
@ -4047,23 +4077,20 @@
/**
* A hook used by the Printer to perform just-in-time substitution of a node. This is
* primarily used by node transformations that need to substitute one node for another,
* such as replacing `myExportedVar` with `exports.myExportedVar`. A compatible
* implementation **must** invoke `emitCallback` eith the provided `hint` and either
* the provided `node`, or its substitute.
* such as replacing `myExportedVar` with `exports.myExportedVar`.
* @param hint A hint indicating the intended purpose of the node.
* @param node The node to emit.
* @param emitCallback A callback that, when invoked, will emit the node.
* @example
* ```ts
* var printer = createPrinter(printerOptions, {
* onSubstituteNode(hint, node, emitCallback) {
* substituteNode(hint, node) {
* // perform substitution if necessary...
* emitCallback(hint, node);
* return node;
* }
* });
* ```
*/
onSubstituteNode?(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
substituteNode?(hint: EmitHint, node: Node): Node;
/*@internal*/ onEmitSourceMapOfNode?: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
/*@internal*/ onEmitSourceMapOfToken?: (node: Node, token: SyntaxKind, pos: number, emitCallback: (token: SyntaxKind, pos: number) => number) => number;
/*@internal*/ onEmitSourceMapOfPosition?: (pos: number) => void;

View file

@ -3799,6 +3799,12 @@ namespace ts {
return node.kind === SyntaxKind.PropertyAccessExpression;
}
export function isPropertyAccessOrQualifiedName(node: Node): node is PropertyAccessExpression | QualifiedName {
const kind = node.kind;
return kind === SyntaxKind.PropertyAccessExpression
|| kind === SyntaxKind.QualifiedName;
}
export function isElementAccessExpression(node: Node): node is ElementAccessExpression {
return node.kind === SyntaxKind.ElementAccessExpression;
}
@ -4149,16 +4155,18 @@ namespace ts {
return node.kind === SyntaxKind.JsxAttribute;
}
export function isJsxOpeningLikeElement(node: Node): node is JsxOpeningLikeElement {
return node.kind === SyntaxKind.JsxOpeningElement || node.kind === SyntaxKind.JsxSelfClosingElement;
}
export function isStringLiteralOrJsxExpression(node: Node): node is StringLiteral | JsxExpression {
const kind = node.kind;
return kind === SyntaxKind.StringLiteral
|| kind === SyntaxKind.JsxExpression;
}
export function isJsxOpeningLikeElement(node: Node): node is JsxOpeningLikeElement {
const kind = node.kind;
return kind === SyntaxKind.JsxOpeningElement
|| kind === SyntaxKind.JsxSelfClosingElement;
}
// Clauses
export function isCaseOrDefaultClause(node: Node): node is CaseOrDefaultClause {
@ -4608,7 +4616,7 @@ namespace ts {
*/
export function getParseTreeNode<T extends Node>(node: Node, nodeTest?: (node: Node) => node is T): T;
export function getParseTreeNode(node: Node, nodeTest?: (node: Node) => boolean): Node {
if (isParseTreeNode(node)) {
if (node == undefined || isParseTreeNode(node)) {
return node;
}

File diff suppressed because it is too large Load diff

View file

@ -77,8 +77,8 @@
"../services/codefixes/helpers.ts",
"../services/codefixes/importFixes.ts",
"../services/codefixes/unusedIdentifierFixes.ts",
"../services/harness.ts",
"harness.ts",
"sourceMapRecorder.ts",
"harnessLanguageService.ts",
"fourslash.ts",
@ -119,6 +119,8 @@
"./unittests/compileOnSave.ts",
"./unittests/typingsInstaller.ts",
"./unittests/projectErrors.ts",
"./unittests/printer.ts"
"./unittests/printer.ts",
"./unittests/transform.ts",
"./unittests/customTransforms.ts"
]
}

View file

@ -0,0 +1,86 @@
/// <reference path="..\..\compiler\emitter.ts" />
/// <reference path="..\harness.ts" />
namespace ts {
describe("customTransforms", () => {
function emitsCorrectly(name: string, sources: { file: string, text: string }[], customTransformers: CustomTransformers) {
it(name, () => {
const roots = sources.map(source => createSourceFile(source.file, source.text, ScriptTarget.ES2015));
const fileMap = arrayToMap(roots, file => file.fileName);
const outputs = createMap<string>();
const options: CompilerOptions = {};
const host: CompilerHost = {
getSourceFile: (fileName) => fileMap.get(fileName),
getDefaultLibFileName: () => "lib.d.ts",
getCurrentDirectory: () => "",
getDirectories: () => [],
getCanonicalFileName: (fileName) => fileName,
useCaseSensitiveFileNames: () => true,
getNewLine: () => "\n",
fileExists: (fileName) => fileMap.has(fileName),
readFile: (fileName) => fileMap.has(fileName) ? fileMap.get(fileName).text : undefined,
writeFile: (fileName, text) => outputs.set(fileName, text),
};
const program = createProgram(arrayFrom(fileMap.keys()), options, host);
program.emit(/*targetSourceFile*/ undefined, host.writeFile, /*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ false, customTransformers);
Harness.Baseline.runBaseline(`customTransforms/${name}.js`, () => {
let content = "";
for (const [file, text] of arrayFrom(outputs.entries())) {
if (content) content += "\n\n";
content += `// [${file}]\n`;
content += text;
}
return content;
});
});
}
const sources = [{
file: "source.ts",
text: `
function f1() { }
class c() { }
enum e { }
// leading
function f2() { } // trailing
`
}];
const before: TransformerFactory<SourceFile> = context => {
return file => visitEachChild(file, visit, context);
function visit(node: Node): VisitResult<Node> {
switch (node.kind) {
case SyntaxKind.FunctionDeclaration:
return visitFunction(<FunctionDeclaration>node);
default:
return visitEachChild(node, visit, context);
}
}
function visitFunction(node: FunctionDeclaration) {
addSyntheticLeadingComment(node, SyntaxKind.MultiLineCommentTrivia, "@before", /*hasTrailingNewLine*/ true);
return node;
}
};
const after: TransformerFactory<SourceFile> = context => {
return file => visitEachChild(file, visit, context);
function visit(node: Node): VisitResult<Node> {
switch (node.kind) {
case SyntaxKind.VariableStatement:
return visitVariableStatement(<VariableStatement>node);
default:
return visitEachChild(node, visit, context);
}
}
function visitVariableStatement(node: VariableStatement) {
addSyntheticLeadingComment(node, SyntaxKind.SingleLineCommentTrivia, "@after");
return node;
}
};
emitsCorrectly("before", sources, { before: [before] });
emitsCorrectly("after", sources, { after: [after] });
emitsCorrectly("both", sources, { before: [before], after: [after] });
});
}

View file

@ -0,0 +1,43 @@
/// <reference path="..\..\services\transform.ts" />
/// <reference path="..\harness.ts" />
namespace ts {
describe("TransformAPI", () => {
function transformsCorrectly(name: string, source: string, transformers: TransformerFactory<SourceFile>[]) {
it(name, () => {
Harness.Baseline.runBaseline(`transformApi/transformsCorrectly.${name}.js`, () => {
const transformed = transform(createSourceFile("source.ts", source, ScriptTarget.ES2015), transformers);
const printer = createPrinter({ newLine: NewLineKind.CarriageReturnLineFeed }, {
onEmitNode: transformed.emitNodeWithNotification,
substituteNode: transformed.substituteNode
});
const result = printer.printBundle(createBundle(transformed.transformed));
transformed.dispose();
return result;
});
});
}
transformsCorrectly("substitution", `
var a = undefined;
`, [
context => {
const previousOnSubstituteNode = context.onSubstituteNode;
context.enableSubstitution(SyntaxKind.Identifier);
context.onSubstituteNode = (hint, node) => {
node = previousOnSubstituteNode(hint, node);
if (hint === EmitHint.Expression && node.kind === SyntaxKind.Identifier && (<Identifier>node).text === "undefined") {
node = createPartiallyEmittedExpression(
addSyntheticTrailingComment(
setTextRange(
createVoidZero(),
node),
SyntaxKind.MultiLineCommentTrivia, "undefined"));
}
return node;
};
return file => file;
}
]);
});
}

View file

@ -67,10 +67,10 @@ namespace ts.OutliningElementsCollector {
// Only outline spans of two or more consecutive single line comments
if (count > 1) {
const multipleSingleLineComments = {
const multipleSingleLineComments: CommentRange = {
kind: SyntaxKind.SingleLineCommentTrivia,
pos: start,
end: end,
kind: SyntaxKind.SingleLineCommentTrivia
};
addOutliningSpanComments(multipleSingleLineComments, /*autoCollapse*/ false);

View file

@ -1447,7 +1447,8 @@ namespace ts {
});
}
const emitOutput = program.emit(sourceFile, writeFile, cancellationToken, emitOnlyDtsFiles);
const customTransformers = host.getCustomTransformers && host.getCustomTransformers();
const emitOutput = program.emit(sourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers);
return {
outputFiles,

18
src/services/transform.ts Normal file
View file

@ -0,0 +1,18 @@
/// <reference path="..\compiler\transformer.ts"/>
/// <reference path="transpile.ts"/>
namespace ts {
/**
* Transform one or more nodes using the supplied transformers.
* @param source A single `Node` or an array of `Node` objects.
* @param transformers An array of `TransformerFactory` callbacks used to process the transformation.
* @param compilerOptions Optional compiler options.
*/
export function transform<T extends Node>(source: T | T[], transformers: TransformerFactory<T>[], compilerOptions?: CompilerOptions) {
const diagnostics: Diagnostic[] = [];
compilerOptions = fixupCompilerOptions(compilerOptions, diagnostics);
const nodes = isArray(source) ? source : [source];
const result = transformNodes(/*resolver*/ undefined, /*emitHost*/ undefined, compilerOptions, nodes, transformers, /*allowDtsFiles*/ true);
result.diagnostics = concatenate(result.diagnostics, diagnostics);
return result;
}
}

View file

@ -123,7 +123,8 @@
let commandLineOptionsStringToEnum: CommandLineOptionOfCustomType[];
/** JS users may pass in string values for enum compiler options (such as ModuleKind), so convert. */
function fixupCompilerOptions(options: CompilerOptions, diagnostics: Diagnostic[]): CompilerOptions {
/*@internal*/
export function fixupCompilerOptions(options: CompilerOptions, diagnostics: Diagnostic[]): CompilerOptions {
// Lazily create this value to fix module loading errors.
commandLineOptionsStringToEnum = commandLineOptionsStringToEnum || <CommandLineOptionOfCustomType[]>filter(optionDeclarations, o =>
typeof o.type === "object" && !forEachEntry(o.type, v => typeof v !== "number"));

View file

@ -57,6 +57,7 @@
"preProcess.ts",
"rename.ts",
"services.ts",
"transform.ts",
"transpile.ts",
"shims.ts",
"signatureHelp.ts",

View file

@ -170,6 +170,11 @@ namespace ts {
* completions will not be provided
*/
getDirectories?(directoryName: string): string[];
/**
* Gets a set of custom transformers to use during emit.
*/
getCustomTransformers?(): CustomTransformers | undefined;
}
//

View file

@ -0,0 +1,15 @@
// [source.js]
function f1() { }
//@after
var c = (function () {
function c() {
}
return c;
}());
(function () { });
//@after
var e;
(function (e) {
})(e || (e = {}));
// leading
function f2() { } // trailing

View file

@ -0,0 +1,15 @@
// [source.js]
/*@before*/
function f1() { }
var c = (function () {
function c() {
}
return c;
}());
(function () { });
var e;
(function (e) {
})(e || (e = {}));
// leading
/*@before*/
function f2() { } // trailing

View file

@ -0,0 +1,17 @@
// [source.js]
/*@before*/
function f1() { }
//@after
var c = (function () {
function c() {
}
return c;
}());
(function () { });
//@after
var e;
(function (e) {
})(e || (e = {}));
// leading
/*@before*/
function f2() { } // trailing

View file

@ -0,0 +1 @@
var a = void 0 /*undefined*/;