Skip to content
Closed
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
59 changes: 46 additions & 13 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ namespace ts {
const printerOptions: PrinterOptions = {
removeComments: compilerOptions.removeComments,
newLine: compilerOptions.newLine,
preserveSourceNewlines: true,
noEmitHelpers: compilerOptions.noEmitHelpers,
module: compilerOptions.module,
target: compilerOptions.target,
Expand Down Expand Up @@ -2365,16 +2366,10 @@ namespace ts {

function emitParenthesizedExpression(node: ParenthesizedExpression) {
const openParenPos = emitTokenWithComment(SyntaxKind.OpenParenToken, node.pos, writePunctuation, node);
const leadingNewlines = preserveSourceNewlines && getLeadingLineTerminatorCount(node, [node.expression], ListFormat.None);
if (leadingNewlines) {
writeLinesAndIndent(leadingNewlines, /*writeLinesIfNotIndenting*/ false);
}
const indented = writeLineSeparatorsAndIndentBefore(node.expression, node);
emitExpression(node.expression);
const trailingNewlines = preserveSourceNewlines && getClosingLineTerminatorCount(node, [node.expression], ListFormat.None);
if (trailingNewlines) {
writeLine(trailingNewlines);
}
decreaseIndentIf(leadingNewlines);
writeLineSeparatorsAfter(node.expression, node);
decreaseIndentIf(indented);
emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression ? node.expression.end : openParenPos, writePunctuation, node);
}

Expand Down Expand Up @@ -3292,12 +3287,15 @@ namespace ts {
writePunctuation("<");

if (isJsxOpeningElement(node)) {
const indented = writeLineSeparatorsAndIndentBefore(node.tagName, node);
emitJsxTagName(node.tagName);
emitTypeArguments(node, node.typeArguments);
if (node.attributes.properties && node.attributes.properties.length > 0) {
writeSpace();
}
emit(node.attributes);
writeLineSeparatorsAfter(node.attributes, node);
decreaseIndentIf(indented);
}

writePunctuation(">");
Expand Down Expand Up @@ -3686,7 +3684,9 @@ namespace ts {
const statements = node.statements;
pushNameGenerationScope(node);
forEach(node.statements, generateNames);
emitHelpers(node);
if (emitHelpers(node)) {
writeLine();
}
const index = findIndex(statements, statement => !isPrologueDirective(statement));
emitTripleSlashDirectivesIfNeeded(node);
emitList(node, statements, ListFormat.MultiLine, index === -1 ? statements.length : index);
Expand Down Expand Up @@ -4301,6 +4301,7 @@ namespace ts {
return getEffectiveLines(
includeComments => getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter(
firstChild.pos,
parentNode.pos,
currentSourceFile!,
includeComments));
}
Expand All @@ -4322,12 +4323,12 @@ namespace ts {
// JsxText will be written with its leading whitespace, so don't add more manually.
return 0;
}
else if (!nodeIsSynthesized(previousNode) && !nodeIsSynthesized(nextNode) && previousNode.parent === nextNode.parent) {
else if (siblingNodePositionsAreComparable(previousNode, nextNode)) {
if (preserveSourceNewlines) {
return getEffectiveLines(
includeComments => getLinesBetweenRangeEndAndRangeStart(
previousNode,
nextNode,
getOriginalNode(previousNode),
getOriginalNode(nextNode),
currentSourceFile!,
includeComments));
}
Expand All @@ -4343,6 +4344,22 @@ namespace ts {
return format & ListFormat.MultiLine ? 1 : 0;
}

function siblingNodePositionsAreComparable(previousNode: Node, nextNode: Node) {
if (previousNode.kind === SyntaxKind.NotEmittedStatement && nextNode.kind === SyntaxKind.NotEmittedStatement) {
return false;
}
if (nodeIsSynthesized(previousNode) || nodeIsSynthesized(nextNode)) {
return false;
}

if (!previousNode.parent || !nextNode.parent) {
const previousParent = getOriginalNode(previousNode).parent;
return previousParent && previousParent === getOriginalNode(nextNode).parent;
}

return nextNode.pos >= previousNode.end;
}

function getClosingLineTerminatorCount(parentNode: TextRange, children: readonly Node[], format: ListFormat): number {
if (format & ListFormat.PreserveLines || preserveSourceNewlines) {
if (format & ListFormat.PreferNewLine) {
Expand All @@ -4358,6 +4375,7 @@ namespace ts {
return getEffectiveLines(
includeComments => getLinesBetweenPositionAndNextNonWhitespaceCharacter(
lastChild.end,
parentNode.end,
currentSourceFile!,
includeComments));
}
Expand Down Expand Up @@ -4397,6 +4415,21 @@ namespace ts {
return lines;
}

function writeLineSeparatorsAndIndentBefore(node: Node, parent: Node): boolean {
const leadingNewlines = preserveSourceNewlines && getLeadingLineTerminatorCount(parent, [node], ListFormat.None);
if (leadingNewlines) {
writeLinesAndIndent(leadingNewlines, /*writeLinesIfNotIndenting*/ false);
}
return !!leadingNewlines;
}

function writeLineSeparatorsAfter(node: Node, parent: Node) {
const trailingNewlines = preserveSourceNewlines && getClosingLineTerminatorCount(parent, [node], ListFormat.None);
if (trailingNewlines) {
writeLine(trailingNewlines);
}
}

function synthesizedNodeStartsOnNewLine(node: Node, format: ListFormat) {
if (nodeIsSynthesized(node)) {
const startsOnNewLine = getStartsOnNewLine(node);
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/transformers/es2015.ts
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,7 @@ namespace ts {
transformConstructorBody(constructor, node, extendsClauseElement, hasSynthesizedSuper)
);

setTextRange(constructorFunction, constructor || node);
setTextRange(setOriginalNode(constructorFunction, constructor), constructor || node);
if (extendsClauseElement) {
setEmitFlags(constructorFunction, EmitFlags.CapturesThis);
}
Expand Down
15 changes: 9 additions & 6 deletions src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2178,13 +2178,16 @@ namespace ts {
return undefined;
}

return setTextRange(
createExpressionStatement(
inlineExpressions(
map(variables, transformInitializedVariable)
)
return setOriginalNode(
setTextRange(
createExpressionStatement(
inlineExpressions(
map(variables, transformInitializedVariable)
)
),
node
),
node
node,
);
}
else {
Expand Down
14 changes: 7 additions & 7 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4776,19 +4776,19 @@ namespace ts {
return positionIsSynthesized(range.pos) ? -1 : skipTrivia(sourceFile.text, range.pos, /*stopAfterLineBreak*/ false, includeComments);
}

export function getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter(pos: number, sourceFile: SourceFile, includeComments?: boolean) {
export function getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter(pos: number, stopPos: number, sourceFile: SourceFile, includeComments?: boolean) {
const startPos = skipTrivia(sourceFile.text, pos, /*stopAfterLineBreak*/ false, includeComments);
const prevPos = getPreviousNonWhitespacePosition(startPos, sourceFile);
return getLinesBetweenPositions(sourceFile, prevPos || 0, startPos);
const prevPos = getPreviousNonWhitespacePosition(startPos, stopPos, sourceFile);
return getLinesBetweenPositions(sourceFile, prevPos ?? stopPos, startPos);
}

export function getLinesBetweenPositionAndNextNonWhitespaceCharacter(pos: number, sourceFile: SourceFile, includeComments?: boolean) {
export function getLinesBetweenPositionAndNextNonWhitespaceCharacter(pos: number, stopPos: number, sourceFile: SourceFile, includeComments?: boolean) {
const nextPos = skipTrivia(sourceFile.text, pos, /*stopAfterLineBreak*/ false, includeComments);
return getLinesBetweenPositions(sourceFile, pos, nextPos);
return getLinesBetweenPositions(sourceFile, pos, Math.min(stopPos, nextPos));
}

function getPreviousNonWhitespacePosition(pos: number, sourceFile: SourceFile) {
while (pos-- > 0) {
function getPreviousNonWhitespacePosition(pos: number, stopPos = 0, sourceFile: SourceFile) {
while (pos-- > stopPos) {
if (!isWhiteSpaceLike(sourceFile.text.charCodeAt(pos))) {
return pos;
}
Expand Down
1 change: 1 addition & 0 deletions tests/baselines/reference/1.0lib-noErrors.js
Original file line number Diff line number Diff line change
Expand Up @@ -1158,4 +1158,5 @@ MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */

/// <reference no-default-lib="true"/>
Expand Down
19 changes: 17 additions & 2 deletions tests/baselines/reference/APISample_Watch.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,21 @@ watchMain();
* Please log a "breaking change" issue for any API breaking change affecting this issue
*/
exports.__esModule = true;

var ts = require("typescript");

var formatHost = {
getCanonicalFileName: function (path) { return path; },
getCurrentDirectory: ts.sys.getCurrentDirectory,
getNewLine: function () { return ts.sys.newLine; }
};

function watchMain() {
var configPath = ts.findConfigFile(/*searchPath*/ "./", ts.sys.fileExists, "tsconfig.json");
if (!configPath) {
throw new Error("Could not find a valid 'tsconfig.json'.");
}

// TypeScript can use several different program creation "strategies":
// * ts.createEmitAndSemanticDiagnosticsBuilderProgram,
// * ts.createSemanticDiagnosticsBuilderProgram
Expand All @@ -111,7 +115,11 @@ function watchMain() {
// Between `createEmitAndSemanticDiagnosticsBuilderProgram` and `createSemanticDiagnosticsBuilderProgram`, the only difference is emit.
// For pure type-checking scenarios, or when another tool/process handles emit, using `createSemanticDiagnosticsBuilderProgram` may be more desirable.
// Note that there is another overload for `createWatchCompilerHost` that takes a set of root files.
var host = ts.createWatchCompilerHost(configPath, {}, ts.sys, ts.createSemanticDiagnosticsBuilderProgram, reportDiagnostic, reportWatchStatusChanged);
var host = ts.createWatchCompilerHost(configPath, {}, ts.sys,
ts.createSemanticDiagnosticsBuilderProgram,
reportDiagnostic,
reportWatchStatusChanged);

// You can technically override any given hook on the host, though you probably don't need to.
// Note that we're assuming `origCreateProgram` and `origPostProgramCreate` doesn't use `this` at all.
var origCreateProgram = host.createProgram;
Expand All @@ -120,21 +128,28 @@ function watchMain() {
return origCreateProgram(rootNames, options, host, oldProgram);
};
var origPostProgramCreate = host.afterProgramCreate;

host.afterProgramCreate = function (program) {
console.log("** We finished making the program! **");
origPostProgramCreate(program);
};

// `createWatchProgram` creates an initial program, watches files, and updates the program over time.
ts.createWatchProgram(host);
}

function reportDiagnostic(diagnostic) {
console.error("Error", diagnostic.code, ":", ts.flattenDiagnosticMessageText(diagnostic.messageText, formatHost.getNewLine()));
console.error("Error", diagnostic.code, ":",
ts.flattenDiagnosticMessageText(diagnostic.messageText, formatHost.getNewLine())
);
}

/**
* Prints a diagnostic every time the watch status changes.
* This is mainly for messages like "Starting compilation" or "Compilation completed".
*/
function reportWatchStatusChanged(diagnostic) {
console.info(ts.formatDiagnostic(diagnostic, formatHost));
}

watchMain();
7 changes: 7 additions & 0 deletions tests/baselines/reference/APISample_WatchWithDefaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,15 @@ watchMain();
* Please log a "breaking change" issue for any API breaking change affecting this issue
*/
exports.__esModule = true;

var ts = require("typescript");

function watchMain() {
var configPath = ts.findConfigFile(/*searchPath*/ "./", ts.sys.fileExists, "tsconfig.json");
if (!configPath) {
throw new Error("Could not find a valid 'tsconfig.json'.");
}

// TypeScript can use several different program creation "strategies":
// * ts.createEmitAndSemanticDiagnosticsBuilderProgram,
// * ts.createSemanticDiagnosticsBuilderProgram
Expand All @@ -79,6 +82,7 @@ function watchMain() {
// For pure type-checking scenarios, or when another tool/process handles emit, using `createSemanticDiagnosticsBuilderProgram` may be more desirable.
// Note that there is another overload for `createWatchCompilerHost` that takes a set of root files.
var host = ts.createWatchCompilerHost(configPath, {}, ts.sys);

// You can technically override any given hook on the host, though you probably don't need to.
// Note that we're assuming `origCreateProgram` and `origPostProgramCreate` doesn't use `this` at all.
var origCreateProgram = host.createProgram;
Expand All @@ -87,11 +91,14 @@ function watchMain() {
return origCreateProgram(rootNames, options, host, oldProgram);
};
var origPostProgramCreate = host.afterProgramCreate;

host.afterProgramCreate = function (program) {
console.log("** We finished making the program! **");
origPostProgramCreate(program);
};

// `createWatchProgram` creates an initial program, watches files, and updates the program over time.
ts.createWatchProgram(host);
}

watchMain();
9 changes: 9 additions & 0 deletions tests/baselines/reference/APISample_WatchWithOwnWatchHost.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,28 +69,34 @@ watchMain();
* Please log a "breaking change" issue for any API breaking change affecting this issue
*/
exports.__esModule = true;

var ts = require("typescript");

function watchMain() {
// get list of files and compiler options somehow
var files = [];
var options = {};

var host = {
rootFiles: files,
options: options,
useCaseSensitiveFileNames: function () { return ts.sys.useCaseSensitiveFileNames; },
getNewLine: function () { return ts.sys.newLine; },
getCurrentDirectory: ts.sys.getCurrentDirectory,
getDefaultLibFileName: function (options) { return ts.getDefaultLibFilePath(options); },

fileExists: ts.sys.fileExists,
readFile: ts.sys.readFile,
directoryExists: ts.sys.directoryExists,
getDirectories: ts.sys.getDirectories,
readDirectory: ts.sys.readDirectory,
realpath: ts.sys.realpath,

watchFile: ts.sys.watchFile,
watchDirectory: ts.sys.watchDirectory,
createProgram: ts.createAbstractBuilder
};

// You can technically override any given hook on the host, though you probably don't need to.
// Note that we're assuming `origCreateProgram` and `origPostProgramCreate` doesn't use `this` at all.
var origCreateProgram = host.createProgram;
Expand All @@ -99,11 +105,14 @@ function watchMain() {
return origCreateProgram(rootNames, options, host, oldProgram);
};
var origPostProgramCreate = host.afterProgramCreate;

host.afterProgramCreate = function (program) {
console.log("** We finished making the program! **");
origPostProgramCreate(program);
};

// `createWatchProgram` creates an initial program, watches files, and updates the program over time.
ts.createWatchProgram(host);
}

watchMain();
5 changes: 5 additions & 0 deletions tests/baselines/reference/APISample_compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,15 @@ compile(process.argv.slice(2), {
*/
exports.__esModule = true;
exports.compile = void 0;

var ts = require("typescript");

function compile(fileNames, options) {
var program = ts.createProgram(fileNames, options);
var emitResult = program.emit();

var allDiagnostics = ts.getPreEmitDiagnostics(program);

allDiagnostics.forEach(function (diagnostic) {
var message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
if (!diagnostic.file) {
Expand All @@ -68,6 +72,7 @@ function compile(fileNames, options) {
var _a = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start), line = _a.line, character = _a.character;
console.log(diagnostic.file.fileName + " (" + (line + 1) + "," + (character + 1) + "): " + message);
});

var exitCode = emitResult.emitSkipped ? 1 : 0;
console.log("Process exiting with code '" + exitCode + "'.");
process.exit(exitCode);
Expand Down
Loading