mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge the comment writer back into the emitter to reduce stack size.
This commit is contained in:
+1
-64
@@ -82,70 +82,7 @@ var cancellationTokenSources = filesFromConfig(path.join(serverDirectory, "cance
|
||||
var typingsInstallerSources = filesFromConfig(path.join(serverDirectory, "typingsInstaller/tsconfig.json"));
|
||||
var serverSources = filesFromConfig(path.join(serverDirectory, "tsconfig.json"))
|
||||
var languageServiceLibrarySources = filesFromConfig(path.join(serverDirectory, "tsconfig.library.json"));
|
||||
|
||||
var harnessCoreSources = [
|
||||
"harness.ts",
|
||||
"virtualFileSystem.ts",
|
||||
"sourceMapRecorder.ts",
|
||||
"harnessLanguageService.ts",
|
||||
"fourslash.ts",
|
||||
"runnerbase.ts",
|
||||
"compilerRunner.ts",
|
||||
"typeWriter.ts",
|
||||
"fourslashRunner.ts",
|
||||
"projectsRunner.ts",
|
||||
"loggedIO.ts",
|
||||
"rwcRunner.ts",
|
||||
"test262Runner.ts",
|
||||
"runner.ts"
|
||||
].map(function (f) {
|
||||
return path.join(harnessDirectory, f);
|
||||
});
|
||||
|
||||
var harnessSources = harnessCoreSources.concat([
|
||||
"incrementalParser.ts",
|
||||
"jsDocParsing.ts",
|
||||
"services/colorization.ts",
|
||||
"services/documentRegistry.ts",
|
||||
"services/preProcessFile.ts",
|
||||
"services/patternMatcher.ts",
|
||||
"session.ts",
|
||||
"versionCache.ts",
|
||||
"convertToBase64.ts",
|
||||
"transpile.ts",
|
||||
"reuseProgramStructure.ts",
|
||||
"textStorage.ts",
|
||||
"cachingInServerLSHost.ts",
|
||||
"moduleResolution.ts",
|
||||
"tsconfigParsing.ts",
|
||||
"commandLineParsing.ts",
|
||||
"configurationExtension.ts",
|
||||
"convertCompilerOptionsFromJson.ts",
|
||||
"convertTypeAcquisitionFromJson.ts",
|
||||
"tsserverProjectSystem.ts",
|
||||
"compileOnSave.ts",
|
||||
"typingsInstaller.ts",
|
||||
"projectErrors.ts",
|
||||
"matchFiles.ts",
|
||||
"initializeTSConfig.ts",
|
||||
"printer.ts",
|
||||
"transform.ts",
|
||||
"customTransforms.ts",
|
||||
].map(function (f) {
|
||||
return path.join(unittestsDirectory, f);
|
||||
})).concat([
|
||||
"protocol.ts",
|
||||
"utilities.ts",
|
||||
"scriptVersionCache.ts",
|
||||
"scriptInfo.ts",
|
||||
"lsHost.ts",
|
||||
"project.ts",
|
||||
"typingsCache.ts",
|
||||
"editorServices.ts",
|
||||
"session.ts",
|
||||
].map(function (f) {
|
||||
return path.join(serverDirectory, f);
|
||||
}));
|
||||
var harnessSources = filesFromConfig("./src/harness/tsconfig.json");
|
||||
|
||||
var es2015LibrarySources = [
|
||||
"es2015.core.d.ts",
|
||||
|
||||
@@ -1,429 +0,0 @@
|
||||
/// <reference path="sourcemap.ts" />
|
||||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export interface CommentWriter {
|
||||
reset(): void;
|
||||
setSourceFile(sourceFile: SourceFile): void;
|
||||
setWriter(writer: EmitTextWriter): void;
|
||||
emitNodeWithComments(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
|
||||
emitBodyWithDetachedComments(node: Node, detachedRange: TextRange, emitCallback: (node: Node) => void): void;
|
||||
emitTrailingCommentsOfPosition(pos: number): void;
|
||||
emitLeadingCommentsOfPosition(pos: number): void;
|
||||
}
|
||||
|
||||
export function createCommentWriter(printerOptions: PrinterOptions, emitPos: ((pos: number) => void) | undefined): CommentWriter {
|
||||
const extendedDiagnostics = printerOptions.extendedDiagnostics;
|
||||
const newLine = getNewLineCharacter(printerOptions);
|
||||
let writer: EmitTextWriter;
|
||||
let containerPos = -1;
|
||||
let containerEnd = -1;
|
||||
let declarationListContainerEnd = -1;
|
||||
let currentSourceFile: SourceFile;
|
||||
let currentText: string;
|
||||
let currentLineMap: number[];
|
||||
let detachedCommentsInfo: { nodePos: number, detachedCommentEndPos: number}[];
|
||||
let hasWrittenComment = false;
|
||||
let disabled: boolean = printerOptions.removeComments;
|
||||
|
||||
return {
|
||||
reset,
|
||||
setWriter,
|
||||
setSourceFile,
|
||||
emitNodeWithComments,
|
||||
emitBodyWithDetachedComments,
|
||||
emitTrailingCommentsOfPosition,
|
||||
emitLeadingCommentsOfPosition,
|
||||
};
|
||||
|
||||
function emitNodeWithComments(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
|
||||
if (disabled) {
|
||||
emitCallback(hint, node);
|
||||
return;
|
||||
}
|
||||
|
||||
if (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.
|
||||
emitNodeWithSynthesizedComments(hint, node, emitNode, emitFlags, emitCallback);
|
||||
}
|
||||
else {
|
||||
if (extendedDiagnostics) {
|
||||
performance.mark("preEmitNodeWithComment");
|
||||
}
|
||||
|
||||
const isEmittedNode = node.kind !== SyntaxKind.NotEmittedStatement;
|
||||
const skipLeadingComments = pos < 0 || (emitFlags & EmitFlags.NoLeadingComments) !== 0;
|
||||
const skipTrailingComments = end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0;
|
||||
|
||||
// Emit leading comments if the position is not synthesized and the node
|
||||
// has not opted out from emitting leading comments.
|
||||
if (!skipLeadingComments) {
|
||||
emitLeadingComments(pos, isEmittedNode);
|
||||
}
|
||||
|
||||
// Save current container state on the stack.
|
||||
const savedContainerPos = containerPos;
|
||||
const savedContainerEnd = containerEnd;
|
||||
const savedDeclarationListContainerEnd = declarationListContainerEnd;
|
||||
|
||||
if (!skipLeadingComments) {
|
||||
containerPos = pos;
|
||||
}
|
||||
|
||||
if (!skipTrailingComments) {
|
||||
containerEnd = end;
|
||||
|
||||
// To avoid invalid comment emit in a down-level binding pattern, we
|
||||
// keep track of the last declaration list container's end
|
||||
if (node.kind === SyntaxKind.VariableDeclarationList) {
|
||||
declarationListContainerEnd = end;
|
||||
}
|
||||
}
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.measure("commentTime", "preEmitNodeWithComment");
|
||||
}
|
||||
|
||||
emitNodeWithSynthesizedComments(hint, node, emitNode, emitFlags, emitCallback);
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.mark("postEmitNodeWithComment");
|
||||
}
|
||||
|
||||
// Restore previous container state.
|
||||
containerPos = savedContainerPos;
|
||||
containerEnd = savedContainerEnd;
|
||||
declarationListContainerEnd = savedDeclarationListContainerEnd;
|
||||
|
||||
// Emit trailing comments if the position is not synthesized and the node
|
||||
// has not opted out from emitting leading comments and is an emitted node.
|
||||
if (!skipTrailingComments && isEmittedNode) {
|
||||
emitTrailingComments(end);
|
||||
}
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
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");
|
||||
}
|
||||
|
||||
const { pos, end } = detachedRange;
|
||||
const emitFlags = getEmitFlags(node);
|
||||
const skipLeadingComments = pos < 0 || (emitFlags & EmitFlags.NoLeadingComments) !== 0;
|
||||
const skipTrailingComments = disabled || end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0;
|
||||
|
||||
if (!skipLeadingComments) {
|
||||
emitDetachedCommentsAndUpdateCommentsInfo(detachedRange);
|
||||
}
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.measure("commentTime", "preEmitBodyWithDetachedComments");
|
||||
}
|
||||
|
||||
if (emitFlags & EmitFlags.NoNestedComments && !disabled) {
|
||||
disabled = true;
|
||||
emitCallback(node);
|
||||
disabled = false;
|
||||
}
|
||||
else {
|
||||
emitCallback(node);
|
||||
}
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.mark("beginEmitBodyWithDetachedCommetns");
|
||||
}
|
||||
|
||||
if (!skipTrailingComments) {
|
||||
emitLeadingComments(detachedRange.end, /*isEmittedNode*/ true);
|
||||
if (hasWrittenComment && !writer.isAtStartOfLine()) {
|
||||
writer.writeLine();
|
||||
}
|
||||
}
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.measure("commentTime", "beginEmitBodyWithDetachedCommetns");
|
||||
}
|
||||
}
|
||||
|
||||
function emitLeadingComments(pos: number, isEmittedNode: boolean) {
|
||||
hasWrittenComment = false;
|
||||
|
||||
if (isEmittedNode) {
|
||||
forEachLeadingCommentToEmit(pos, emitLeadingComment);
|
||||
}
|
||||
else if (pos === 0) {
|
||||
// If the node will not be emitted in JS, remove all the comments(normal, pinned and ///) associated with the node,
|
||||
// unless it is a triple slash comment at the top of the file.
|
||||
// For Example:
|
||||
// /// <reference-path ...>
|
||||
// declare var x;
|
||||
// /// <reference-path ...>
|
||||
// interface F {}
|
||||
// The first /// will NOT be removed while the second one will be removed even though both node will not be emitted
|
||||
forEachLeadingCommentToEmit(pos, emitTripleSlashLeadingComment);
|
||||
}
|
||||
}
|
||||
|
||||
function emitTripleSlashLeadingComment(commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) {
|
||||
if (isTripleSlashComment(commentPos, commentEnd)) {
|
||||
emitLeadingComment(commentPos, commentEnd, kind, hasTrailingNewLine, rangePos);
|
||||
}
|
||||
}
|
||||
|
||||
function emitLeadingComment(commentPos: number, commentEnd: number, _kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) {
|
||||
if (!hasWrittenComment) {
|
||||
emitNewLineBeforeLeadingCommentOfPosition(currentLineMap, writer, rangePos, commentPos);
|
||||
hasWrittenComment = true;
|
||||
}
|
||||
|
||||
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
|
||||
if (emitPos) emitPos(commentPos);
|
||||
writeCommentRange(currentText, currentLineMap, writer, commentPos, commentEnd, newLine);
|
||||
if (emitPos) emitPos(commentEnd);
|
||||
|
||||
if (hasTrailingNewLine) {
|
||||
writer.writeLine();
|
||||
}
|
||||
else {
|
||||
writer.write(" ");
|
||||
}
|
||||
}
|
||||
|
||||
function emitLeadingCommentsOfPosition(pos: number) {
|
||||
if (disabled || pos === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
emitLeadingComments(pos, /*isEmittedNode*/ true);
|
||||
}
|
||||
|
||||
function emitTrailingComments(pos: number) {
|
||||
forEachTrailingCommentToEmit(pos, emitTrailingComment);
|
||||
}
|
||||
|
||||
function emitTrailingComment(commentPos: number, commentEnd: number, _kind: SyntaxKind, hasTrailingNewLine: boolean) {
|
||||
// trailing comments are emitted at space/*trailing comment1 */space/*trailing comment2*/
|
||||
if (!writer.isAtStartOfLine()) {
|
||||
writer.write(" ");
|
||||
}
|
||||
|
||||
if (emitPos) emitPos(commentPos);
|
||||
writeCommentRange(currentText, currentLineMap, writer, commentPos, commentEnd, newLine);
|
||||
if (emitPos) emitPos(commentEnd);
|
||||
|
||||
if (hasTrailingNewLine) {
|
||||
writer.writeLine();
|
||||
}
|
||||
}
|
||||
|
||||
function emitTrailingCommentsOfPosition(pos: number) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.mark("beforeEmitTrailingCommentsOfPosition");
|
||||
}
|
||||
|
||||
forEachTrailingCommentToEmit(pos, emitTrailingCommentOfPosition);
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.measure("commentTime", "beforeEmitTrailingCommentsOfPosition");
|
||||
}
|
||||
}
|
||||
|
||||
function emitTrailingCommentOfPosition(commentPos: number, commentEnd: number, _kind: SyntaxKind, hasTrailingNewLine: boolean) {
|
||||
// trailing comments of a position are emitted at /*trailing comment1 */space/*trailing comment*/space
|
||||
|
||||
if (emitPos) emitPos(commentPos);
|
||||
writeCommentRange(currentText, currentLineMap, writer, commentPos, commentEnd, newLine);
|
||||
if (emitPos) emitPos(commentEnd);
|
||||
|
||||
if (hasTrailingNewLine) {
|
||||
writer.writeLine();
|
||||
}
|
||||
else {
|
||||
writer.write(" ");
|
||||
}
|
||||
}
|
||||
|
||||
function forEachLeadingCommentToEmit(pos: number, cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) => void) {
|
||||
// Emit the leading comments only if the container's pos doesn't match because the container should take care of emitting these comments
|
||||
if (containerPos === -1 || pos !== containerPos) {
|
||||
if (hasDetachedComments(pos)) {
|
||||
forEachLeadingCommentWithoutDetachedComments(cb);
|
||||
}
|
||||
else {
|
||||
forEachLeadingCommentRange(currentText, pos, cb, /*state*/ pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function forEachTrailingCommentToEmit(end: number, cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean) => void) {
|
||||
// Emit the trailing comments only if the container's end doesn't match because the container should take care of emitting these comments
|
||||
if (containerEnd === -1 || (end !== containerEnd && end !== declarationListContainerEnd)) {
|
||||
forEachTrailingCommentRange(currentText, end, cb);
|
||||
}
|
||||
}
|
||||
|
||||
function reset() {
|
||||
currentSourceFile = undefined;
|
||||
currentText = undefined;
|
||||
currentLineMap = undefined;
|
||||
detachedCommentsInfo = undefined;
|
||||
}
|
||||
|
||||
function setWriter(output: EmitTextWriter): void {
|
||||
writer = output;
|
||||
}
|
||||
|
||||
function setSourceFile(sourceFile: SourceFile) {
|
||||
currentSourceFile = sourceFile;
|
||||
currentText = currentSourceFile.text;
|
||||
currentLineMap = getLineStarts(currentSourceFile);
|
||||
detachedCommentsInfo = undefined;
|
||||
}
|
||||
|
||||
function hasDetachedComments(pos: number) {
|
||||
return detachedCommentsInfo !== undefined && lastOrUndefined(detachedCommentsInfo).nodePos === pos;
|
||||
}
|
||||
|
||||
function forEachLeadingCommentWithoutDetachedComments(cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) => void) {
|
||||
// get the leading comments from detachedPos
|
||||
const pos = lastOrUndefined(detachedCommentsInfo).detachedCommentEndPos;
|
||||
if (detachedCommentsInfo.length - 1) {
|
||||
detachedCommentsInfo.pop();
|
||||
}
|
||||
else {
|
||||
detachedCommentsInfo = undefined;
|
||||
}
|
||||
|
||||
forEachLeadingCommentRange(currentText, pos, cb, /*state*/ pos);
|
||||
}
|
||||
|
||||
function emitDetachedCommentsAndUpdateCommentsInfo(range: TextRange) {
|
||||
const currentDetachedCommentInfo = emitDetachedComments(currentText, currentLineMap, writer, writeComment, range, newLine, disabled);
|
||||
if (currentDetachedCommentInfo) {
|
||||
if (detachedCommentsInfo) {
|
||||
detachedCommentsInfo.push(currentDetachedCommentInfo);
|
||||
}
|
||||
else {
|
||||
detachedCommentsInfo = [currentDetachedCommentInfo];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeComment(text: string, lineMap: number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) {
|
||||
if (emitPos) emitPos(commentPos);
|
||||
writeCommentRange(text, lineMap, writer, commentPos, commentEnd, newLine);
|
||||
if (emitPos) emitPos(commentEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given comment is a triple-slash
|
||||
*
|
||||
* @return true if the comment is a triple-slash comment else false
|
||||
**/
|
||||
function isTripleSlashComment(commentPos: number, commentEnd: number) {
|
||||
// Verify this is /// comment, but do the regexp match only when we first can find /// in the comment text
|
||||
// so that we don't end up computing comment string and doing match for all // comments
|
||||
if (currentText.charCodeAt(commentPos + 1) === CharacterCodes.slash &&
|
||||
commentPos + 2 < commentEnd &&
|
||||
currentText.charCodeAt(commentPos + 2) === CharacterCodes.slash) {
|
||||
const textSubStr = currentText.substring(commentPos, commentEnd);
|
||||
return textSubStr.match(fullTripleSlashReferencePathRegEx) ||
|
||||
textSubStr.match(fullTripleSlashAMDReferencePathRegEx) ?
|
||||
true : false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+419
-76
@@ -2,7 +2,6 @@
|
||||
/// <reference path="transformer.ts" />
|
||||
/// <reference path="declarationEmitter.ts" />
|
||||
/// <reference path="sourcemap.ts" />
|
||||
/// <reference path="comments.ts" />
|
||||
|
||||
namespace ts {
|
||||
const delimiters = createDelimiterMap();
|
||||
@@ -194,24 +193,19 @@ namespace ts {
|
||||
hasGlobalName,
|
||||
onEmitSourceMapOfNode,
|
||||
onEmitSourceMapOfToken,
|
||||
onEmitSourceMapOfPosition,
|
||||
onEmitSourceMapOfPosition: emitPos,
|
||||
onEmitNode,
|
||||
onEmitHelpers,
|
||||
onSetSourceFile,
|
||||
substituteNode,
|
||||
} = handlers;
|
||||
|
||||
const extendedDiagnostics = printerOptions.extendedDiagnostics;
|
||||
const newLine = getNewLineCharacter(printerOptions);
|
||||
const languageVersion = getEmitScriptTarget(printerOptions);
|
||||
const comments = createCommentWriter(printerOptions, onEmitSourceMapOfPosition);
|
||||
const {
|
||||
emitNodeWithComments,
|
||||
emitBodyWithDetachedComments,
|
||||
emitTrailingCommentsOfPosition,
|
||||
emitLeadingCommentsOfPosition,
|
||||
} = comments;
|
||||
|
||||
let currentSourceFile: SourceFile;
|
||||
let currentText: string;
|
||||
let nodeIdToGeneratedName: string[]; // Map of generated names for specific nodes.
|
||||
let autoGeneratedIdToGeneratedName: string[]; // Map of generated names for temp and loop variables.
|
||||
let generatedNames: Map<string>; // Set of names generated by the NameGenerator.
|
||||
@@ -219,6 +213,13 @@ namespace ts {
|
||||
let tempFlags: TempFlags; // TempFlags for the current name generation scope.
|
||||
let writer: EmitTextWriter;
|
||||
let ownWriter: EmitTextWriter;
|
||||
let containerPos = -1;
|
||||
let containerEnd = -1;
|
||||
let declarationListContainerEnd = -1;
|
||||
let currentLineMap: number[];
|
||||
let detachedCommentsInfo: { nodePos: number, detachedCommentEndPos: number}[];
|
||||
let hasWrittenComment = false;
|
||||
let disabled: boolean = printerOptions.removeComments;
|
||||
|
||||
reset();
|
||||
return {
|
||||
@@ -302,12 +303,14 @@ namespace ts {
|
||||
|
||||
function print(hint: EmitHint, node: Node, sourceFile: SourceFile) {
|
||||
setSourceFile(sourceFile);
|
||||
pipelineEmitWithNotification(hint, node);
|
||||
pipelineEmit(hint, node);
|
||||
}
|
||||
|
||||
function setSourceFile(sourceFile: SourceFile) {
|
||||
currentSourceFile = sourceFile;
|
||||
comments.setSourceFile(sourceFile);
|
||||
currentText = currentSourceFile.text;
|
||||
currentLineMap = getLineStarts(currentSourceFile);
|
||||
detachedCommentsInfo = undefined;
|
||||
if (onSetSourceFile) {
|
||||
onSetSourceFile(sourceFile);
|
||||
}
|
||||
@@ -315,57 +318,73 @@ namespace ts {
|
||||
|
||||
function setWriter(output: EmitTextWriter | undefined) {
|
||||
writer = output;
|
||||
comments.setWriter(output);
|
||||
}
|
||||
|
||||
function reset() {
|
||||
setWriter(/*output*/ undefined);
|
||||
nodeIdToGeneratedName = [];
|
||||
autoGeneratedIdToGeneratedName = [];
|
||||
generatedNames = createMap<string>();
|
||||
tempFlagsStack = [];
|
||||
tempFlags = TempFlags.Auto;
|
||||
comments.reset();
|
||||
setWriter(/*output*/ undefined);
|
||||
currentSourceFile = undefined;
|
||||
currentText = undefined;
|
||||
currentLineMap = undefined;
|
||||
detachedCommentsInfo = undefined;
|
||||
}
|
||||
|
||||
function emit(node: Node) {
|
||||
pipelineEmitWithNotification(EmitHint.Unspecified, node);
|
||||
pipelineEmit(EmitHint.Unspecified, node);
|
||||
}
|
||||
|
||||
function emitIdentifierName(node: Identifier) {
|
||||
pipelineEmitWithNotification(EmitHint.IdentifierName, node);
|
||||
pipelineEmit(EmitHint.IdentifierName, node);
|
||||
}
|
||||
|
||||
function emitExpression(node: Expression) {
|
||||
pipelineEmitWithNotification(EmitHint.Expression, node);
|
||||
pipelineEmit(EmitHint.Expression, node);
|
||||
}
|
||||
|
||||
function pipelineEmit(hint: EmitHint, node: Node) {
|
||||
getInitialPhase(hint)(hint, trySubstituteNode(hint, node));
|
||||
}
|
||||
|
||||
function getInitialPhase(hint: EmitHint) {
|
||||
return !shouldSkipNotificationPhase() ? pipelineEmitWithNotification : getNextPhaseFollowingNotification(hint);
|
||||
}
|
||||
|
||||
function shouldSkipNotificationPhase() {
|
||||
return onEmitNode === undefined;
|
||||
}
|
||||
|
||||
function getNextPhaseFollowingNotification(hint: EmitHint) {
|
||||
return !shouldSkipCommentPhase(hint) ? emitNodeConsideringComments : getNextPhaseFollowingComments(hint);
|
||||
}
|
||||
|
||||
function shouldSkipCommentPhase(hint: EmitHint) {
|
||||
return disabled || hint === EmitHint.SourceFile;
|
||||
}
|
||||
|
||||
function getNextPhaseFollowingComments(hint: EmitHint) {
|
||||
return !shouldSkipSourceMapPhase(hint) ? pipelineEmitWithSourceMap : getNextPhaseFollowingSourceMap();
|
||||
}
|
||||
|
||||
function shouldSkipSourceMapPhase(hint: EmitHint) {
|
||||
return onEmitSourceMapOfNode === undefined
|
||||
|| hint === EmitHint.SourceFile
|
||||
|| hint === EmitHint.IdentifierName;
|
||||
}
|
||||
|
||||
function getNextPhaseFollowingSourceMap() {
|
||||
return pipelineEmitWithHint;
|
||||
}
|
||||
|
||||
function pipelineEmitWithNotification(hint: EmitHint, node: Node) {
|
||||
if (onEmitNode) {
|
||||
onEmitNode(hint, node, pipelineEmitWithComments);
|
||||
}
|
||||
else {
|
||||
pipelineEmitWithComments(hint, node);
|
||||
}
|
||||
}
|
||||
|
||||
function pipelineEmitWithComments(hint: EmitHint, node: Node) {
|
||||
node = trySubstituteNode(hint, node);
|
||||
if (emitNodeWithComments && hint !== EmitHint.SourceFile) {
|
||||
emitNodeWithComments(hint, node, pipelineEmitWithSourceMap);
|
||||
}
|
||||
else {
|
||||
pipelineEmitWithSourceMap(hint, node);
|
||||
}
|
||||
onEmitNode(hint, node, getNextPhaseFollowingNotification(hint));
|
||||
}
|
||||
|
||||
function pipelineEmitWithSourceMap(hint: EmitHint, node: Node) {
|
||||
if (onEmitSourceMapOfNode && hint !== EmitHint.SourceFile && hint !== EmitHint.IdentifierName) {
|
||||
onEmitSourceMapOfNode(hint, node, pipelineEmitWithHint);
|
||||
}
|
||||
else {
|
||||
pipelineEmitWithHint(hint, node);
|
||||
}
|
||||
onEmitSourceMapOfNode(hint, node, getNextPhaseFollowingSourceMap());
|
||||
}
|
||||
|
||||
function pipelineEmitWithHint(hint: EmitHint, node: Node): void {
|
||||
@@ -728,15 +747,6 @@ namespace ts {
|
||||
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);
|
||||
}
|
||||
else {
|
||||
emitCallback(node);
|
||||
}
|
||||
}
|
||||
|
||||
function emitHelpersIndirect(node: Node) {
|
||||
if (onEmitHelpers) {
|
||||
onEmitHelpers(node, writeLines);
|
||||
@@ -1635,26 +1645,30 @@ namespace ts {
|
||||
write(" {");
|
||||
increaseIndent();
|
||||
|
||||
const emitBlockFunctionBody = shouldEmitBlockFunctionBodyOnSingleLine(body)
|
||||
? emitBlockFunctionBodyOnSingleLine
|
||||
: emitBlockFunctionBodyWorker;
|
||||
const commentFlags = getEmitFlags(body);
|
||||
emitLeadingDetachedComments(body.statements, commentFlags);
|
||||
|
||||
emitBodyIndirect(body, body.statements, emitBlockFunctionBody);
|
||||
if (!disabled && (commentFlags & EmitFlags.NoNestedComments)) {
|
||||
disabled = true;
|
||||
emitBlockFunctionBodyWorker(body);
|
||||
disabled = false;
|
||||
}
|
||||
else {
|
||||
emitBlockFunctionBodyWorker(body);
|
||||
}
|
||||
|
||||
emitTrailingDetachedComments(body.statements, commentFlags);
|
||||
|
||||
decreaseIndent();
|
||||
writeToken(SyntaxKind.CloseBraceToken, body.statements.end, body);
|
||||
}
|
||||
|
||||
function emitBlockFunctionBodyOnSingleLine(body: Block) {
|
||||
emitBlockFunctionBodyWorker(body, /*emitBlockFunctionBodyOnSingleLine*/ true);
|
||||
}
|
||||
|
||||
function emitBlockFunctionBodyWorker(body: Block, emitBlockFunctionBodyOnSingleLine?: boolean) {
|
||||
function emitBlockFunctionBodyWorker(body: Block) {
|
||||
// Emit all the prologue directives (like "use strict").
|
||||
const statementOffset = emitPrologueDirectives(body.statements, /*startWithNewLine*/ true);
|
||||
const pos = writer.getTextPos();
|
||||
const statementOffset = emitPrologueDirectives(body.statements, /*startWithNewLine*/ true);
|
||||
emitHelpersIndirect(body);
|
||||
if (statementOffset === 0 && pos === writer.getTextPos() && emitBlockFunctionBodyOnSingleLine) {
|
||||
if (statementOffset === 0 && pos === writer.getTextPos() && shouldEmitBlockFunctionBodyOnSingleLine(body)) {
|
||||
decreaseIndent();
|
||||
emitList(body, body.statements, ListFormat.SingleLineFunctionBodyStatements);
|
||||
increaseIndent();
|
||||
@@ -2040,16 +2054,17 @@ namespace ts {
|
||||
function emitSourceFile(node: SourceFile) {
|
||||
writeLine();
|
||||
emitShebang();
|
||||
emitBodyIndirect(node, node.statements, emitSourceFileWorker);
|
||||
}
|
||||
|
||||
function emitSourceFileWorker(node: SourceFile) {
|
||||
const statements = node.statements;
|
||||
const statementOffset = emitPrologueDirectives(statements);
|
||||
const commentFlags = getEmitFlags(node);
|
||||
emitLeadingDetachedComments(node.statements, commentFlags);
|
||||
|
||||
const statementOffset = emitPrologueDirectives(node.statements);
|
||||
pushNameGenerationScope();
|
||||
emitHelpersIndirect(node);
|
||||
emitList(node, statements, ListFormat.MultiLine, statementOffset);
|
||||
emitList(node, node.statements, ListFormat.MultiLine, statementOffset);
|
||||
popNameGenerationScope();
|
||||
|
||||
emitTrailingDetachedComments(node.statements, commentFlags);
|
||||
}
|
||||
|
||||
// Transformation nodes
|
||||
@@ -2493,9 +2508,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function needsIndentation(parent: Node, node1: Node, node2: Node): boolean {
|
||||
parent = skipSynthesizedParentheses(parent);
|
||||
node1 = skipSynthesizedParentheses(node1);
|
||||
node2 = skipSynthesizedParentheses(node2);
|
||||
parent = skipOuterExpressions(parent, OuterExpressionKinds.SynthesizedParentheses);
|
||||
node1 = skipOuterExpressions(node1, OuterExpressionKinds.SynthesizedParentheses);
|
||||
node2 = skipOuterExpressions(node2, OuterExpressionKinds.SynthesizedParentheses);
|
||||
|
||||
// Always use a newline for synthesized code if the synthesizer desires it.
|
||||
if (node2.startsOnNewLine) {
|
||||
@@ -2518,14 +2533,6 @@ namespace ts {
|
||||
&& rangeEndIsOnSameLineAsRangeStart(block, block, currentSourceFile);
|
||||
}
|
||||
|
||||
function skipSynthesizedParentheses(node: Node) {
|
||||
while (node.kind === SyntaxKind.ParenthesizedExpression && nodeIsSynthesized(node)) {
|
||||
node = (<ParenthesizedExpression>node).expression;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function getTextOfNode(node: Node, includeTrivia?: boolean): string {
|
||||
if (isGeneratedIdentifier(node)) {
|
||||
return generateName(node);
|
||||
@@ -2557,6 +2564,10 @@ namespace ts {
|
||||
return getLiteralText(node, currentSourceFile, languageVersion);
|
||||
}
|
||||
|
||||
//
|
||||
// Name generation
|
||||
//
|
||||
|
||||
/**
|
||||
* Push a new name generation scope.
|
||||
*/
|
||||
@@ -2779,6 +2790,297 @@ namespace ts {
|
||||
// otherwise, return the original node for the source;
|
||||
return node;
|
||||
}
|
||||
|
||||
//
|
||||
// Comments
|
||||
//
|
||||
|
||||
function emitNodeConsideringComments(hint: EmitHint, node: Node) {
|
||||
if (node === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const commentRange = getCommentRange(node);
|
||||
const commentFlags = shouldEmitLeadingOrTrailingComments(node, commentRange);
|
||||
if ((commentFlags & EmitFlags.NoComments) === EmitFlags.NoComments) {
|
||||
// always emit any explicit leading or trailing comments.
|
||||
emitLeadingSynthesizedCommentsOfNode(node);
|
||||
emitNodeConsideringNestedComments(hint, node, commentFlags, commentRange);
|
||||
emitTrailingSynthesizedCommentsOfNode(node);
|
||||
}
|
||||
else {
|
||||
// Emit leading comments if the position is not synthesized and the node
|
||||
// has not opted out from emitting leading comments.
|
||||
if ((commentFlags & EmitFlags.NoLeadingComments) === 0) {
|
||||
emitLeadingComments(commentRange.pos, !isNotEmittedStatement(node));
|
||||
}
|
||||
|
||||
emitLeadingSynthesizedCommentsOfNode(node);
|
||||
emitNodeConsideringNestedComments(hint, node, commentFlags, commentRange);
|
||||
emitTrailingSynthesizedCommentsOfNode(node);
|
||||
|
||||
// Emit trailing comments if the position is not synthesized and the node
|
||||
// has not opted out from emitting trailing comments.
|
||||
if ((commentFlags & EmitFlags.NoTrailingComments) === 0 && !isNotEmittedStatement(node)) {
|
||||
emitTrailingComments(commentRange.end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function emitLeadingSynthesizedCommentsOfNode(node: Node) {
|
||||
if (extendedDiagnostics) performance.mark("emitLeadingSynthesizedComments");
|
||||
forEach(getSyntheticLeadingComments(node), emitLeadingSynthesizedComment);
|
||||
if (extendedDiagnostics) performance.measure("commentTime", "emitLeadingSynthesizedComments");
|
||||
}
|
||||
|
||||
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 emitTrailingSynthesizedCommentsOfNode(node: Node) {
|
||||
if (extendedDiagnostics) performance.mark("emitTrailingSynthesizedComments");
|
||||
forEach(getSyntheticTrailingComments(node), emitTrailingSynthesizedComment);
|
||||
if (extendedDiagnostics) performance.measure("commentTime", "emitTrailingSynthesizedComments");
|
||||
}
|
||||
|
||||
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 emitNodeConsideringNestedComments(hint: EmitHint, node: Node, commentFlags: EmitFlags, commentRange: TextRange) {
|
||||
if (commentFlags & EmitFlags.NoNestedComments) {
|
||||
disabled = true;
|
||||
getNextPhaseFollowingComments(hint)(hint, node);
|
||||
disabled = false;
|
||||
}
|
||||
else {
|
||||
emitNodeWithNestedComments(hint, node, commentFlags, commentRange);
|
||||
}
|
||||
}
|
||||
|
||||
function emitNodeWithNestedComments(hint: EmitHint, node: Node, commentFlags: EmitFlags, commentRange: TextRange) {
|
||||
// Save current container state on the stack.
|
||||
const savedContainerPos = containerPos;
|
||||
const savedContainerEnd = containerEnd;
|
||||
const savedDeclarationListContainerEnd = declarationListContainerEnd;
|
||||
|
||||
if ((commentFlags & EmitFlags.NoLeadingComments) === 0) {
|
||||
containerPos = commentRange.pos;
|
||||
}
|
||||
|
||||
if ((commentFlags & EmitFlags.NoTrailingComments) === 0) {
|
||||
containerEnd = commentRange.end;
|
||||
|
||||
// To avoid invalid comment emit in a down-level binding pattern, we
|
||||
// keep track of the last declaration list container's end
|
||||
if (node.kind === SyntaxKind.VariableDeclarationList) {
|
||||
declarationListContainerEnd = commentRange.end;
|
||||
}
|
||||
}
|
||||
|
||||
getNextPhaseFollowingComments(hint)(hint, node);
|
||||
|
||||
// Restore previous container state.
|
||||
containerPos = savedContainerPos;
|
||||
containerEnd = savedContainerEnd;
|
||||
declarationListContainerEnd = savedDeclarationListContainerEnd;
|
||||
}
|
||||
|
||||
function emitLeadingDetachedComments(detachedRange: TextRange, commentFlags: EmitFlags) {
|
||||
if (extendedDiagnostics) performance.mark("emitLeadingDetachedCommentsOfBody");
|
||||
if (!positionIsSynthesized(detachedRange.pos) && (commentFlags & EmitFlags.NoLeadingComments) === 0) {
|
||||
emitDetachedCommentsAndUpdateCommentsInfo(detachedRange);
|
||||
}
|
||||
if (extendedDiagnostics) performance.measure("commentTime", "emitLeadingDetachedCommentsOfBody");
|
||||
}
|
||||
|
||||
function emitTrailingDetachedComments(detachedRange: TextRange, commentFlags: EmitFlags) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
if (extendedDiagnostics) performance.mark("emitTrailingDetachedComments");
|
||||
if (!positionIsSynthesized(detachedRange.end) && (commentFlags & EmitFlags.NoTrailingComments) === 0) {
|
||||
emitLeadingComments(detachedRange.end, /*isEmittedNode*/ true);
|
||||
if (hasWrittenComment && !writer.isAtStartOfLine()) {
|
||||
writer.writeLine();
|
||||
}
|
||||
}
|
||||
if (extendedDiagnostics) performance.measure("commentTime", "emitTrailingDetachedComments");
|
||||
}
|
||||
|
||||
function emitLeadingCommentsOfPosition(pos: number) {
|
||||
if (disabled || positionIsSynthesized(pos)) {
|
||||
return;
|
||||
}
|
||||
|
||||
emitLeadingComments(pos, /*isEmittedNode*/ true);
|
||||
}
|
||||
|
||||
function emitLeadingComments(pos: number, isEmittedNode: boolean) {
|
||||
if (extendedDiagnostics) performance.mark("emitLeadingComments");
|
||||
hasWrittenComment = false;
|
||||
if (isEmittedNode) {
|
||||
forEachLeadingCommentToEmit(pos, emitLeadingComment);
|
||||
}
|
||||
else if (pos === 0) {
|
||||
// If the node will not be emitted in JS, remove all the comments(normal, pinned and ///) associated with the node,
|
||||
// unless it is a triple slash comment at the top of the file.
|
||||
// For Example:
|
||||
// /// <reference-path ...>
|
||||
// declare var x;
|
||||
// /// <reference-path ...>
|
||||
// interface F {}
|
||||
// The first /// will NOT be removed while the second one will be removed even though both node will not be emitted
|
||||
forEachLeadingCommentToEmit(pos, emitTripleSlashLeadingComment);
|
||||
}
|
||||
if (extendedDiagnostics) performance.measure("commentTime", "emitLeadingComments");
|
||||
}
|
||||
|
||||
function emitTripleSlashLeadingComment(commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) {
|
||||
if (isTripleSlashComment(currentText, commentPos, commentEnd)) {
|
||||
emitLeadingComment(commentPos, commentEnd, kind, hasTrailingNewLine, rangePos);
|
||||
}
|
||||
}
|
||||
|
||||
function emitLeadingComment(commentPos: number, commentEnd: number, _kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) {
|
||||
if (!hasWrittenComment) {
|
||||
emitNewLineBeforeLeadingCommentOfPosition(currentLineMap, writer, rangePos, commentPos);
|
||||
hasWrittenComment = true;
|
||||
}
|
||||
|
||||
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
|
||||
if (emitPos) emitPos(commentPos);
|
||||
writeCommentRange(currentText, currentLineMap, writer, commentPos, commentEnd, newLine);
|
||||
if (emitPos) emitPos(commentEnd);
|
||||
|
||||
if (hasTrailingNewLine) {
|
||||
writer.writeLine();
|
||||
}
|
||||
else {
|
||||
writer.write(" ");
|
||||
}
|
||||
}
|
||||
|
||||
function emitTrailingComments(pos: number) {
|
||||
if (extendedDiagnostics) performance.mark("emitTrailingComments");
|
||||
forEachTrailingCommentToEmit(pos, emitTrailingComment);
|
||||
if (extendedDiagnostics) performance.measure("commentTime", "emitTrailingComments");
|
||||
}
|
||||
|
||||
function emitTrailingComment(commentPos: number, commentEnd: number, _kind: SyntaxKind, hasTrailingNewLine: boolean) {
|
||||
// trailing comments are emitted at space/*trailing comment1 */space/*trailing comment2*/
|
||||
if (!writer.isAtStartOfLine()) {
|
||||
writer.write(" ");
|
||||
}
|
||||
|
||||
if (emitPos) emitPos(commentPos);
|
||||
writeCommentRange(currentText, currentLineMap, writer, commentPos, commentEnd, newLine);
|
||||
if (emitPos) emitPos(commentEnd);
|
||||
|
||||
if (hasTrailingNewLine) {
|
||||
writer.writeLine();
|
||||
}
|
||||
}
|
||||
|
||||
function emitTrailingCommentsOfPosition(pos: number) {
|
||||
if (disabled || positionIsSynthesized(pos)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (extendedDiagnostics) performance.mark("emitTrailingCommentsOfPosition");
|
||||
forEachTrailingCommentToEmit(pos, emitTrailingCommentOfPosition);
|
||||
if (extendedDiagnostics) performance.measure("commentTime", "emitTrailingCommentsOfPosition");
|
||||
}
|
||||
|
||||
function emitTrailingCommentOfPosition(commentPos: number, commentEnd: number, _kind: SyntaxKind, hasTrailingNewLine: boolean) {
|
||||
// trailing comments of a position are emitted at /*trailing comment1 */space/*trailing comment*/space
|
||||
|
||||
if (emitPos) emitPos(commentPos);
|
||||
writeCommentRange(currentText, currentLineMap, writer, commentPos, commentEnd, newLine);
|
||||
if (emitPos) emitPos(commentEnd);
|
||||
|
||||
if (hasTrailingNewLine) {
|
||||
writer.writeLine();
|
||||
}
|
||||
else {
|
||||
writer.write(" ");
|
||||
}
|
||||
}
|
||||
|
||||
function forEachLeadingCommentToEmit(pos: number, cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) => void) {
|
||||
// Emit the leading comments only if the container's pos doesn't match because the container should take care of emitting these comments
|
||||
if (containerPos === -1 || pos !== containerPos) {
|
||||
if (hasDetachedComments(pos)) {
|
||||
forEachLeadingCommentWithoutDetachedComments(cb);
|
||||
}
|
||||
else {
|
||||
forEachLeadingCommentRange(currentText, pos, cb, /*state*/ pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function forEachTrailingCommentToEmit(end: number, cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean) => void) {
|
||||
// Emit the trailing comments only if the container's end doesn't match because the container should take care of emitting these comments
|
||||
if (containerEnd === -1 || (end !== containerEnd && end !== declarationListContainerEnd)) {
|
||||
forEachTrailingCommentRange(currentText, end, cb);
|
||||
}
|
||||
}
|
||||
|
||||
function hasDetachedComments(pos: number) {
|
||||
return detachedCommentsInfo !== undefined && lastOrUndefined(detachedCommentsInfo).nodePos === pos;
|
||||
}
|
||||
|
||||
function forEachLeadingCommentWithoutDetachedComments(cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) => void) {
|
||||
// get the leading comments from detachedPos
|
||||
const pos = lastOrUndefined(detachedCommentsInfo).detachedCommentEndPos;
|
||||
if (detachedCommentsInfo.length - 1) {
|
||||
detachedCommentsInfo.pop();
|
||||
}
|
||||
else {
|
||||
detachedCommentsInfo = undefined;
|
||||
}
|
||||
|
||||
forEachLeadingCommentRange(currentText, pos, cb, /*state*/ pos);
|
||||
}
|
||||
|
||||
function emitDetachedCommentsAndUpdateCommentsInfo(range: TextRange) {
|
||||
const currentDetachedCommentInfo = emitDetachedComments(currentText, currentLineMap, writer, writeComment, range, newLine, disabled);
|
||||
if (currentDetachedCommentInfo) {
|
||||
if (detachedCommentsInfo) {
|
||||
detachedCommentsInfo.push(currentDetachedCommentInfo);
|
||||
}
|
||||
else {
|
||||
detachedCommentsInfo = [currentDetachedCommentInfo];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeComment(text: string, lineMap: number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) {
|
||||
if (emitPos) emitPos(commentPos);
|
||||
writeCommentRange(text, lineMap, writer, commentPos, commentEnd, newLine);
|
||||
if (emitPos) emitPos(commentEnd);
|
||||
}
|
||||
}
|
||||
|
||||
function createDelimiterMap() {
|
||||
@@ -2811,6 +3113,47 @@ namespace ts {
|
||||
return brackets[format & ListFormat.BracketsMask][1];
|
||||
}
|
||||
|
||||
function shouldEmitLeadingOrTrailingComments(node: Node, commentRange: TextRange) {
|
||||
let commentFlags = getEmitFlags(node) & (EmitFlags.NoComments | EmitFlags.NoNestedComments);
|
||||
if (isCollapsedRange(commentRange)) {
|
||||
commentFlags |= EmitFlags.NoComments;
|
||||
}
|
||||
else {
|
||||
if ((commentFlags & EmitFlags.NoLeadingComments) === 0 && positionIsSynthesized(commentRange.pos)) {
|
||||
commentFlags |= EmitFlags.NoLeadingComments;
|
||||
}
|
||||
if ((commentFlags & EmitFlags.NoTrailingComments) === 0 && positionIsSynthesized(commentRange.end)) {
|
||||
commentFlags |= EmitFlags.NoTrailingComments;
|
||||
}
|
||||
}
|
||||
return commentFlags;
|
||||
}
|
||||
|
||||
function formatSynthesizedComment(comment: SynthesizedComment) {
|
||||
return comment.kind === SyntaxKind.MultiLineCommentTrivia
|
||||
? `/*${comment.text}*/`
|
||||
: `//${comment.text}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given comment is a triple-slash
|
||||
*
|
||||
* @return true if the comment is a triple-slash comment else false
|
||||
**/
|
||||
function isTripleSlashComment(text: string, commentPos: number, commentEnd: number) {
|
||||
// Verify this is /// comment, but do the regexp match only when we first can find /// in the comment text
|
||||
// so that we don't end up computing comment string and doing match for all // comments
|
||||
if (text.charCodeAt(commentPos + 1) === CharacterCodes.slash &&
|
||||
commentPos + 2 < commentEnd &&
|
||||
text.charCodeAt(commentPos + 2) === CharacterCodes.slash) {
|
||||
const textSubStr = text.substring(commentPos, commentEnd);
|
||||
return textSubStr.match(fullTripleSlashReferencePathRegEx) ||
|
||||
textSubStr.match(fullTripleSlashAMDReferencePathRegEx) ?
|
||||
true : false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Flags enum to track count of temp variables and a few dedicated names
|
||||
const enum TempFlags {
|
||||
Auto = 0x00000000, // No preferred name
|
||||
|
||||
@@ -3067,7 +3067,10 @@ namespace ts {
|
||||
Assertions = 1 << 1,
|
||||
PartiallyEmittedExpressions = 1 << 2,
|
||||
|
||||
All = Parentheses | Assertions | PartiallyEmittedExpressions
|
||||
All = Parentheses | Assertions | PartiallyEmittedExpressions,
|
||||
|
||||
OnlySynthetic = 1 << 3,
|
||||
SynthesizedParentheses = Parentheses | OnlySynthetic,
|
||||
}
|
||||
|
||||
export function skipOuterExpressions(node: Expression, kinds?: OuterExpressionKinds): Expression;
|
||||
@@ -3076,6 +3079,10 @@ namespace ts {
|
||||
let previousNode: Node;
|
||||
do {
|
||||
previousNode = node;
|
||||
if (kinds & OuterExpressionKinds.OnlySynthetic && !nodeIsSynthesized(node)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (kinds & OuterExpressionKinds.Parentheses) {
|
||||
node = skipParentheses(node);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
"transformers/module/system.ts",
|
||||
"transformers/module/es2015.ts",
|
||||
"transformer.ts",
|
||||
"comments.ts",
|
||||
"sourcemap.ts",
|
||||
"declarationEmitter.ts",
|
||||
"emitter.ts",
|
||||
|
||||
@@ -3749,6 +3749,7 @@
|
||||
}
|
||||
|
||||
export const enum EmitFlags {
|
||||
None = 0,
|
||||
SingleLine = 1 << 0, // The contents of this node should be emitted on a single line.
|
||||
AdviseOnEmitNode = 1 << 1, // The printer should invoke the onEmitNode callback when printing this node.
|
||||
NoSubstitution = 1 << 2, // Disables further substitution of an expression.
|
||||
|
||||
@@ -3352,7 +3352,7 @@ namespace ts {
|
||||
* @param range A TextRange.
|
||||
*/
|
||||
export function isCollapsedRange(range: TextRange) {
|
||||
return range.pos === range.end;
|
||||
return getRangePos(range) === getRangeEnd(range);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
"../compiler/transformers/module/system.ts",
|
||||
"../compiler/transformers/module/es2015.ts",
|
||||
"../compiler/transformer.ts",
|
||||
"../compiler/comments.ts",
|
||||
"../compiler/sourcemap.ts",
|
||||
"../compiler/declarationEmitter.ts",
|
||||
"../compiler/emitter.ts",
|
||||
@@ -91,7 +90,7 @@
|
||||
"rwcRunner.ts",
|
||||
"test262Runner.ts",
|
||||
"runner.ts",
|
||||
"../server/protocol.d.ts",
|
||||
"../server/protocol.ts",
|
||||
"../server/session.ts",
|
||||
"../server/client.ts",
|
||||
"../server/editorServices.ts",
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
"../compiler/transformers/module/system.ts",
|
||||
"../compiler/transformers/module/es2015.ts",
|
||||
"../compiler/transformer.ts",
|
||||
"../compiler/comments.ts",
|
||||
"../compiler/sourcemap.ts",
|
||||
"../compiler/declarationEmitter.ts",
|
||||
"../compiler/emitter.ts",
|
||||
|
||||
Reference in New Issue
Block a user