mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-06 02:33:53 -06:00
Merge pull request #8824 from Microsoft/transforms-fixPerformance
[Transforms] Performance fixes
This commit is contained in:
commit
2ed97896d7
@ -3,8 +3,6 @@
|
||||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export let bindTime = 0;
|
||||
|
||||
export const enum ModuleInstanceState {
|
||||
NonInstantiated = 0,
|
||||
Instantiated = 1,
|
||||
@ -96,9 +94,9 @@ namespace ts {
|
||||
const binder = createBinder();
|
||||
|
||||
export function bindSourceFile(file: SourceFile, options: CompilerOptions) {
|
||||
const start = new Date().getTime();
|
||||
const bindStart = performance.mark();
|
||||
binder(file, options);
|
||||
bindTime += new Date().getTime() - start;
|
||||
performance.measure("bindTime", bindStart);
|
||||
}
|
||||
|
||||
function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
|
||||
|
||||
@ -14,8 +14,6 @@ namespace ts {
|
||||
return node.id;
|
||||
}
|
||||
|
||||
export let checkTime = 0;
|
||||
|
||||
export function getSymbolId(symbol: Symbol): number {
|
||||
if (!symbol.id) {
|
||||
symbol.id = nextSymbolId;
|
||||
@ -16066,11 +16064,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkSourceFile(node: SourceFile) {
|
||||
const start = new Date().getTime();
|
||||
const checkStart = performance.mark();
|
||||
|
||||
checkSourceFileWorker(node);
|
||||
|
||||
checkTime += new Date().getTime() - start;
|
||||
performance.measure("checkTime", checkStart);
|
||||
}
|
||||
|
||||
// Fully type check a source file and collect the relevant diagnostics.
|
||||
|
||||
@ -27,6 +27,11 @@ namespace ts {
|
||||
name: "diagnostics",
|
||||
type: "boolean",
|
||||
},
|
||||
{
|
||||
name: "extendedDiagnostics",
|
||||
type: "boolean",
|
||||
experimental: true,
|
||||
},
|
||||
{
|
||||
name: "emitBOM",
|
||||
type: "boolean"
|
||||
|
||||
@ -7,7 +7,6 @@ namespace ts {
|
||||
setSourceFile(sourceFile: SourceFile): void;
|
||||
getLeadingComments(range: TextRange): CommentRange[];
|
||||
getLeadingComments(range: TextRange, contextNode: Node, ignoreNodeCallback: (contextNode: Node) => boolean, getTextRangeCallback: (contextNode: Node) => TextRange): CommentRange[];
|
||||
getLeadingCommentsOfPosition(pos: number): CommentRange[];
|
||||
getTrailingComments(range: TextRange): CommentRange[];
|
||||
getTrailingComments(range: TextRange, contextNode: Node, ignoreNodeCallback: (contextNode: Node) => boolean, getTextRangeCallback: (contextNode: Node) => TextRange): CommentRange[];
|
||||
getTrailingCommentsOfPosition(pos: number): CommentRange[];
|
||||
@ -32,20 +31,23 @@ namespace ts {
|
||||
|
||||
// This maps start->end for a comment range. See `hasConsumedCommentRange` and
|
||||
// `consumeCommentRange` for usage.
|
||||
let consumedCommentRanges: number[];
|
||||
let leadingCommentRangePositions: boolean[];
|
||||
let trailingCommentRangePositions: boolean[];
|
||||
let consumedCommentRanges: Map<number>;
|
||||
let leadingCommentRangePositions: Map<boolean>;
|
||||
let trailingCommentRangePositions: Map<boolean>;
|
||||
|
||||
return compilerOptions.removeComments
|
||||
const commentWriter = compilerOptions.removeComments
|
||||
? createCommentRemovingWriter()
|
||||
: createCommentPreservingWriter();
|
||||
|
||||
return compilerOptions.extendedDiagnostics
|
||||
? createCommentWriterWithExtendedDiagnostics(commentWriter)
|
||||
: commentWriter;
|
||||
|
||||
function createCommentRemovingWriter(): CommentWriter {
|
||||
return {
|
||||
reset,
|
||||
setSourceFile,
|
||||
getLeadingComments(range: TextRange, contextNode?: Node, ignoreNodeCallback?: (contextNode: Node) => boolean, getTextRangeCallback?: (contextNode: Node) => TextRange): CommentRange[] { return undefined; },
|
||||
getLeadingCommentsOfPosition(pos: number): CommentRange[] { return undefined; },
|
||||
getTrailingComments(range: TextRange, contextNode?: Node, ignoreNodeCallback?: (contextNode: Node) => boolean, getTextRangeCallback?: (contextNode: Node) => TextRange): CommentRange[] { return undefined; },
|
||||
getTrailingCommentsOfPosition(pos: number): CommentRange[] { return undefined; },
|
||||
emitLeadingComments(range: TextRange, comments: CommentRange[], contextNode?: Node, getTextRangeCallback?: (contextNode: Node) => TextRange): void { },
|
||||
@ -69,7 +71,6 @@ namespace ts {
|
||||
reset,
|
||||
setSourceFile,
|
||||
getLeadingComments,
|
||||
getLeadingCommentsOfPosition,
|
||||
getTrailingComments,
|
||||
getTrailingCommentsOfPosition,
|
||||
emitLeadingComments,
|
||||
@ -100,11 +101,10 @@ namespace ts {
|
||||
return filter(getLeadingCommentsOfPosition(0), isTripleSlashComment);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return getLeadingCommentsOfPosition(range.pos);
|
||||
}
|
||||
|
||||
@ -127,15 +127,21 @@ namespace ts {
|
||||
function getTrailingComments(range: TextRange): CommentRange[];
|
||||
function getTrailingComments(range: TextRange, contextNode: Node, ignoreNodeCallback: (contextNode: Node) => boolean, getTextRangeCallback: (contextNode: Node) => TextRange): CommentRange[];
|
||||
function getTrailingComments(range: TextRange, contextNode?: Node, ignoreNodeCallback?: (contextNode: Node) => boolean, getTextRangeCallback?: (contextNode: Node) => TextRange) {
|
||||
let ignored = false;
|
||||
if (contextNode) {
|
||||
if (ignoreNodeCallback(contextNode)) {
|
||||
return undefined;
|
||||
ignored = true;
|
||||
}
|
||||
else {
|
||||
range = getTextRangeCallback(contextNode) || range;
|
||||
}
|
||||
|
||||
range = getTextRangeCallback(contextNode) || range;
|
||||
}
|
||||
|
||||
return getTrailingCommentsOfPosition(range.end);
|
||||
let comments: CommentRange[];
|
||||
if (!ignored) {
|
||||
comments = getTrailingCommentsOfPosition(range.end);
|
||||
}
|
||||
return comments;
|
||||
}
|
||||
|
||||
function getLeadingCommentsOfPosition(pos: number) {
|
||||
@ -249,6 +255,63 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function createCommentWriterWithExtendedDiagnostics(writer: CommentWriter): CommentWriter {
|
||||
const {
|
||||
reset,
|
||||
setSourceFile,
|
||||
getLeadingComments,
|
||||
getTrailingComments,
|
||||
getTrailingCommentsOfPosition,
|
||||
emitLeadingComments,
|
||||
emitTrailingComments,
|
||||
emitLeadingDetachedComments,
|
||||
emitTrailingDetachedComments
|
||||
} = writer;
|
||||
|
||||
return {
|
||||
reset,
|
||||
setSourceFile,
|
||||
getLeadingComments(range: TextRange, contextNode?: Node, ignoreNodeCallback?: (contextNode: Node) => boolean, getTextRangeCallback?: (contextNode: Node) => TextRange): CommentRange[] {
|
||||
const commentStart = performance.mark();
|
||||
const comments = getLeadingComments(range, contextNode, ignoreNodeCallback, getTextRangeCallback);
|
||||
performance.measure("commentTime", commentStart);
|
||||
return comments;
|
||||
},
|
||||
getTrailingComments(range: TextRange, contextNode?: Node, ignoreNodeCallback?: (contextNode: Node) => boolean, getTextRangeCallback?: (contextNode: Node) => TextRange): CommentRange[] {
|
||||
const commentStart = performance.mark();
|
||||
const comments = getTrailingComments(range, contextNode, ignoreNodeCallback, getTextRangeCallback);
|
||||
performance.measure("commentTime", commentStart);
|
||||
return comments;
|
||||
},
|
||||
getTrailingCommentsOfPosition(pos: number): CommentRange[] {
|
||||
const commentStart = performance.mark();
|
||||
const comments = getTrailingCommentsOfPosition(pos);
|
||||
performance.measure("commentTime", commentStart);
|
||||
return comments;
|
||||
},
|
||||
emitLeadingComments(range: TextRange, comments: CommentRange[], contextNode?: Node, getTextRangeCallback?: (contextNode: Node) => TextRange): void {
|
||||
const commentStart = performance.mark();
|
||||
emitLeadingComments(range, comments, contextNode, getTextRangeCallback);
|
||||
performance.measure("commentTime", commentStart);
|
||||
},
|
||||
emitTrailingComments(range: TextRange, comments: CommentRange[]): void {
|
||||
const commentStart = performance.mark();
|
||||
emitLeadingComments(range, comments);
|
||||
performance.measure("commentTime", commentStart);
|
||||
},
|
||||
emitLeadingDetachedComments(range: TextRange, contextNode?: Node, ignoreNodeCallback?: (contextNode: Node) => boolean): void {
|
||||
const commentStart = performance.mark();
|
||||
emitLeadingDetachedComments(range, contextNode, ignoreNodeCallback);
|
||||
performance.measure("commentTime", commentStart);
|
||||
},
|
||||
emitTrailingDetachedComments(range: TextRange, contextNode?: Node, ignoreNodeCallback?: (contextNode: Node) => boolean): void {
|
||||
const commentStart = performance.mark();
|
||||
emitTrailingDetachedComments(range, contextNode, ignoreNodeCallback);
|
||||
performance.measure("commentTime", commentStart);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function reset() {
|
||||
currentSourceFile = undefined;
|
||||
currentText = undefined;
|
||||
@ -264,9 +327,9 @@ namespace ts {
|
||||
currentText = sourceFile.text;
|
||||
currentLineMap = getLineStarts(sourceFile);
|
||||
detachedCommentsInfo = undefined;
|
||||
consumedCommentRanges = [];
|
||||
leadingCommentRangePositions = [];
|
||||
trailingCommentRangePositions = [];
|
||||
consumedCommentRanges = {};
|
||||
leadingCommentRangePositions = {};
|
||||
trailingCommentRangePositions = {};
|
||||
}
|
||||
|
||||
function hasDetachedComments(pos: number) {
|
||||
|
||||
@ -1049,6 +1049,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function Node(kind: SyntaxKind, pos: number, end: number) {
|
||||
this.id = 0;
|
||||
this.kind = kind;
|
||||
this.pos = pos;
|
||||
this.end = end;
|
||||
@ -1058,6 +1059,7 @@ namespace ts {
|
||||
this.excludeTransformFlags = TransformFlags.None;
|
||||
this.parent = undefined;
|
||||
this.original = undefined;
|
||||
this.transformId = 0;
|
||||
}
|
||||
|
||||
export let objectAllocator: ObjectAllocator = {
|
||||
@ -1118,6 +1120,18 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function getEnvironmentVariable(name: string, host?: CompilerHost) {
|
||||
if (host && host.getEnvironmentVariable) {
|
||||
return host.getEnvironmentVariable(name);
|
||||
}
|
||||
|
||||
if (sys && sys.getEnvironmentVariable) {
|
||||
return sys.getEnvironmentVariable(name);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
export function copyListRemovingItem<T>(item: T, list: T[]) {
|
||||
const copiedList: T[] = [];
|
||||
for (const e of list) {
|
||||
@ -1134,4 +1148,80 @@ namespace ts {
|
||||
: ((fileName) => fileName.toLowerCase());
|
||||
}
|
||||
|
||||
/** Performance measurements for the compiler. */
|
||||
/*@internal*/
|
||||
export namespace performance {
|
||||
let counters: Map<number>;
|
||||
let measures: Map<number>;
|
||||
|
||||
/**
|
||||
* Increments a counter with the specified name.
|
||||
*
|
||||
* @param counterName The name of the counter.
|
||||
*/
|
||||
export function increment(counterName: string) {
|
||||
if (counters) {
|
||||
counters[counterName] = (getProperty(counters, counterName) || 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the counter with the specified name.
|
||||
*
|
||||
* @param counterName The name of the counter.
|
||||
*/
|
||||
export function getCount(counterName: string) {
|
||||
return counters && getProperty(counters, counterName) || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the start of a performance measurement.
|
||||
*/
|
||||
export function mark() {
|
||||
return measures ? Date.now() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a performance measurement with the specified name.
|
||||
*
|
||||
* @param measureName The name of the performance measurement.
|
||||
* @param marker The timestamp of the starting mark.
|
||||
*/
|
||||
export function measure(measureName: string, marker: number) {
|
||||
if (measures) {
|
||||
measures[measureName] = (getProperty(measures, measureName) || 0) + (mark() - marker);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total duration of all measurements with the supplied name.
|
||||
*
|
||||
* @param measureName The name of the measure whose durations should be accumulated.
|
||||
*/
|
||||
export function getDuration(measureName: string) {
|
||||
return measures && getProperty(measures, measureName) || 0;
|
||||
}
|
||||
|
||||
/** Enables (and resets) performance measurements for the compiler. */
|
||||
export function enable() {
|
||||
counters = { };
|
||||
measures = {
|
||||
programTime: 0,
|
||||
parseTime: 0,
|
||||
bindTime: 0,
|
||||
emitTime: 0,
|
||||
ioReadTime: 0,
|
||||
ioWriteTime: 0,
|
||||
printTime: 0,
|
||||
commentTime: 0,
|
||||
sourceMapTime: 0
|
||||
};
|
||||
}
|
||||
|
||||
/** Disables (and clears) performance measurements for the compiler. */
|
||||
export function disable() {
|
||||
counters = undefined;
|
||||
measures = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -524,7 +524,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
const writer = createTextWriter(newLine);
|
||||
const { write, writeTextOfNode, writeLine, increaseIndent, decreaseIndent } = writer;
|
||||
|
||||
let sourceMap = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? createSourceMapWriter(host, writer) : getNullSourceMapWriter();
|
||||
let sourceMap = createSourceMapWriter(host, writer);
|
||||
let { setSourceFile, emitStart, emitEnd, emitPos } = sourceMap;
|
||||
|
||||
let currentSourceFile: SourceFile;
|
||||
|
||||
@ -8,7 +8,7 @@ namespace ts {
|
||||
let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
|
||||
let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
|
||||
|
||||
function createNode(kind: SyntaxKind, location?: TextRange, flags?: NodeFlags, emitOptions?: NodeEmitOptions): Node {
|
||||
function createNode(kind: SyntaxKind, location?: TextRange, flags?: NodeFlags): Node {
|
||||
const ConstructorForKind = kind === SyntaxKind.SourceFile
|
||||
? (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))
|
||||
: (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()));
|
||||
@ -17,13 +17,7 @@ namespace ts {
|
||||
? new ConstructorForKind(kind, location.pos, location.end)
|
||||
: new ConstructorForKind(kind, /*pos*/ -1, /*end*/ -1);
|
||||
|
||||
if (flags) {
|
||||
node.flags = flags;
|
||||
}
|
||||
|
||||
if (emitOptions) {
|
||||
node.emitOptions = emitOptions;
|
||||
}
|
||||
node.flags = flags | NodeFlags.Synthesized;
|
||||
|
||||
return node;
|
||||
}
|
||||
@ -68,12 +62,11 @@ namespace ts {
|
||||
/**
|
||||
* Creates a shallow, memberwise clone of a node with no source map location.
|
||||
*/
|
||||
export function getSynthesizedClone<T extends Node>(node: T, emitOptions?: NodeEmitOptions): T {
|
||||
export function getSynthesizedClone<T extends Node>(node: T): T {
|
||||
// We don't use "clone" from core.ts here, as we need to preserve the prototype chain of
|
||||
// the original node. We also need to exclude specific properties and only include own-
|
||||
// properties (to skip members already defined on the shared prototype).
|
||||
const clone = <T>createNode(node.kind, /*location*/ undefined, /*flags*/ undefined, emitOptions);
|
||||
clone.flags = node.flags;
|
||||
const clone = <T>createNode(node.kind, /*location*/ undefined, node.flags);
|
||||
clone.original = node;
|
||||
|
||||
for (const key in node) {
|
||||
@ -90,46 +83,36 @@ namespace ts {
|
||||
/**
|
||||
* Creates a shallow, memberwise clone of a node for mutation.
|
||||
*/
|
||||
export function getMutableClone<T extends Node>(node: T, emitOptions?: NodeEmitOptions): T {
|
||||
const clone = getSynthesizedClone(node, emitOptions);
|
||||
export function getMutableClone<T extends Node>(node: T): T {
|
||||
const clone = getSynthesizedClone(node);
|
||||
clone.pos = node.pos;
|
||||
clone.end = node.end;
|
||||
clone.parent = node.parent;
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a clone of a node with a unique node ID.
|
||||
*/
|
||||
export function getUniqueClone<T extends Node>(node: T, emitOptions?: NodeEmitOptions): T {
|
||||
const clone = getMutableClone(node, emitOptions);
|
||||
clone.id = undefined;
|
||||
getNodeId(clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Literals
|
||||
|
||||
export function createLiteral(textSource: StringLiteral | Identifier, location?: TextRange, emitOptions?: NodeEmitOptions): StringLiteral;
|
||||
export function createLiteral(value: string, location?: TextRange, emitOptions?: NodeEmitOptions): StringLiteral;
|
||||
export function createLiteral(value: number, location?: TextRange, emitOptions?: NodeEmitOptions): LiteralExpression;
|
||||
export function createLiteral(value: string | number | boolean, location?: TextRange, emitOptions?: NodeEmitOptions): PrimaryExpression;
|
||||
export function createLiteral(value: string | number | boolean | StringLiteral | Identifier, location?: TextRange, emitOptions?: NodeEmitOptions): PrimaryExpression {
|
||||
export function createLiteral(textSource: StringLiteral | Identifier, location?: TextRange): StringLiteral;
|
||||
export function createLiteral(value: string, location?: TextRange): StringLiteral;
|
||||
export function createLiteral(value: number, location?: TextRange): LiteralExpression;
|
||||
export function createLiteral(value: string | number | boolean, location?: TextRange): PrimaryExpression;
|
||||
export function createLiteral(value: string | number | boolean | StringLiteral | Identifier, location?: TextRange): PrimaryExpression {
|
||||
if (typeof value === "number") {
|
||||
const node = <LiteralExpression>createNode(SyntaxKind.NumericLiteral, location, /*flags*/ undefined, emitOptions);
|
||||
const node = <LiteralExpression>createNode(SyntaxKind.NumericLiteral, location, /*flags*/ undefined);
|
||||
node.text = value.toString();
|
||||
return node;
|
||||
}
|
||||
else if (typeof value === "boolean") {
|
||||
return <PrimaryExpression>createNode(value ? SyntaxKind.TrueKeyword : SyntaxKind.FalseKeyword, location, /*flags*/ undefined, emitOptions);
|
||||
return <PrimaryExpression>createNode(value ? SyntaxKind.TrueKeyword : SyntaxKind.FalseKeyword, location, /*flags*/ undefined);
|
||||
}
|
||||
else if (typeof value === "string") {
|
||||
const node = <StringLiteral>createNode(SyntaxKind.StringLiteral, location, /*flags*/ undefined, emitOptions);
|
||||
const node = <StringLiteral>createNode(SyntaxKind.StringLiteral, location, /*flags*/ undefined);
|
||||
node.text = value;
|
||||
return node;
|
||||
}
|
||||
else {
|
||||
const node = <StringLiteral>createNode(SyntaxKind.StringLiteral, location, /*flags*/ undefined, emitOptions);
|
||||
const node = <StringLiteral>createNode(SyntaxKind.StringLiteral, location, /*flags*/ undefined);
|
||||
node.textSourceNode = value;
|
||||
node.text = value.text;
|
||||
return node;
|
||||
@ -138,17 +121,23 @@ namespace ts {
|
||||
|
||||
// Identifiers
|
||||
|
||||
let nextAutoGenerateId = 0;
|
||||
|
||||
export function createIdentifier(text: string, location?: TextRange): Identifier {
|
||||
const node = <Identifier>createNode(SyntaxKind.Identifier, location);
|
||||
node.text = escapeIdentifier(text);
|
||||
node.originalKeywordKind = stringToToken(text);
|
||||
node.autoGenerateKind = GeneratedIdentifierKind.None;
|
||||
node.autoGenerateId = 0;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createTempVariable(recordTempVariable: (node: Identifier) => void, location?: TextRange): Identifier {
|
||||
const name = <Identifier>createNode(SyntaxKind.Identifier, location);
|
||||
name.text = "";
|
||||
name.originalKeywordKind = SyntaxKind.Unknown;
|
||||
name.autoGenerateKind = GeneratedIdentifierKind.Auto;
|
||||
getNodeId(name);
|
||||
name.autoGenerateId = nextAutoGenerateId++;
|
||||
if (recordTempVariable) {
|
||||
recordTempVariable(name);
|
||||
}
|
||||
@ -157,24 +146,29 @@ namespace ts {
|
||||
|
||||
export function createLoopVariable(location?: TextRange): Identifier {
|
||||
const name = <Identifier>createNode(SyntaxKind.Identifier, location);
|
||||
name.text = "";
|
||||
name.originalKeywordKind = SyntaxKind.Unknown;
|
||||
name.autoGenerateKind = GeneratedIdentifierKind.Loop;
|
||||
getNodeId(name);
|
||||
name.autoGenerateId = nextAutoGenerateId++;
|
||||
return name;
|
||||
}
|
||||
|
||||
export function createUniqueName(text: string, location?: TextRange): Identifier {
|
||||
const name = <Identifier>createNode(SyntaxKind.Identifier, location);
|
||||
name.text = text;
|
||||
name.originalKeywordKind = SyntaxKind.Unknown;
|
||||
name.autoGenerateKind = GeneratedIdentifierKind.Unique;
|
||||
getNodeId(name);
|
||||
name.autoGenerateId = nextAutoGenerateId++;
|
||||
return name;
|
||||
}
|
||||
|
||||
export function getGeneratedNameForNode(node: Node, location?: TextRange): Identifier {
|
||||
const name = <Identifier>createNode(SyntaxKind.Identifier, location);
|
||||
name.autoGenerateKind = GeneratedIdentifierKind.Node;
|
||||
name.original = node;
|
||||
getNodeId(name);
|
||||
name.text = "";
|
||||
name.originalKeywordKind = SyntaxKind.Unknown;
|
||||
name.autoGenerateKind = GeneratedIdentifierKind.Node;
|
||||
name.autoGenerateId = nextAutoGenerateId++;
|
||||
return name;
|
||||
}
|
||||
|
||||
@ -286,8 +280,8 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createPropertyAccess(expression: Expression, name: string | Identifier, location?: TextRange, emitOptions?: NodeEmitOptions) {
|
||||
const node = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, location, /*flags*/ undefined, emitOptions);
|
||||
export function createPropertyAccess(expression: Expression, name: string | Identifier, location?: TextRange) {
|
||||
const node = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, location, /*flags*/ undefined);
|
||||
node.expression = parenthesizeForAccess(expression);
|
||||
node.dotToken = createSynthesizedNode(SyntaxKind.DotToken);
|
||||
node.name = typeof name === "string" ? createIdentifier(name) : name;
|
||||
@ -504,8 +498,8 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createFor(initializer: ForInitializer, condition: Expression, incrementor: Expression, statement: Statement, location?: TextRange, emitOptions?: NodeEmitOptions) {
|
||||
const node = <ForStatement>createNode(SyntaxKind.ForStatement, location, /*flags*/ undefined, emitOptions);
|
||||
export function createFor(initializer: ForInitializer, condition: Expression, incrementor: Expression, statement: Statement, location?: TextRange) {
|
||||
const node = <ForStatement>createNode(SyntaxKind.ForStatement, location, /*flags*/ undefined);
|
||||
node.initializer = initializer;
|
||||
node.condition = condition;
|
||||
node.incrementor = incrementor;
|
||||
@ -735,9 +729,11 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createMemberAccessForPropertyName(target: Expression, memberName: PropertyName, location?: TextRange): MemberExpression {
|
||||
export function createMemberAccessForPropertyName(target: Expression, memberName: PropertyName, setNodeEmitFlags: (node: Node, flags: NodeEmitFlags) => void, location?: TextRange): MemberExpression {
|
||||
if (isIdentifier(memberName)) {
|
||||
return createPropertyAccess(target, memberName, location, { flags: NodeEmitFlags.NoNestedSourceMaps | NodeEmitFlags.Merge });
|
||||
const expression = createPropertyAccess(target, memberName, location);
|
||||
setNodeEmitFlags(expression, NodeEmitFlags.NoNestedSourceMaps);
|
||||
return expression;
|
||||
}
|
||||
else if (isComputedPropertyName(memberName)) {
|
||||
return createElementAccess(target, memberName.expression, location);
|
||||
@ -815,9 +811,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function createReactNamespace(reactNamespace: string, parent: JsxOpeningLikeElement) {
|
||||
// Create an identifier and give it a parent. This allows us to resolve the react
|
||||
// namespace during emit.
|
||||
// To ensure the emit resolver can properly resolve the namespace, we need to
|
||||
// treat this identifier as if it were a source tree node by clearing the `Synthesized`
|
||||
// flag and setting a parent node.
|
||||
const react = createIdentifier(reactNamespace || "React");
|
||||
react.flags &= ~NodeFlags.Synthesized;
|
||||
react.parent = parent;
|
||||
return react;
|
||||
}
|
||||
@ -1170,26 +1168,26 @@ namespace ts {
|
||||
return reduceLeft(expressions, createComma);
|
||||
}
|
||||
|
||||
export function createExpressionFromEntityName(node: EntityName | Expression, emitOptions?: NodeEmitOptions): Expression {
|
||||
export function createExpressionFromEntityName(node: EntityName | Expression): Expression {
|
||||
if (isQualifiedName(node)) {
|
||||
const left = createExpressionFromEntityName(node.left, emitOptions);
|
||||
const right = getMutableClone(node.right, emitOptions && clone(emitOptions));
|
||||
return createPropertyAccess(left, right, /*location*/ node, emitOptions && clone(emitOptions));
|
||||
const left = createExpressionFromEntityName(node.left);
|
||||
const right = getMutableClone(node.right);
|
||||
return createPropertyAccess(left, right, /*location*/ node);
|
||||
}
|
||||
else {
|
||||
return getMutableClone(node, emitOptions && clone(emitOptions));
|
||||
return getMutableClone(node);
|
||||
}
|
||||
}
|
||||
|
||||
export function createExpressionForPropertyName(memberName: PropertyName, emitOptions?: NodeEmitOptions): Expression {
|
||||
export function createExpressionForPropertyName(memberName: PropertyName): Expression {
|
||||
if (isIdentifier(memberName)) {
|
||||
return createLiteral(memberName, /*location*/ undefined, emitOptions);
|
||||
return createLiteral(memberName, /*location*/ undefined);
|
||||
}
|
||||
else if (isComputedPropertyName(memberName)) {
|
||||
return getMutableClone(memberName.expression, emitOptions);
|
||||
return getMutableClone(memberName.expression);
|
||||
}
|
||||
else {
|
||||
return getMutableClone(memberName, emitOptions);
|
||||
return getMutableClone(memberName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2034,7 +2034,7 @@ namespace ts {
|
||||
// FormalParameter [Yield,Await]:
|
||||
// BindingElement[?Yield,?Await]
|
||||
node.name = parseIdentifierOrPattern();
|
||||
if (getFullWidth(node.name) === 0 && node.flags === 0 && isModifierKind(token)) {
|
||||
if (getFullWidth(node.name) === 0 && !hasModifiers(node) && isModifierKind(token)) {
|
||||
// in cases like
|
||||
// 'use strict'
|
||||
// function foo(static)
|
||||
|
||||
@ -151,7 +151,7 @@ const _super = (function (geti, seti) {
|
||||
decreaseIndent
|
||||
} = writer;
|
||||
|
||||
const sourceMap = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? createSourceMapWriter(host, writer) : getNullSourceMapWriter();
|
||||
const sourceMap = createSourceMapWriter(host, writer);
|
||||
const {
|
||||
emitStart,
|
||||
emitEnd,
|
||||
@ -180,7 +180,8 @@ const _super = (function (geti, seti) {
|
||||
let isEmitNotificationEnabled: (node: Node) => boolean;
|
||||
let onSubstituteNode: (node: Node, isExpression: boolean) => Node;
|
||||
let onEmitNode: (node: Node, emit: (node: Node) => void) => void;
|
||||
let nodeToGeneratedName: string[];
|
||||
let nodeIdToGeneratedName: string[];
|
||||
let autoGeneratedIdToGeneratedName: string[];
|
||||
let generatedNameSet: Map<string>;
|
||||
let tempFlags: TempFlags;
|
||||
let currentSourceFile: SourceFile;
|
||||
@ -197,7 +198,8 @@ const _super = (function (geti, seti) {
|
||||
|
||||
function doPrint(jsFilePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) {
|
||||
sourceMap.initialize(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit);
|
||||
nodeToGeneratedName = [];
|
||||
nodeIdToGeneratedName = [];
|
||||
autoGeneratedIdToGeneratedName = [];
|
||||
generatedNameSet = {};
|
||||
isOwnFileEmit = !isBundledEmit;
|
||||
|
||||
@ -265,7 +267,7 @@ const _super = (function (geti, seti) {
|
||||
isEmitNotificationEnabled = context.isEmitNotificationEnabled;
|
||||
onSubstituteNode = context.onSubstituteNode;
|
||||
onEmitNode = context.onEmitNode;
|
||||
return printSourceFile;
|
||||
return compilerOptions.extendedDiagnostics ? printSourceFileWithExtendedDiagnostics : printSourceFile;
|
||||
}
|
||||
|
||||
function printSourceFile(node: SourceFile) {
|
||||
@ -278,6 +280,13 @@ const _super = (function (geti, seti) {
|
||||
return node;
|
||||
}
|
||||
|
||||
function printSourceFileWithExtendedDiagnostics(node: SourceFile) {
|
||||
const printStart = performance.mark();
|
||||
printSourceFile(node);
|
||||
performance.measure("printTime", printStart);
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits a node.
|
||||
*/
|
||||
@ -2706,6 +2715,11 @@ const _super = (function (geti, seti) {
|
||||
return makeUniqueName("class");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique name from a node.
|
||||
*
|
||||
* @param node A node.
|
||||
*/
|
||||
function generateNameForNode(node: Node): string {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
@ -2727,46 +2741,69 @@ const _super = (function (geti, seti) {
|
||||
}
|
||||
}
|
||||
|
||||
function generateIdentifier(node: Identifier) {
|
||||
switch (node.autoGenerateKind) {
|
||||
/**
|
||||
* Generates a unique identifier for a node.
|
||||
*
|
||||
* @param name A generated name.
|
||||
*/
|
||||
function generateName(name: Identifier) {
|
||||
switch (name.autoGenerateKind) {
|
||||
case GeneratedIdentifierKind.Auto:
|
||||
return makeTempVariableName(TempFlags.Auto);
|
||||
case GeneratedIdentifierKind.Loop:
|
||||
return makeTempVariableName(TempFlags._i);
|
||||
case GeneratedIdentifierKind.Unique:
|
||||
return makeUniqueName(node.text);
|
||||
case GeneratedIdentifierKind.Node:
|
||||
return generateNameForNode(getSourceNodeForGeneratedName(node));
|
||||
return makeUniqueName(name.text);
|
||||
}
|
||||
|
||||
Debug.fail("Unsupported GeneratedIdentifierKind.");
|
||||
}
|
||||
|
||||
function getGeneratedIdentifier(node: Identifier) {
|
||||
const id = getNodeIdForGeneratedIdentifier(node);
|
||||
return nodeToGeneratedName[id] || (nodeToGeneratedName[id] = unescapeIdentifier(generateIdentifier(node)));
|
||||
}
|
||||
/**
|
||||
* Gets the node from which a name should be generated.
|
||||
*
|
||||
* @param name A generated name wrapper.
|
||||
*/
|
||||
function getNodeForGeneratedName(name: Identifier) {
|
||||
const autoGenerateId = name.autoGenerateId;
|
||||
let node = name as Node;
|
||||
let original = node.original;
|
||||
while (original) {
|
||||
node = original;
|
||||
|
||||
function getSourceNodeForGeneratedName(name: Identifier) {
|
||||
let node: Node = name;
|
||||
while (node.original !== undefined) {
|
||||
const nodeId = node.id;
|
||||
node = node.original;
|
||||
// If "node" is not the exact clone of "original" identifier, use "original" identifier to generate the name
|
||||
if (isIdentifier(node) && node.autoGenerateKind === GeneratedIdentifierKind.Node && node.id !== nodeId) {
|
||||
// if "node" is a different generated name (having a different
|
||||
// "autoGenerateId"), use it and stop traversing.
|
||||
if (isIdentifier(node)
|
||||
&& node.autoGenerateKind === GeneratedIdentifierKind.Node
|
||||
&& node.autoGenerateId !== autoGenerateId) {
|
||||
break;
|
||||
}
|
||||
|
||||
original = node.original;
|
||||
}
|
||||
|
||||
// otherwise, return the original node for the source;
|
||||
return node;
|
||||
}
|
||||
|
||||
function getNodeIdForGeneratedIdentifier(node: Identifier) {
|
||||
switch (node.autoGenerateKind) {
|
||||
case GeneratedIdentifierKind.Auto:
|
||||
case GeneratedIdentifierKind.Loop:
|
||||
case GeneratedIdentifierKind.Unique:
|
||||
return getNodeId(node);
|
||||
case GeneratedIdentifierKind.Node:
|
||||
return getNodeId(getSourceNodeForGeneratedName(node));
|
||||
/**
|
||||
* Gets the generated identifier text from a generated identifier.
|
||||
*
|
||||
* @param name The generated identifier.
|
||||
*/
|
||||
function getGeneratedIdentifier(name: Identifier) {
|
||||
if (name.autoGenerateKind === GeneratedIdentifierKind.Node) {
|
||||
// Generated names generate unique names based on their original node
|
||||
// and are cached based on that node's id
|
||||
const node = getNodeForGeneratedName(name);
|
||||
const nodeId = getNodeId(node);
|
||||
return nodeIdToGeneratedName[nodeId] || (nodeIdToGeneratedName[nodeId] = unescapeIdentifier(generateNameForNode(node)));
|
||||
}
|
||||
else {
|
||||
// Auto, Loop, and Unique names are cached based on their unique
|
||||
// autoGenerateId.
|
||||
const autoGenerateId = name.autoGenerateId;
|
||||
return autoGeneratedIdToGeneratedName[autoGenerateId] || (autoGeneratedIdToGeneratedName[autoGenerateId] = unescapeIdentifier(generateName(name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,11 +4,6 @@
|
||||
/// <reference path="printer.ts" />
|
||||
|
||||
namespace ts {
|
||||
/* @internal */ export let programTime = 0;
|
||||
/* @internal */ export let emitTime = 0;
|
||||
/* @internal */ export let ioReadTime = 0;
|
||||
/* @internal */ export let ioWriteTime = 0;
|
||||
|
||||
/** The version of the TypeScript compiler release */
|
||||
|
||||
const emptyArray: any[] = [];
|
||||
@ -781,9 +776,9 @@ namespace ts {
|
||||
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile {
|
||||
let text: string;
|
||||
try {
|
||||
const start = new Date().getTime();
|
||||
const ioReadStart = performance.mark();
|
||||
text = sys.readFile(fileName, options.charset);
|
||||
ioReadTime += new Date().getTime() - start;
|
||||
performance.measure("ioReadTime", ioReadStart);
|
||||
}
|
||||
catch (e) {
|
||||
if (onError) {
|
||||
@ -850,7 +845,7 @@ namespace ts {
|
||||
|
||||
function writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) {
|
||||
try {
|
||||
const start = new Date().getTime();
|
||||
const ioWriteStart = performance.mark();
|
||||
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
|
||||
|
||||
if (isWatchSet(options) && sys.createHash && sys.getModifiedTime) {
|
||||
@ -860,7 +855,7 @@ namespace ts {
|
||||
sys.writeFile(fileName, data, writeByteOrderMark);
|
||||
}
|
||||
|
||||
ioWriteTime += new Date().getTime() - start;
|
||||
performance.measure("ioWriteTime", ioWriteStart);
|
||||
}
|
||||
catch (e) {
|
||||
if (onError) {
|
||||
@ -962,7 +957,7 @@ namespace ts {
|
||||
let resolvedTypeReferenceDirectives: Map<ResolvedTypeReferenceDirective> = {};
|
||||
let fileProcessingDiagnostics = createDiagnosticCollection();
|
||||
|
||||
const start = new Date().getTime();
|
||||
const programStart = performance.mark();
|
||||
|
||||
host = host || createCompilerHost(options);
|
||||
|
||||
@ -1055,7 +1050,7 @@ namespace ts {
|
||||
|
||||
verifyCompilerOptions();
|
||||
|
||||
programTime += new Date().getTime() - start;
|
||||
performance.measure("programTime", programStart);
|
||||
|
||||
return program;
|
||||
|
||||
@ -1288,7 +1283,7 @@ namespace ts {
|
||||
// checked is to not pass the file to getEmitResolver.
|
||||
const emitResolver = getDiagnosticsProducingTypeChecker().getEmitResolver((options.outFile || options.out) ? undefined : sourceFile);
|
||||
|
||||
const start = new Date().getTime();
|
||||
const emitStart = performance.mark();
|
||||
|
||||
// TODO(rbuckton): remove USE_TRANSFORMS condition when we switch to transforms permanently.
|
||||
let useLegacyEmitter = options.useLegacyEmitter;
|
||||
@ -1302,7 +1297,8 @@ namespace ts {
|
||||
getEmitHost(writeFileCallback),
|
||||
sourceFile);
|
||||
|
||||
emitTime += new Date().getTime() - start;
|
||||
performance.measure("emitTime", emitStart);
|
||||
|
||||
return emitResult;
|
||||
}
|
||||
|
||||
@ -2076,7 +2072,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Cannot specify module gen that isn't amd or system with --out
|
||||
// Report this error if user specified --module moduleKind
|
||||
// Report this error if user specified --module moduleKind
|
||||
// or if there is external module in compilation which defaults to commonjs
|
||||
const emitModuleKind = getEmitModuleKind(options);
|
||||
if (outFile && (options.module || firstExternalModuleSourceFile) && !(emitModuleKind === ModuleKind.AMD || emitModuleKind === ModuleKind.System)) {
|
||||
|
||||
@ -593,7 +593,7 @@ namespace ts {
|
||||
function getCommentRanges(text: string, pos: number, trailing: boolean): CommentRange[] {
|
||||
let result: CommentRange[];
|
||||
let collecting = trailing || pos === 0;
|
||||
while (pos < text.length) {
|
||||
while (pos >= 0 && pos < text.length) {
|
||||
const ch = text.charCodeAt(pos);
|
||||
switch (ch) {
|
||||
case CharacterCodes.carriageReturn:
|
||||
|
||||
@ -170,6 +170,20 @@ namespace ts {
|
||||
getSourceMappingURL(): string;
|
||||
}
|
||||
|
||||
export function createSourceMapWriter(host: EmitHost, writer: EmitTextWriter): SourceMapWriter {
|
||||
const compilerOptions = host.getCompilerOptions();
|
||||
if (compilerOptions.sourceMap || compilerOptions.inlineSourceMap) {
|
||||
if (compilerOptions.extendedDiagnostics) {
|
||||
return createSourceMapWriterWithExtendedDiagnostics(host, writer);
|
||||
}
|
||||
|
||||
return createSourceMapWriterWorker(host, writer);
|
||||
}
|
||||
else {
|
||||
return getNullSourceMapWriter();
|
||||
}
|
||||
}
|
||||
|
||||
let nullSourceMapWriter: SourceMapWriter;
|
||||
|
||||
export function getNullSourceMapWriter(): SourceMapWriter {
|
||||
@ -182,8 +196,8 @@ namespace ts {
|
||||
emitPos(pos: number): void { },
|
||||
emitStart(range: TextRange, contextNode?: Node, ignoreNodeCallback?: (node: Node) => boolean, ignoreChildrenCallback?: (node: Node) => boolean, getTextRangeCallback?: (node: Node) => TextRange): void { },
|
||||
emitEnd(range: TextRange, contextNode?: Node, ignoreNodeCallback?: (node: Node) => boolean, ignoreChildrenCallback?: (node: Node) => boolean, getTextRangeCallback?: (node: Node) => TextRange): void { },
|
||||
emitTokenStart(token: SyntaxKind, pos: number, contextNode?: Node, ignoreTokenCallback?: (node: Node) => boolean, getTokenTextRangeCallback?: (node: Node, token: SyntaxKind, pos: number) => TextRange): number { return -1; },
|
||||
emitTokenEnd(token: SyntaxKind, end: number, contextNode?: Node, ignoreTokenCallback?: (node: Node) => boolean, getTokenTextRangeCallback?: (node: Node, token: SyntaxKind, pos: number) => TextRange): number { return -1; },
|
||||
emitTokenStart(token: SyntaxKind, pos: number, contextNode?: Node, ignoreTokenCallback?: (node: Node) => boolean, getTokenTextRangeCallback?: (node: Node, token: SyntaxKind) => TextRange): number { return -1; },
|
||||
emitTokenEnd(token: SyntaxKind, end: number, contextNode?: Node, ignoreTokenCallback?: (node: Node) => boolean, getTokenTextRangeCallback?: (node: Node, token: SyntaxKind) => TextRange): number { return -1; },
|
||||
changeEmitSourcePos(): void { },
|
||||
stopOverridingSpan(): void { },
|
||||
getText(): string { return undefined; },
|
||||
@ -203,7 +217,7 @@ namespace ts {
|
||||
sourceIndex: 0
|
||||
};
|
||||
|
||||
export function createSourceMapWriter(host: EmitHost, writer: EmitTextWriter): SourceMapWriter {
|
||||
function createSourceMapWriterWorker(host: EmitHost, writer: EmitTextWriter): SourceMapWriter {
|
||||
const compilerOptions = host.getCompilerOptions();
|
||||
let currentSourceFile: SourceFile;
|
||||
let currentSourceText: string;
|
||||
@ -746,6 +760,61 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function createSourceMapWriterWithExtendedDiagnostics(host: EmitHost, writer: EmitTextWriter): SourceMapWriter {
|
||||
const {
|
||||
initialize,
|
||||
reset,
|
||||
getSourceMapData,
|
||||
setSourceFile,
|
||||
emitPos,
|
||||
emitStart,
|
||||
emitEnd,
|
||||
emitTokenStart,
|
||||
emitTokenEnd,
|
||||
changeEmitSourcePos,
|
||||
stopOverridingSpan,
|
||||
getText,
|
||||
getSourceMappingURL,
|
||||
} = createSourceMapWriterWorker(host, writer);
|
||||
return {
|
||||
initialize,
|
||||
reset,
|
||||
getSourceMapData,
|
||||
setSourceFile,
|
||||
emitPos(pos: number): void {
|
||||
const sourcemapStart = performance.mark();
|
||||
emitPos(pos);
|
||||
performance.measure("sourceMapTime", sourcemapStart);
|
||||
},
|
||||
emitStart(range: TextRange, contextNode?: Node, ignoreNodeCallback?: (node: Node) => boolean, ignoreChildrenCallback?: (node: Node) => boolean, getTextRangeCallback?: (node: Node) => TextRange): void {
|
||||
const sourcemapStart = performance.mark();
|
||||
emitStart(range, contextNode, ignoreNodeCallback, ignoreChildrenCallback, getTextRangeCallback);
|
||||
performance.measure("sourceMapTime", sourcemapStart);
|
||||
},
|
||||
emitEnd(range: TextRange, contextNode?: Node, ignoreNodeCallback?: (node: Node) => boolean, ignoreChildrenCallback?: (node: Node) => boolean, getTextRangeCallback?: (node: Node) => TextRange): void {
|
||||
const sourcemapStart = performance.mark();
|
||||
emitEnd(range, contextNode, ignoreNodeCallback, ignoreChildrenCallback, getTextRangeCallback);
|
||||
performance.measure("sourceMapTime", sourcemapStart);
|
||||
},
|
||||
emitTokenStart(token: SyntaxKind, tokenStartPos: number, contextNode?: Node, ignoreTokenCallback?: (node: Node) => boolean, getTokenTextRangeCallback?: (node: Node, token: SyntaxKind) => TextRange): number {
|
||||
const sourcemapStart = performance.mark();
|
||||
tokenStartPos = emitTokenStart(token, tokenStartPos, contextNode, ignoreTokenCallback, getTokenTextRangeCallback);
|
||||
performance.measure("sourceMapTime", sourcemapStart);
|
||||
return tokenStartPos;
|
||||
},
|
||||
emitTokenEnd(token: SyntaxKind, tokenEndPos: number, contextNode?: Node, ignoreTokenCallback?: (node: Node) => boolean, getTokenTextRangeCallback?: (node: Node, token: SyntaxKind) => TextRange): number {
|
||||
const sourcemapStart = performance.mark();
|
||||
tokenEndPos = emitTokenEnd(token, tokenEndPos, contextNode, ignoreTokenCallback, getTokenTextRangeCallback);
|
||||
performance.measure("sourceMapTime", sourcemapStart);
|
||||
return tokenEndPos;
|
||||
},
|
||||
changeEmitSourcePos,
|
||||
stopOverridingSpan,
|
||||
getText,
|
||||
getSourceMappingURL,
|
||||
};
|
||||
}
|
||||
|
||||
const base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
function base64FormatEncode(inValue: number) {
|
||||
|
||||
@ -23,6 +23,100 @@ namespace ts {
|
||||
EmitNotifications = 1 << 1,
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface TransformationContext extends LexicalEnvironment {
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
getEmitResolver(): EmitResolver;
|
||||
getEmitHost(): EmitHost;
|
||||
|
||||
/**
|
||||
* Gets flags used to customize later transformations or emit.
|
||||
*/
|
||||
getNodeEmitFlags(node: Node): NodeEmitFlags;
|
||||
|
||||
/**
|
||||
* Sets flags used to customize later transformations or emit.
|
||||
*/
|
||||
setNodeEmitFlags<T extends Node>(node: T, flags: NodeEmitFlags): T;
|
||||
|
||||
/**
|
||||
* Gets the TextRange to use for source maps for the node.
|
||||
*/
|
||||
getSourceMapRange(node: Node): TextRange;
|
||||
|
||||
/**
|
||||
* Sets the TextRange to use for source maps for the node.
|
||||
*/
|
||||
setSourceMapRange<T extends Node>(node: T, range: TextRange): T;
|
||||
|
||||
/**
|
||||
* Gets the TextRange to use for source maps for a token of a node.
|
||||
*/
|
||||
getTokenSourceMapRange(node: Node, token: SyntaxKind): TextRange;
|
||||
|
||||
/**
|
||||
* Sets the TextRange to use for source maps for a token of a node.
|
||||
*/
|
||||
setTokenSourceMapRange<T extends Node>(node: T, token: SyntaxKind, range: TextRange): T;
|
||||
|
||||
/**
|
||||
* Gets the TextRange to use for comments for the node.
|
||||
*/
|
||||
getCommentRange(node: Node): TextRange;
|
||||
|
||||
/**
|
||||
* Sets the TextRange to use for comments for the node.
|
||||
*/
|
||||
setCommentRange<T extends Node>(node: T, range: TextRange): T;
|
||||
|
||||
/**
|
||||
* Hoists a function declaration to the containing scope.
|
||||
*/
|
||||
hoistFunctionDeclaration(node: FunctionDeclaration): void;
|
||||
|
||||
/**
|
||||
* Hoists a variable declaration to the containing scope.
|
||||
*/
|
||||
hoistVariableDeclaration(node: Identifier): void;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
isSubstitutionEnabled(node: Node): boolean;
|
||||
|
||||
/**
|
||||
* Hook used by transformers to substitute expressions just before they
|
||||
* are emitted by the pretty printer.
|
||||
*/
|
||||
onSubstituteNode?: (node: Node, isExpression: boolean) => Node;
|
||||
|
||||
/**
|
||||
* Enables before/after emit notifications in the pretty printer for the provided
|
||||
* SyntaxKind.
|
||||
*/
|
||||
enableEmitNotification(kind: SyntaxKind): void;
|
||||
|
||||
/**
|
||||
* Determines whether before/after emit notifications should be raised in the pretty
|
||||
* printer when it emits a node.
|
||||
*/
|
||||
isEmitNotificationEnabled(node: Node): boolean;
|
||||
|
||||
/**
|
||||
* Hook used to allow transformers to capture state before or after
|
||||
* the printer emits a node.
|
||||
*/
|
||||
onEmitNode?: (node: Node, emit: (node: Node) => void) => void;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export type Transformer = (context: TransformationContext) => (node: SourceFile) => SourceFile;
|
||||
|
||||
export function getTransformers(compilerOptions: CompilerOptions) {
|
||||
const jsx = compilerOptions.jsx;
|
||||
const languageVersion = getEmitScriptTarget(compilerOptions);
|
||||
@ -45,6 +139,14 @@ namespace ts {
|
||||
return transformers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks a monotonically increasing transformation id used to associate a node with a specific
|
||||
* transformation. This ensures transient properties related to transformations can be safely
|
||||
* stored on source tree nodes that may be reused across multiple transformations (such as
|
||||
* with compile-on-save).
|
||||
*/
|
||||
let nextTransformId = 1;
|
||||
|
||||
/**
|
||||
* Transforms an array of SourceFiles by passing them through each transformer.
|
||||
*
|
||||
@ -54,10 +156,22 @@ namespace ts {
|
||||
* @param transforms An array of Transformers.
|
||||
*/
|
||||
export function transformFiles(resolver: EmitResolver, host: EmitHost, sourceFiles: SourceFile[], transformers: Transformer[]) {
|
||||
const nodeEmitOptions: NodeEmitOptions[] = [];
|
||||
const transformId = nextTransformId++;
|
||||
const tokenSourceMapRanges: Map<TextRange> = { };
|
||||
const lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = [];
|
||||
const lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = [];
|
||||
const enabledSyntaxKindFeatures = new Array<SyntaxKindFeatureFlags>(SyntaxKind.Count);
|
||||
const sourceTreeNodesWithAnnotations: Node[] = [];
|
||||
|
||||
let lastNodeEmitFlagsNode: Node;
|
||||
let lastNodeEmitFlags: NodeEmitFlags;
|
||||
let lastSourceMapRangeNode: Node;
|
||||
let lastSourceMapRange: TextRange;
|
||||
let lastTokenSourceMapRangeNode: Node;
|
||||
let lastTokenSourceMapRangeToken: SyntaxKind;
|
||||
let lastTokenSourceMapRange: TextRange;
|
||||
let lastCommentMapRangeNode: Node;
|
||||
let lastCommentMapRange: TextRange;
|
||||
let lexicalEnvironmentStackOffset = 0;
|
||||
let hoistedVariableDeclarations: VariableDeclaration[];
|
||||
let hoistedFunctionDeclarations: FunctionDeclaration[];
|
||||
@ -107,7 +221,20 @@ namespace ts {
|
||||
}
|
||||
|
||||
currentSourceFile = sourceFile;
|
||||
return transformation(sourceFile);
|
||||
sourceFile = transformation(sourceFile);
|
||||
|
||||
// Cleanup source tree nodes with annotations
|
||||
for (const node of sourceTreeNodesWithAnnotations) {
|
||||
if (node.transformId === transformId) {
|
||||
node.transformId = 0;
|
||||
node.emitFlags = 0;
|
||||
node.commentRange = undefined;
|
||||
node.sourceMapRange = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
sourceTreeNodesWithAnnotations.length = 0;
|
||||
return sourceFile;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -170,143 +297,233 @@ namespace ts {
|
||||
emit(node);
|
||||
}
|
||||
|
||||
function getEmitOptions(node: Node, create?: boolean) {
|
||||
let options = isSourceTreeNode(node)
|
||||
? nodeEmitOptions[getNodeId(node)]
|
||||
: node.emitOptions;
|
||||
if (!options && create) {
|
||||
options = { };
|
||||
if (isSourceTreeNode(node)) {
|
||||
nodeEmitOptions[getNodeId(node)] = options;
|
||||
}
|
||||
else {
|
||||
node.emitOptions = options;
|
||||
/**
|
||||
* Associates a node with the current transformation, initializing
|
||||
* various transient transformation properties.
|
||||
*
|
||||
* @param node The node.
|
||||
*/
|
||||
function beforeSetAnnotation(node: Node) {
|
||||
if (node.transformId !== transformId) {
|
||||
node.transformId = transformId;
|
||||
if ((node.flags & NodeFlags.Synthesized) === 0) {
|
||||
node.emitFlags = 0;
|
||||
node.sourceMapRange = undefined;
|
||||
node.commentRange = undefined;
|
||||
|
||||
// To avoid holding onto transformation artifacts, we keep track of any
|
||||
// source tree node we are annotating. This allows us to clean them up after
|
||||
// all transformations have completed.
|
||||
sourceTreeNodesWithAnnotations.push(node);
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets flags that control emit behavior of a node.
|
||||
*
|
||||
* If the node does not have its own NodeEmitFlags set, the node emit flags of its
|
||||
* original pointer are used.
|
||||
*
|
||||
* @param node The node.
|
||||
*/
|
||||
function getNodeEmitFlags(node: Node) {
|
||||
while (node) {
|
||||
const options = getEmitOptions(node, /*create*/ false);
|
||||
if (options && options.flags !== undefined) {
|
||||
if (options.flags & NodeEmitFlags.Merge) {
|
||||
options.flags = (options.flags | getNodeEmitFlags(node.original)) & ~NodeEmitFlags.Merge;
|
||||
}
|
||||
|
||||
return options.flags;
|
||||
}
|
||||
|
||||
node = node.original;
|
||||
// As a performance optimization, use the cached value of the most recent node.
|
||||
// This helps for cases where this function is called repeatedly for the same node.
|
||||
if (lastNodeEmitFlagsNode === node) {
|
||||
return lastNodeEmitFlags;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
// Get the emit flags for a node or from one of its original nodes.
|
||||
let flags: NodeEmitFlags;
|
||||
let current = node;
|
||||
while (current) {
|
||||
if (current.transformId === transformId) {
|
||||
const nodeEmitFlags = current.emitFlags;
|
||||
if (nodeEmitFlags) {
|
||||
flags = nodeEmitFlags & ~NodeEmitFlags.HasNodeEmitFlags;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
current = current.original;
|
||||
}
|
||||
|
||||
// Cache the most recently requested value.
|
||||
lastNodeEmitFlagsNode = node;
|
||||
lastNodeEmitFlags = flags;
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets flags that control emit behavior of a node.
|
||||
*
|
||||
* @param node The node.
|
||||
* @param emitFlags The NodeEmitFlags for the node.
|
||||
*/
|
||||
function setNodeEmitFlags<T extends Node>(node: T, flags: NodeEmitFlags) {
|
||||
const options = getEmitOptions(node, /*create*/ true);
|
||||
if (flags & NodeEmitFlags.Merge) {
|
||||
flags = options.flags | (flags & ~NodeEmitFlags.Merge);
|
||||
function setNodeEmitFlags<T extends Node>(node: T, emitFlags: NodeEmitFlags) {
|
||||
// Merge existing flags.
|
||||
if (emitFlags & NodeEmitFlags.Merge) {
|
||||
emitFlags = getNodeEmitFlags(node) | (emitFlags & ~NodeEmitFlags.Merge);
|
||||
}
|
||||
|
||||
options.flags = flags;
|
||||
beforeSetAnnotation(node);
|
||||
|
||||
// Cache the most recently requested value.
|
||||
lastNodeEmitFlagsNode = node;
|
||||
lastNodeEmitFlags = emitFlags;
|
||||
node.emitFlags = emitFlags | NodeEmitFlags.HasNodeEmitFlags;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a custom text range to use when emitting source maps.
|
||||
*
|
||||
* If a node does not have its own custom source map text range, the custom source map
|
||||
* text range of its original pointer is used.
|
||||
*
|
||||
* @param node The node.
|
||||
*/
|
||||
function getSourceMapRange(node: Node) {
|
||||
// As a performance optimization, use the cached value of the most recent node.
|
||||
// This helps for cases where this function is called repeatedly for the same node.
|
||||
if (lastSourceMapRangeNode === node) {
|
||||
return lastSourceMapRange || node;
|
||||
}
|
||||
|
||||
// Get the custom source map range for a node or from one of its original nodes.
|
||||
let range: TextRange;
|
||||
let current = node;
|
||||
while (current) {
|
||||
const options = getEmitOptions(current);
|
||||
if (options && options.sourceMapRange !== undefined) {
|
||||
return options.sourceMapRange;
|
||||
if (current.transformId === transformId) {
|
||||
range = current.sourceMapRange;
|
||||
if (range !== undefined) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
current = current.original;
|
||||
}
|
||||
|
||||
return node;
|
||||
// Cache the most recently requested value.
|
||||
lastSourceMapRangeNode = node;
|
||||
lastSourceMapRange = range;
|
||||
return range || node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom text range to use when emitting source maps.
|
||||
*
|
||||
* @param node The node.
|
||||
* @param range The text range.
|
||||
*/
|
||||
function setSourceMapRange<T extends Node>(node: T, range: TextRange) {
|
||||
getEmitOptions(node, /*create*/ true).sourceMapRange = range;
|
||||
beforeSetAnnotation(node);
|
||||
|
||||
// Cache the most recently requested value.
|
||||
lastSourceMapRangeNode = node;
|
||||
lastSourceMapRange = range;
|
||||
node.sourceMapRange = range;
|
||||
return node;
|
||||
}
|
||||
|
||||
function getTokenSourceMapRanges(node: Node) {
|
||||
/**
|
||||
* Gets the TextRange to use for source maps for a token of a node.
|
||||
*
|
||||
* If a node does not have its own custom source map text range for a token, the custom
|
||||
* source map text range for the token of its original pointer is used.
|
||||
*
|
||||
* @param node The node.
|
||||
* @param token The token.
|
||||
*/
|
||||
function getTokenSourceMapRange(node: Node, token: SyntaxKind) {
|
||||
// As a performance optimization, use the cached value of the most recent node.
|
||||
// This helps for cases where this function is called repeatedly for the same node.
|
||||
if (lastTokenSourceMapRangeNode === node && lastTokenSourceMapRangeToken === token) {
|
||||
return lastTokenSourceMapRange;
|
||||
}
|
||||
|
||||
// Get the custom token source map range for a node or from one of its original nodes.
|
||||
// Custom token ranges are not stored on the node to avoid the GC burden.
|
||||
let range: TextRange;
|
||||
let current = node;
|
||||
while (current) {
|
||||
const options = getEmitOptions(current);
|
||||
if (options && options.tokenSourceMapRange) {
|
||||
return options.tokenSourceMapRange;
|
||||
range = current.id ? tokenSourceMapRanges[current.id + "-" + token] : undefined;
|
||||
if (range !== undefined) {
|
||||
break;
|
||||
}
|
||||
|
||||
current = current.original;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the TextRange to use for source maps for a token of a node.
|
||||
*/
|
||||
function getTokenSourceMapRange(node: Node, token: SyntaxKind) {
|
||||
const ranges = getTokenSourceMapRanges(node);
|
||||
if (ranges) {
|
||||
return ranges[token];
|
||||
}
|
||||
|
||||
return undefined;
|
||||
// Cache the most recently requested value.
|
||||
lastTokenSourceMapRangeNode = node;
|
||||
lastTokenSourceMapRangeToken = token;
|
||||
lastTokenSourceMapRange = range;
|
||||
return range;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the TextRange to use for source maps for a token of a node.
|
||||
*
|
||||
* @param node The node.
|
||||
* @param token The token.
|
||||
* @param range The text range.
|
||||
*/
|
||||
function setTokenSourceMapRange<T extends Node>(node: T, token: SyntaxKind, range: TextRange) {
|
||||
const options = getEmitOptions(node, /*create*/ true);
|
||||
if (!options.tokenSourceMapRange) {
|
||||
const existingRanges = getTokenSourceMapRanges(node);
|
||||
const ranges = existingRanges ? clone(existingRanges) : { };
|
||||
options.tokenSourceMapRange = ranges;
|
||||
}
|
||||
|
||||
options.tokenSourceMapRange[token] = range;
|
||||
// Cache the most recently requested value.
|
||||
lastTokenSourceMapRangeNode = node;
|
||||
lastTokenSourceMapRangeToken = token;
|
||||
lastTokenSourceMapRange = range;
|
||||
tokenSourceMapRanges[getNodeId(node) + "-" + token] = range;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a custom text range to use when emitting comments.
|
||||
*
|
||||
* If a node does not have its own custom source map text range, the custom source map
|
||||
* text range of its original pointer is used.
|
||||
*
|
||||
* @param node The node.
|
||||
*/
|
||||
function getCommentRange(node: Node) {
|
||||
// As a performance optimization, use the cached value of the most recent node.
|
||||
// This helps for cases where this function is called repeatedly for the same node.
|
||||
if (lastCommentMapRangeNode === node) {
|
||||
return lastCommentMapRange || node;
|
||||
}
|
||||
|
||||
// Get the custom comment range for a node or from one of its original nodes.
|
||||
let range: TextRange;
|
||||
let current = node;
|
||||
while (current) {
|
||||
const options = getEmitOptions(current, /*create*/ false);
|
||||
if (options && options.commentRange !== undefined) {
|
||||
return options.commentRange;
|
||||
if (current.transformId === transformId) {
|
||||
range = current.commentRange;
|
||||
if (range !== undefined) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
current = current.original;
|
||||
}
|
||||
|
||||
return node;
|
||||
// Cache the most recently requested value.
|
||||
lastCommentMapRangeNode = node;
|
||||
lastCommentMapRange = range;
|
||||
return range || node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom text range to use when emitting comments.
|
||||
*/
|
||||
function setCommentRange<T extends Node>(node: T, range: TextRange) {
|
||||
getEmitOptions(node, /*create*/ true).commentRange = range;
|
||||
beforeSetAnnotation(node);
|
||||
|
||||
// Cache the most recently requested value.
|
||||
lastCommentMapRangeNode = node;
|
||||
lastCommentMapRange = range;
|
||||
node.commentRange = range;
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
@ -251,7 +251,9 @@ namespace ts {
|
||||
emitArrayLiteralAssignment(<ArrayLiteralExpression>target, value, location);
|
||||
}
|
||||
else {
|
||||
const name = getSynthesizedClone(<Identifier>target, { sourceMapRange: target, commentRange: target });
|
||||
const name = getMutableClone(<Identifier>target);
|
||||
context.setSourceMapRange(name, target);
|
||||
context.setCommentRange(name, target);
|
||||
emitAssignment(name, value, location, /*original*/ undefined);
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,7 +164,7 @@ namespace ts {
|
||||
let currentNode: Node;
|
||||
let enclosingBlockScopeContainer: Node;
|
||||
let enclosingBlockScopeContainerParent: Node;
|
||||
let containingNonArrowFunction: FunctionLikeDeclaration;
|
||||
let containingNonArrowFunction: FunctionLikeDeclaration | ClassElement;
|
||||
|
||||
/**
|
||||
* Used to track if we are emitting body of the converted loop
|
||||
@ -1003,7 +1003,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// `declarationName` is the name of the local declaration for the parameter.
|
||||
const declarationName = getUniqueClone(<Identifier>parameter.name);
|
||||
const declarationName = getMutableClone(<Identifier>parameter.name);
|
||||
setNodeEmitFlags(declarationName, NodeEmitFlags.NoSourceMap);
|
||||
|
||||
// `expressionName` is the name of the parameter used in expressions.
|
||||
@ -1150,6 +1150,7 @@ namespace ts {
|
||||
createMemberAccessForPropertyName(
|
||||
receiver,
|
||||
visitNode(member.name, visitor, isPropertyName),
|
||||
setNodeEmitFlags,
|
||||
/*location*/ member.name
|
||||
),
|
||||
func
|
||||
@ -2311,7 +2312,8 @@ namespace ts {
|
||||
return createAssignment(
|
||||
createMemberAccessForPropertyName(
|
||||
receiver,
|
||||
visitNode(property.name, visitor, isPropertyName)
|
||||
visitNode(property.name, visitor, isPropertyName),
|
||||
setNodeEmitFlags
|
||||
),
|
||||
visitNode(property.initializer, visitor, isExpression),
|
||||
/*location*/ property
|
||||
@ -2329,7 +2331,8 @@ namespace ts {
|
||||
return createAssignment(
|
||||
createMemberAccessForPropertyName(
|
||||
receiver,
|
||||
visitNode(property.name, visitor, isPropertyName)
|
||||
visitNode(property.name, visitor, isPropertyName),
|
||||
setNodeEmitFlags
|
||||
),
|
||||
getSynthesizedClone(property.name),
|
||||
/*location*/ property
|
||||
@ -2347,7 +2350,8 @@ namespace ts {
|
||||
return createAssignment(
|
||||
createMemberAccessForPropertyName(
|
||||
receiver,
|
||||
visitNode(method.name, visitor, isPropertyName)
|
||||
visitNode(method.name, visitor, isPropertyName),
|
||||
setNodeEmitFlags
|
||||
),
|
||||
transformFunctionLikeToExpression(method, /*location*/ method, /*name*/ undefined),
|
||||
/*location*/ method
|
||||
@ -2912,7 +2916,7 @@ namespace ts {
|
||||
*/
|
||||
function getDeclarationName(node: DeclarationStatement | ClassExpression, allowComments?: boolean, allowSourceMaps?: boolean, emitFlags?: NodeEmitFlags) {
|
||||
if (node.name && !isGeneratedIdentifier(node.name)) {
|
||||
const name = getUniqueClone(node.name);
|
||||
const name = getMutableClone(node.name);
|
||||
emitFlags |= getNodeEmitFlags(node.name);
|
||||
if (!allowSourceMaps) {
|
||||
emitFlags |= NodeEmitFlags.NoSourceMap;
|
||||
|
||||
@ -100,7 +100,7 @@ namespace ts {
|
||||
exportFunctionForFile = createUniqueName("exports");
|
||||
contextObjectForFile = createUniqueName("context");
|
||||
|
||||
exportFunctionForFileMap[getNodeId(node)] = exportFunctionForFile;
|
||||
exportFunctionForFileMap[getOriginalNodeId(node)] = exportFunctionForFile;
|
||||
|
||||
const dependencyGroups = collectDependencyGroups(externalImports);
|
||||
|
||||
@ -968,7 +968,7 @@ namespace ts {
|
||||
|
||||
function onEmitNode(node: Node, emit: (node: Node) => void): void {
|
||||
if (node.kind === SyntaxKind.SourceFile) {
|
||||
exportFunctionForFile = exportFunctionForFileMap[getNodeId(node)];
|
||||
exportFunctionForFile = exportFunctionForFileMap[getOriginalNodeId(node)];
|
||||
previousOnEmitNode(node, emit);
|
||||
exportFunctionForFile = undefined;
|
||||
}
|
||||
|
||||
@ -1034,7 +1034,7 @@ namespace ts {
|
||||
function transformInitializedProperty(node: ClassExpression | ClassDeclaration, property: PropertyDeclaration, receiver: LeftHandSideExpression) {
|
||||
const propertyName = visitPropertyNameOfClassElement(property);
|
||||
const initializer = visitNode(property.initializer, visitor, isExpression);
|
||||
const memberAccess = createMemberAccessForPropertyName(receiver, propertyName, /*location*/ propertyName);
|
||||
const memberAccess = createMemberAccessForPropertyName(receiver, propertyName, setNodeEmitFlags, /*location*/ propertyName);
|
||||
if (!isComputedPropertyName(propertyName)) {
|
||||
setNodeEmitFlags(memberAccess, NodeEmitFlags.NoNestedSourceMaps);
|
||||
}
|
||||
@ -1753,7 +1753,10 @@ namespace ts {
|
||||
function serializeEntityNameAsExpression(node: EntityName, useFallback: boolean): Expression {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
// Create a clone of the name with a new parent, and treat it as if it were
|
||||
// a source tree node for the purposes of the checker.
|
||||
const name = getMutableClone(<Identifier>node);
|
||||
name.flags &= ~NodeFlags.Synthesized;
|
||||
name.original = undefined;
|
||||
name.parent = currentScope;
|
||||
if (useFallback) {
|
||||
@ -2714,6 +2717,11 @@ namespace ts {
|
||||
&& resolver.isTopLevelValueImportEqualsWithEntityName(node));
|
||||
}
|
||||
|
||||
function disableCommentsRecursive(node: Node) {
|
||||
setNodeEmitFlags(node, NodeEmitFlags.NoComments | NodeEmitFlags.Merge);
|
||||
forEachChild(node, disableCommentsRecursive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an import equals declaration.
|
||||
*
|
||||
@ -2728,7 +2736,8 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const moduleReference = createExpressionFromEntityName(<EntityName>node.moduleReference, { flags: NodeEmitFlags.NoComments });
|
||||
const moduleReference = createExpressionFromEntityName(<EntityName>node.moduleReference);
|
||||
disableCommentsRecursive(moduleReference);
|
||||
if (isNamedExternalModuleExport(node) || !isNamespaceExport(node)) {
|
||||
// export var ${name} = ${moduleReference};
|
||||
// var ${name} = ${moduleReference};
|
||||
@ -2913,7 +2922,7 @@ namespace ts {
|
||||
*/
|
||||
function getDeclarationName(node: DeclarationStatement | ClassExpression, allowComments?: boolean, allowSourceMaps?: boolean, emitFlags?: NodeEmitFlags) {
|
||||
if (node.name) {
|
||||
const name = getUniqueClone(node.name);
|
||||
const name = getMutableClone(node.name);
|
||||
emitFlags |= getNodeEmitFlags(node.name);
|
||||
if (!allowSourceMaps) {
|
||||
emitFlags |= NodeEmitFlags.NoSourceMap;
|
||||
@ -3150,9 +3159,12 @@ namespace ts {
|
||||
// behavior of class names in ES6.
|
||||
const declaration = resolver.getReferencedValueDeclaration(node);
|
||||
if (declaration) {
|
||||
const classAlias = currentDecoratedClassAliases[getNodeId(declaration)];
|
||||
const classAlias = currentDecoratedClassAliases[getOriginalNodeId(declaration)];
|
||||
if (classAlias) {
|
||||
return getSynthesizedClone(classAlias, { sourceMapRange: node, commentRange: node });
|
||||
const clone = getSynthesizedClone(classAlias);
|
||||
setSourceMapRange(clone, node);
|
||||
setCommentRange(clone, node);
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,7 +238,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function reportStatisticalValue(name: string, value: string) {
|
||||
sys.write(padRight(name + ":", 12) + padLeft(value.toString(), 10) + sys.newLine);
|
||||
sys.write(padRight(name + ":", 20) + padLeft(value.toString(), 10) + sys.newLine);
|
||||
}
|
||||
|
||||
function reportCountStatistic(name: string, count: number) {
|
||||
@ -544,12 +544,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function compile(fileNames: string[], compilerOptions: CompilerOptions, compilerHost: CompilerHost) {
|
||||
ioReadTime = 0;
|
||||
ioWriteTime = 0;
|
||||
programTime = 0;
|
||||
bindTime = 0;
|
||||
checkTime = 0;
|
||||
emitTime = 0;
|
||||
if (compilerOptions.diagnostics || compilerOptions.extendedDiagnostics) {
|
||||
performance.enable();
|
||||
}
|
||||
|
||||
const program = createProgram(fileNames, compilerOptions, compilerHost);
|
||||
const exitStatus = compileProgram();
|
||||
@ -560,7 +557,7 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
if (compilerOptions.diagnostics) {
|
||||
if (compilerOptions.diagnostics || compilerOptions.extendedDiagnostics) {
|
||||
const memoryUsed = sys.getMemoryUsage ? sys.getMemoryUsage() : -1;
|
||||
reportCountStatistic("Files", program.getSourceFiles().length);
|
||||
reportCountStatistic("Lines", countLines(program));
|
||||
@ -573,17 +570,29 @@ namespace ts {
|
||||
reportStatisticalValue("Memory used", Math.round(memoryUsed / 1000) + "K");
|
||||
}
|
||||
|
||||
if (compilerOptions.extendedDiagnostics) {
|
||||
reportTimeStatistic("Print time", performance.getDuration("printTime"));
|
||||
reportTimeStatistic("Comment time", performance.getDuration("commentTime"));
|
||||
reportTimeStatistic("SourceMap time", performance.getDuration("sourceMapTime"));
|
||||
}
|
||||
|
||||
// Individual component times.
|
||||
// Note: To match the behavior of previous versions of the compiler, the reported parse time includes
|
||||
// I/O read time and processing time for triple-slash references and module imports, and the reported
|
||||
// emit time includes I/O write time. We preserve this behavior so we can accurately compare times.
|
||||
reportTimeStatistic("I/O read", ioReadTime);
|
||||
reportTimeStatistic("I/O write", ioWriteTime);
|
||||
reportTimeStatistic("I/O read", performance.getDuration("ioReadTime"));
|
||||
reportTimeStatistic("I/O write", performance.getDuration("ioWriteTime"));
|
||||
const programTime = performance.getDuration("programTime");
|
||||
const bindTime = performance.getDuration("bindTime");
|
||||
const checkTime = performance.getDuration("checkTime");
|
||||
const emitTime = performance.getDuration("emitTime");
|
||||
reportTimeStatistic("Parse time", programTime);
|
||||
reportTimeStatistic("Bind time", bindTime);
|
||||
reportTimeStatistic("Check time", checkTime);
|
||||
reportTimeStatistic("Emit time", emitTime);
|
||||
reportTimeStatistic("Total time", programTime + bindTime + checkTime + emitTime);
|
||||
|
||||
performance.disable();
|
||||
}
|
||||
|
||||
return { program, exitStatus };
|
||||
|
||||
@ -383,6 +383,7 @@ namespace ts {
|
||||
Let = 1 << 0, // Variable declaration
|
||||
Const = 1 << 1, // Variable declaration
|
||||
NestedNamespace = 1 << 2, // Namespace declaration
|
||||
Synthesized = 1 << 3, // Node was synthesized during transformation
|
||||
Namespace = 1 << 12, // Namespace declaration
|
||||
ExportContext = 1 << 13, // Export context (initialized by binding)
|
||||
ContainsThis = 1 << 14, // Interface contains references to "this"
|
||||
@ -469,7 +470,10 @@ namespace ts {
|
||||
/* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding)
|
||||
/* @internal */ nextContainer?: Node; // Next container in declaration order (initialized by binding)
|
||||
/* @internal */ localSymbol?: Symbol; // Local symbol declared by node (initialized by binding only for exported nodes)
|
||||
/* @internal */ emitOptions?: NodeEmitOptions; // Options used to control node emit (used by transforms, should never be set directly on a source tree node)
|
||||
/* @internal */ transformId?: number; // Associates transient transformation properties with a specific transformation (initialized by transformation).
|
||||
/* @internal */ emitFlags?: NodeEmitFlags; // Transient emit flags for a synthesized node (initialized by transformation).
|
||||
/* @internal */ sourceMapRange?: TextRange; // Transient custom sourcemap range for a synthesized node (initialized by transformation).
|
||||
/* @internal */ commentRange?: TextRange; // Transient custom comment range for a synthesized node (initialized by transformation).
|
||||
}
|
||||
|
||||
export interface NodeArray<T extends Node> extends Array<T>, TextRange {
|
||||
@ -502,6 +506,7 @@ namespace ts {
|
||||
text: string; // Text of identifier (with escapes converted to characters)
|
||||
originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later
|
||||
/*@internal*/ autoGenerateKind?: GeneratedIdentifierKind; // Specifies whether to auto-generate the text for an identifier.
|
||||
/*@internal*/ autoGenerateId?: number; // Ensures unique generated identifiers get unique names, but clones get the same name.
|
||||
}
|
||||
|
||||
// Transient identifier node (marked by id === -1)
|
||||
@ -2475,6 +2480,7 @@ namespace ts {
|
||||
declaration?: boolean;
|
||||
declarationDir?: string;
|
||||
diagnostics?: boolean;
|
||||
/*@internal*/ extendedDiagnostics?: boolean;
|
||||
emitBOM?: boolean;
|
||||
help?: boolean;
|
||||
init?: boolean;
|
||||
@ -2955,26 +2961,8 @@ namespace ts {
|
||||
// align with the old emitter.
|
||||
SourceMapEmitOpenBraceAsToken = 1 << 21, // Emits the open brace of a block function body as a source mapped token.
|
||||
SourceMapAdjustRestParameterLoop = 1 << 22, // Emits adjusted source map positions for a ForStatement generated when transforming a rest parameter for ES5/3.
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface NodeEmitOptions {
|
||||
/**
|
||||
* Specifies a custom range to use when emitting source maps.
|
||||
*/
|
||||
sourceMapRange?: TextRange;
|
||||
/**
|
||||
* Specifies a custom range to use when emitting tokens of a node.
|
||||
*/
|
||||
tokenSourceMapRange?: Map<TextRange>;
|
||||
/**
|
||||
* Specifies a custom range to use when emitting comments.
|
||||
*/
|
||||
commentRange?: TextRange;
|
||||
/**
|
||||
* Specifies flags to use to customize emit.
|
||||
*/
|
||||
flags?: NodeEmitFlags;
|
||||
HasNodeEmitFlags = 1 << 31, // Indicates the node has emit flags set.
|
||||
}
|
||||
|
||||
/** Additional context provided to `visitEachChild` */
|
||||
@ -2987,99 +2975,6 @@ namespace ts {
|
||||
endLexicalEnvironment(): Statement[];
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface TransformationContext extends LexicalEnvironment {
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
getEmitResolver(): EmitResolver;
|
||||
getEmitHost(): EmitHost;
|
||||
|
||||
/**
|
||||
* Gets flags used to customize later transformations or emit.
|
||||
*/
|
||||
getNodeEmitFlags(node: Node): NodeEmitFlags;
|
||||
|
||||
/**
|
||||
* Sets flags used to customize later transformations or emit.
|
||||
*/
|
||||
setNodeEmitFlags<T extends Node>(node: T, flags: NodeEmitFlags): T;
|
||||
|
||||
/**
|
||||
* Gets the TextRange to use for source maps for the node.
|
||||
*/
|
||||
getSourceMapRange(node: Node): TextRange;
|
||||
|
||||
/**
|
||||
* Sets the TextRange to use for source maps for the node.
|
||||
*/
|
||||
setSourceMapRange<T extends Node>(node: T, range: TextRange): T;
|
||||
|
||||
/**
|
||||
* Gets the TextRange to use for source maps for a token of a node.
|
||||
*/
|
||||
getTokenSourceMapRange(node: Node, token: SyntaxKind): TextRange;
|
||||
|
||||
/**
|
||||
* Sets the TextRange to use for source maps for a token of a node.
|
||||
*/
|
||||
setTokenSourceMapRange<T extends Node>(node: T, token: SyntaxKind, range: TextRange): T;
|
||||
|
||||
/**
|
||||
* Gets the TextRange to use for comments for the node.
|
||||
*/
|
||||
getCommentRange(node: Node): TextRange;
|
||||
|
||||
/**
|
||||
* Sets the TextRange to use for comments for the node.
|
||||
*/
|
||||
setCommentRange<T extends Node>(node: T, range: TextRange): T;
|
||||
|
||||
/**
|
||||
* Hoists a function declaration to the containing scope.
|
||||
*/
|
||||
hoistFunctionDeclaration(node: FunctionDeclaration): void;
|
||||
|
||||
/**
|
||||
* Hoists a variable declaration to the containing scope.
|
||||
*/
|
||||
hoistVariableDeclaration(node: Identifier): void;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
isSubstitutionEnabled(node: Node): boolean;
|
||||
|
||||
/**
|
||||
* Hook used by transformers to substitute expressions just before they
|
||||
* are emitted by the pretty printer.
|
||||
*/
|
||||
onSubstituteNode?: (node: Node, isExpression: boolean) => Node;
|
||||
|
||||
/**
|
||||
* Enables before/after emit notifications in the pretty printer for the provided
|
||||
* SyntaxKind.
|
||||
*/
|
||||
enableEmitNotification(kind: SyntaxKind): void;
|
||||
|
||||
/**
|
||||
* Determines whether before/after emit notifications should be raised in the pretty
|
||||
* printer when it emits a node.
|
||||
*/
|
||||
isEmitNotificationEnabled(node: Node): boolean;
|
||||
|
||||
/**
|
||||
* Hook used to allow transformers to capture state before or after
|
||||
* the printer emits a node.
|
||||
*/
|
||||
onEmitNode?: (node: Node, emit: (node: Node) => void) => void;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export type Transformer = (context: TransformationContext) => (node: SourceFile) => SourceFile;
|
||||
|
||||
export interface TextSpan {
|
||||
start: number;
|
||||
|
||||
@ -207,18 +207,6 @@ namespace ts {
|
||||
return `${ file.fileName }(${ loc.line + 1 },${ loc.character + 1 })`;
|
||||
}
|
||||
|
||||
export function getEnvironmentVariable(name: string, host?: CompilerHost) {
|
||||
if (host && host.getEnvironmentVariable) {
|
||||
return host.getEnvironmentVariable(name);
|
||||
}
|
||||
|
||||
if (sys && sys.getEnvironmentVariable) {
|
||||
return sys.getEnvironmentVariable(name);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
export function getStartPosOfNode(node: Node): number {
|
||||
return node.pos;
|
||||
}
|
||||
@ -1831,14 +1819,17 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function isSourceTreeNode(node: Node): boolean {
|
||||
return node.original === undefined
|
||||
&& (node.parent !== undefined || node.kind === SyntaxKind.SourceFile);
|
||||
return (node.flags & NodeFlags.Synthesized) === 0;
|
||||
}
|
||||
|
||||
export function getSourceTreeNode(node: Node): Node {
|
||||
if (isSourceTreeNode(node)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
node = getOriginalNode(node);
|
||||
|
||||
if (node && (node.parent !== undefined || node.kind === SyntaxKind.SourceFile)) {
|
||||
if (isSourceTreeNode(node)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
@ -113,7 +113,7 @@ false = value;
|
||||
}
|
||||
value;
|
||||
// array literals
|
||||
"" = value[0], "" = value[1];
|
||||
'' = value[0], '' = value[1];
|
||||
// super
|
||||
var Derived = (function (_super) {
|
||||
__extends(Derived, _super);
|
||||
|
||||
@ -134,7 +134,7 @@ false = Math.pow(false, value);
|
||||
}
|
||||
value;
|
||||
// array literals
|
||||
_a = Math.pow(['', ''], value), "" = _a[0], "" = _a[1];
|
||||
_a = Math.pow(['', ''], value), '' = _a[0], '' = _a[1];
|
||||
// super
|
||||
var Derived = (function (_super) {
|
||||
__extends(Derived, _super);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user