Skip to content

Commit 11019e4

Browse files
author
Arthur Ozga
committed
Merge branch 'master' into typeToStringViaTypeNode
2 parents 0820f69 + ed7ae80 commit 11019e4

File tree

82 files changed

+2552
-371
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+2552
-371
lines changed

Gulpfile.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -935,7 +935,7 @@ gulp.task(loggedIOJsPath, /*help*/ false, [], (done) => {
935935
const temp = path.join(builtLocalDirectory, "temp");
936936
mkdirP(temp, (err) => {
937937
if (err) { console.error(err); done(err); process.exit(1); }
938-
exec(host, [LKGCompiler, "--types --outdir", temp, loggedIOpath], () => {
938+
exec(host, [LKGCompiler, "--types", "--target es5", "--lib es5", "--outdir", temp, loggedIOpath], () => {
939939
fs.renameSync(path.join(temp, "/harness/loggedIO.js"), loggedIOJsPath);
940940
del(temp).then(() => done(), done);
941941
}, done);
@@ -946,7 +946,13 @@ const instrumenterPath = path.join(harnessDirectory, "instrumenter.ts");
946946
const instrumenterJsPath = path.join(builtLocalDirectory, "instrumenter.js");
947947
gulp.task(instrumenterJsPath, /*help*/ false, [servicesFile], () => {
948948
const settings: tsc.Settings = getCompilerSettings({
949-
outFile: instrumenterJsPath
949+
outFile: instrumenterJsPath,
950+
target: "es5",
951+
lib: [
952+
"es6",
953+
"dom",
954+
"scripthost"
955+
]
950956
}, /*useBuiltCompiler*/ true);
951957
return gulp.src(instrumenterPath)
952958
.pipe(newer(instrumenterJsPath))

src/compiler/checker.ts

Lines changed: 70 additions & 73 deletions
Large diffs are not rendered by default.

src/compiler/core.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,8 @@ namespace ts {
230230
* If no such value is found, it applies the callback until the parent pointer is undefined or the callback returns "quit"
231231
* At that point findAncestor returns undefined.
232232
*/
233+
export function findAncestor<T extends Node>(node: Node, callback: (element: Node) => element is T): T | undefined;
234+
export function findAncestor(node: Node, callback: (element: Node) => boolean | "quit"): Node | undefined;
233235
export function findAncestor(node: Node, callback: (element: Node) => boolean | "quit"): Node {
234236
while (node) {
235237
const result = callback(node);
@@ -490,6 +492,35 @@ namespace ts {
490492
return result;
491493
}
492494

495+
/**
496+
* Maps an array. If the mapped value is an array, it is spread into the result.
497+
* Avoids allocation if all elements map to themselves.
498+
*
499+
* @param array The array to map.
500+
* @param mapfn The callback used to map the result into one or more values.
501+
*/
502+
export function sameFlatMap<T>(array: T[], mapfn: (x: T, i: number) => T | T[]): T[] {
503+
let result: T[];
504+
if (array) {
505+
for (let i = 0; i < array.length; i++) {
506+
const item = array[i];
507+
const mapped = mapfn(item, i);
508+
if (result || item !== mapped || isArray(mapped)) {
509+
if (!result) {
510+
result = array.slice(0, i);
511+
}
512+
if (isArray(mapped)) {
513+
addRange(result, mapped);
514+
}
515+
else {
516+
result.push(mapped);
517+
}
518+
}
519+
}
520+
}
521+
return result || array;
522+
}
523+
493524
/**
494525
* Computes the first matching span of elements and returns a tuple of the first span
495526
* and the remaining elements.

src/compiler/emitter.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,9 @@ namespace ts {
740740
// Transformation nodes
741741
case SyntaxKind.PartiallyEmittedExpression:
742742
return emitPartiallyEmittedExpression(<PartiallyEmittedExpression>node);
743+
744+
case SyntaxKind.CommaListExpression:
745+
return emitCommaList(<CommaListExpression>node);
743746
}
744747
}
745748

@@ -2124,6 +2127,10 @@ namespace ts {
21242127
emitExpression(node.expression);
21252128
}
21262129

2130+
function emitCommaList(node: CommaListExpression) {
2131+
emitExpressionList(node, node.elements, ListFormat.CommaListElements);
2132+
}
2133+
21272134
/**
21282135
* Emits any prologue directives at the start of a Statement list, returning the
21292136
* number of prologue directives written to the output.
@@ -2979,6 +2986,7 @@ namespace ts {
29792986
ArrayBindingPatternElements = SingleLine | AllowTrailingComma | CommaDelimited | SpaceBetweenSiblings,
29802987
ObjectLiteralExpressionProperties = PreserveLines | CommaDelimited | SpaceBetweenSiblings | SpaceBetweenBraces | Indented | Braces,
29812988
ArrayLiteralExpressionElements = PreserveLines | CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | Indented | SquareBrackets,
2989+
CommaListElements = CommaDelimited | SpaceBetweenSiblings | SingleLine,
29822990
CallExpressionArguments = CommaDelimited | SpaceBetweenSiblings | SingleLine | Parenthesis,
29832991
NewExpressionArguments = CommaDelimited | SpaceBetweenSiblings | SingleLine | Parenthesis | OptionalIfUndefined,
29842992
TemplateExpressionSpans = SingleLine | NoInterveningComments,

src/compiler/factory.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2091,6 +2091,30 @@ namespace ts {
20912091
return node;
20922092
}
20932093

2094+
function flattenCommaElements(node: Expression): Expression | Expression[] {
2095+
if (nodeIsSynthesized(node) && !isParseTreeNode(node) && !node.original && !node.emitNode && !node.id) {
2096+
if (node.kind === SyntaxKind.CommaListExpression) {
2097+
return (<CommaListExpression>node).elements;
2098+
}
2099+
if (isBinaryExpression(node) && node.operatorToken.kind === SyntaxKind.CommaToken) {
2100+
return [node.left, node.right];
2101+
}
2102+
}
2103+
return node;
2104+
}
2105+
2106+
export function createCommaList(elements: Expression[]) {
2107+
const node = <CommaListExpression>createSynthesizedNode(SyntaxKind.CommaListExpression);
2108+
node.elements = createNodeArray(sameFlatMap(elements, flattenCommaElements));
2109+
return node;
2110+
}
2111+
2112+
export function updateCommaList(node: CommaListExpression, elements: Expression[]) {
2113+
return node.elements !== elements
2114+
? updateNode(createCommaList(elements), node)
2115+
: node;
2116+
}
2117+
20942118
export function createBundle(sourceFiles: SourceFile[]) {
20952119
const node = <Bundle>createNode(SyntaxKind.Bundle);
20962120
node.sourceFiles = sourceFiles;
@@ -2898,7 +2922,11 @@ namespace ts {
28982922
}
28992923

29002924
export function inlineExpressions(expressions: Expression[]) {
2901-
return reduceLeft(expressions, createComma);
2925+
// Avoid deeply nested comma expressions as traversing them during emit can result in "Maximum call
2926+
// stack size exceeded" errors.
2927+
return expressions.length > 10
2928+
? createCommaList(expressions)
2929+
: reduceLeft(expressions, createComma);
29022930
}
29032931

29042932
export function createExpressionFromEntityName(node: EntityName | Expression): Expression {

src/compiler/moduleNameResolver.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,11 @@ namespace ts {
4747
return resolved.path;
4848
}
4949

50-
/** Adds `isExernalLibraryImport` to a Resolved to get a ResolvedModule. */
51-
function resolvedModuleFromResolved({ path, extension }: Resolved, isExternalLibraryImport: boolean): ResolvedModuleFull {
52-
return { resolvedFileName: path, extension, isExternalLibraryImport };
53-
}
54-
5550
function createResolvedModuleWithFailedLookupLocations(resolved: Resolved | undefined, isExternalLibraryImport: boolean, failedLookupLocations: string[]): ResolvedModuleWithFailedLookupLocations {
56-
return { resolvedModule: resolved && resolvedModuleFromResolved(resolved, isExternalLibraryImport), failedLookupLocations };
51+
return {
52+
resolvedModule: resolved && { resolvedFileName: resolved.path, extension: resolved.extension, isExternalLibraryImport },
53+
failedLookupLocations
54+
};
5755
}
5856

5957
export function moduleHasNonRelativeName(moduleName: string): boolean {

src/compiler/parser.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,19 @@ namespace ts {
2323
}
2424
}
2525

26-
function visitNode<T>(cbNode: (node: Node) => T, node: Node): T {
26+
function visitNode<T>(cbNode: (node: Node) => T, node: Node): T | undefined {
2727
if (node) {
2828
return cbNode(node);
2929
}
3030
}
3131

32-
function visitNodeArray<T>(cbNodes: (nodes: Node[]) => T, nodes: Node[]) {
32+
function visitNodeArray<T>(cbNodes: (nodes: Node[]) => T, nodes: Node[]): T | undefined {
3333
if (nodes) {
3434
return cbNodes(nodes);
3535
}
3636
}
3737

38-
function visitEachNode<T>(cbNode: (node: Node) => T, nodes: Node[]) {
38+
function visitEachNode<T>(cbNode: (node: Node) => T, nodes: Node[]): T | undefined {
3939
if (nodes) {
4040
for (const node of nodes) {
4141
const result = cbNode(node);
@@ -50,7 +50,7 @@ namespace ts {
5050
// stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise,
5151
// embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns
5252
// a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned.
53-
export function forEachChild<T>(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T {
53+
export function forEachChild<T>(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T | undefined {
5454
if (!node) {
5555
return;
5656
}
@@ -362,6 +362,8 @@ namespace ts {
362362
return visitNode(cbNode, (<ExternalModuleReference>node).expression);
363363
case SyntaxKind.MissingDeclaration:
364364
return visitNodes(cbNodes, node.decorators);
365+
case SyntaxKind.CommaListExpression:
366+
return visitNodes(cbNodes, (<CommaListExpression>node).elements);
365367

366368
case SyntaxKind.JsxElement:
367369
return visitNode(cbNode, (<JsxElement>node).openingElement) ||

src/compiler/program.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,101 @@ namespace ts {
241241
return output;
242242
}
243243

244+
const redForegroundEscapeSequence = "\u001b[91m";
245+
const yellowForegroundEscapeSequence = "\u001b[93m";
246+
const blueForegroundEscapeSequence = "\u001b[93m";
247+
const gutterStyleSequence = "\u001b[100;30m";
248+
const gutterSeparator = " ";
249+
const resetEscapeSequence = "\u001b[0m";
250+
const ellipsis = "...";
251+
function getCategoryFormat(category: DiagnosticCategory): string {
252+
switch (category) {
253+
case DiagnosticCategory.Warning: return yellowForegroundEscapeSequence;
254+
case DiagnosticCategory.Error: return redForegroundEscapeSequence;
255+
case DiagnosticCategory.Message: return blueForegroundEscapeSequence;
256+
}
257+
}
258+
259+
function formatAndReset(text: string, formatStyle: string) {
260+
return formatStyle + text + resetEscapeSequence;
261+
}
262+
263+
function padLeft(s: string, length: number) {
264+
while (s.length < length) {
265+
s = " " + s;
266+
}
267+
return s;
268+
}
269+
270+
export function formatDiagnosticsWithColorAndContext(diagnostics: Diagnostic[], host: FormatDiagnosticsHost): string {
271+
let output = "";
272+
for (const diagnostic of diagnostics) {
273+
if (diagnostic.file) {
274+
const { start, length, file } = diagnostic;
275+
const { line: firstLine, character: firstLineChar } = getLineAndCharacterOfPosition(file, start);
276+
const { line: lastLine, character: lastLineChar } = getLineAndCharacterOfPosition(file, start + length);
277+
const lastLineInFile = getLineAndCharacterOfPosition(file, file.text.length).line;
278+
const relativeFileName = host ? convertToRelativePath(file.fileName, host.getCurrentDirectory(), fileName => host.getCanonicalFileName(fileName)) : file.fileName;
279+
280+
const hasMoreThanFiveLines = (lastLine - firstLine) >= 4;
281+
let gutterWidth = (lastLine + 1 + "").length;
282+
if (hasMoreThanFiveLines) {
283+
gutterWidth = Math.max(ellipsis.length, gutterWidth);
284+
}
285+
286+
output += sys.newLine;
287+
for (let i = firstLine; i <= lastLine; i++) {
288+
// If the error spans over 5 lines, we'll only show the first 2 and last 2 lines,
289+
// so we'll skip ahead to the second-to-last line.
290+
if (hasMoreThanFiveLines && firstLine + 1 < i && i < lastLine - 1) {
291+
output += formatAndReset(padLeft(ellipsis, gutterWidth), gutterStyleSequence) + gutterSeparator + sys.newLine;
292+
i = lastLine - 1;
293+
}
294+
295+
const lineStart = getPositionOfLineAndCharacter(file, i, 0);
296+
const lineEnd = i < lastLineInFile ? getPositionOfLineAndCharacter(file, i + 1, 0) : file.text.length;
297+
let lineContent = file.text.slice(lineStart, lineEnd);
298+
lineContent = lineContent.replace(/\s+$/g, ""); // trim from end
299+
lineContent = lineContent.replace("\t", " "); // convert tabs to single spaces
300+
301+
// Output the gutter and the actual contents of the line.
302+
output += formatAndReset(padLeft(i + 1 + "", gutterWidth), gutterStyleSequence) + gutterSeparator;
303+
output += lineContent + sys.newLine;
304+
305+
// Output the gutter and the error span for the line using tildes.
306+
output += formatAndReset(padLeft("", gutterWidth), gutterStyleSequence) + gutterSeparator;
307+
output += redForegroundEscapeSequence;
308+
if (i === firstLine) {
309+
// If we're on the last line, then limit it to the last character of the last line.
310+
// Otherwise, we'll just squiggle the rest of the line, giving 'slice' no end position.
311+
const lastCharForLine = i === lastLine ? lastLineChar : undefined;
312+
313+
output += lineContent.slice(0, firstLineChar).replace(/\S/g, " ");
314+
output += lineContent.slice(firstLineChar, lastCharForLine).replace(/./g, "~");
315+
}
316+
else if (i === lastLine) {
317+
output += lineContent.slice(0, lastLineChar).replace(/./g, "~");
318+
}
319+
else {
320+
// Squiggle the entire line.
321+
output += lineContent.replace(/./g, "~");
322+
}
323+
output += resetEscapeSequence;
324+
325+
output += sys.newLine;
326+
}
327+
328+
output += sys.newLine;
329+
output += `${ relativeFileName }(${ firstLine + 1 },${ firstLineChar + 1 }): `;
330+
}
331+
332+
const categoryColor = getCategoryFormat(diagnostic.category);
333+
const category = DiagnosticCategory[diagnostic.category].toLowerCase();
334+
output += `${ formatAndReset(category, categoryColor) } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }`;
335+
}
336+
return output;
337+
}
338+
244339
export function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain, newLine: string): string {
245340
if (typeof messageText === "string") {
246341
return messageText;

src/compiler/scanner.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -712,11 +712,11 @@ namespace ts {
712712
return accumulator;
713713
}
714714

715-
export function forEachLeadingCommentRange<T, U>(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state?: T) {
715+
export function forEachLeadingCommentRange<T, U>(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state?: T): U | undefined {
716716
return iterateCommentRanges(/*reduce*/ false, text, pos, /*trailing*/ false, cb, state);
717717
}
718718

719-
export function forEachTrailingCommentRange<T, U>(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state?: T) {
719+
export function forEachTrailingCommentRange<T, U>(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state?: T): U | undefined {
720720
return iterateCommentRanges(/*reduce*/ false, text, pos, /*trailing*/ true, cb, state);
721721
}
722722

@@ -746,10 +746,11 @@ namespace ts {
746746
}
747747

748748
/** Optionally, get the shebang */
749-
export function getShebang(text: string): string {
750-
return shebangTriviaRegex.test(text)
751-
? shebangTriviaRegex.exec(text)[0]
752-
: undefined;
749+
export function getShebang(text: string): string | undefined {
750+
const match = shebangTriviaRegex.exec(text);
751+
if (match) {
752+
return match[0];
753+
}
753754
}
754755

755756
export function isIdentifierStart(ch: number, languageVersion: ScriptTarget): boolean {

src/compiler/transformers/esnext.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -929,8 +929,8 @@ namespace ts {
929929
text: `
930930
var __asyncDelegator = (this && this.__asyncDelegator) || function (o) {
931931
var i, p;
932-
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
933-
function verb(n) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; }
932+
return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
933+
function verb(n, f) { if (o[n]) i[n] = function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; }; }
934934
};
935935
`
936936
};

0 commit comments

Comments
 (0)