From 5ef2b47f7aeeed0d205f1dd0c7cdeb52b4a1bec7 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 23 Jul 2015 00:05:53 -0700 Subject: [PATCH 01/13] Update tslint.json for latest versions of tslint Enforces spaces and double quotes again, and enforces no space before the colon for type definitions. --- tslint.json | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tslint.json b/tslint.json index 16a69b81f8..71dc6730de 100644 --- a/tslint.json +++ b/tslint.json @@ -4,20 +4,31 @@ "comment-format": [true, "check-space" ], - "indent": true, + "indent": [true, + "spaces" + ], "one-line": [true, "check-open-brace" ], "no-unreachable": true, "no-use-before-declare": true, "no-var-keyword": true, - "quotemark": true, + "quotemark": [true, + "double" + ], "semicolon": true, "whitespace": [true, "check-branch", "check-operator", "check-separator", "check-type" - ] + ], + "typedef-whitespace": [true, { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + }] } } From e74f0f0f59eae020ca9d32bf8e7a8bb99da852f3 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 31 Jul 2015 10:40:07 -0700 Subject: [PATCH 02/13] Fix issue with exit status by ensuring the same 'diagnostics' variable is reused. --- src/compiler/tsc.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index 6872c4c876..36f8eb226d 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -355,18 +355,20 @@ namespace ts { return { program, exitStatus }; function compileProgram(): ExitStatus { - // First get any syntactic errors. - let diagnostics = program.getSyntacticDiagnostics(); + let diagnostics: Diagnostic[]; + + // First get and report any syntactic errors. + diagnostics = program.getSyntacticDiagnostics(); reportDiagnostics(diagnostics); // If we didn't have any syntactic errors, then also try getting the global and // semantic errors. if (diagnostics.length === 0) { - let diagnostics = program.getGlobalDiagnostics(); + diagnostics = program.getGlobalDiagnostics(); reportDiagnostics(diagnostics); if (diagnostics.length === 0) { - let diagnostics = program.getSemanticDiagnostics(); + diagnostics = program.getSemanticDiagnostics(); reportDiagnostics(diagnostics); } } From 074a33d12036b164f017ad16abd4f432a18e23a8 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 31 Jul 2015 10:41:13 -0700 Subject: [PATCH 03/13] Double quotes. --- src/compiler/tsc.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index 36f8eb226d..4c9ec6beaf 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -14,7 +14,7 @@ namespace ts { let matchResult = /^([a-z]+)([_\-]([a-z]+))?$/.exec(locale.toLowerCase()); if (!matchResult) { - errors.push(createCompilerDiagnostic(Diagnostics.Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1, 'en', 'ja-jp')); + errors.push(createCompilerDiagnostic(Diagnostics.Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1, "en", "ja-jp")); return false; } @@ -49,7 +49,7 @@ namespace ts { } // TODO: Add codePage support for readFile? - let fileContents = ''; + let fileContents = ""; try { fileContents = sys.readFile(filePath); } From 8b8a138bd0fd44c0c87a2615a1f57e0c7e6570b1 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 31 Jul 2015 10:47:36 -0700 Subject: [PATCH 04/13] Use one call to 'reportDiagnostics'. --- src/compiler/tsc.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index 4c9ec6beaf..880180b133 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -359,20 +359,19 @@ namespace ts { // First get and report any syntactic errors. diagnostics = program.getSyntacticDiagnostics(); - reportDiagnostics(diagnostics); // If we didn't have any syntactic errors, then also try getting the global and // semantic errors. if (diagnostics.length === 0) { diagnostics = program.getGlobalDiagnostics(); - reportDiagnostics(diagnostics); if (diagnostics.length === 0) { diagnostics = program.getSemanticDiagnostics(); - reportDiagnostics(diagnostics); } } + reportDiagnostics(diagnostics); + // If the user doesn't want us to emit, then we're done at this point. if (compilerOptions.noEmit) { return diagnostics.length From cd018e1af438481649ec6238d8b114845a579413 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 30 Jul 2015 12:01:21 -0700 Subject: [PATCH 05/13] Adding testcase for extends helper emit when generating system module Testcase for #3655 --- .../reference/systemModuleWithSuperClass.js | 55 +++++++++++++++++++ .../systemModuleWithSuperClass.symbols | 20 +++++++ .../systemModuleWithSuperClass.types | 20 +++++++ .../compiler/systemModuleWithSuperClass.ts | 12 ++++ 4 files changed, 107 insertions(+) create mode 100644 tests/baselines/reference/systemModuleWithSuperClass.js create mode 100644 tests/baselines/reference/systemModuleWithSuperClass.symbols create mode 100644 tests/baselines/reference/systemModuleWithSuperClass.types create mode 100644 tests/cases/compiler/systemModuleWithSuperClass.ts diff --git a/tests/baselines/reference/systemModuleWithSuperClass.js b/tests/baselines/reference/systemModuleWithSuperClass.js new file mode 100644 index 0000000000..f0c41d34fc --- /dev/null +++ b/tests/baselines/reference/systemModuleWithSuperClass.js @@ -0,0 +1,55 @@ +//// [tests/cases/compiler/systemModuleWithSuperClass.ts] //// + +//// [foo.ts] + +export class Foo { + a: string; +} + +//// [bar.ts] +import {Foo} from './foo'; +export class Bar extends Foo { + b: string; +} + +//// [foo.js] +System.register([], function(exports_1) { + var Foo; + return { + setters:[], + execute: function() { + Foo = (function () { + function Foo() { + } + return Foo; + })(); + exports_1("Foo", Foo); + } + } +}); +//// [bar.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +System.register(['./foo'], function(exports_1) { + var foo_1; + var Bar; + return { + setters:[ + function (_foo_1) { + foo_1 = _foo_1; + }], + execute: function() { + Bar = (function (_super) { + __extends(Bar, _super); + function Bar() { + _super.apply(this, arguments); + } + return Bar; + })(foo_1.Foo); + exports_1("Bar", Bar); + } + } +}); diff --git a/tests/baselines/reference/systemModuleWithSuperClass.symbols b/tests/baselines/reference/systemModuleWithSuperClass.symbols new file mode 100644 index 0000000000..4635433347 --- /dev/null +++ b/tests/baselines/reference/systemModuleWithSuperClass.symbols @@ -0,0 +1,20 @@ +=== tests/cases/compiler/foo.ts === + +export class Foo { +>Foo : Symbol(Foo, Decl(foo.ts, 0, 0)) + + a: string; +>a : Symbol(a, Decl(foo.ts, 1, 18)) +} + +=== tests/cases/compiler/bar.ts === +import {Foo} from './foo'; +>Foo : Symbol(Foo, Decl(bar.ts, 0, 8)) + +export class Bar extends Foo { +>Bar : Symbol(Bar, Decl(bar.ts, 0, 26)) +>Foo : Symbol(Foo, Decl(bar.ts, 0, 8)) + + b: string; +>b : Symbol(b, Decl(bar.ts, 1, 30)) +} diff --git a/tests/baselines/reference/systemModuleWithSuperClass.types b/tests/baselines/reference/systemModuleWithSuperClass.types new file mode 100644 index 0000000000..130f53f0ce --- /dev/null +++ b/tests/baselines/reference/systemModuleWithSuperClass.types @@ -0,0 +1,20 @@ +=== tests/cases/compiler/foo.ts === + +export class Foo { +>Foo : Foo + + a: string; +>a : string +} + +=== tests/cases/compiler/bar.ts === +import {Foo} from './foo'; +>Foo : typeof Foo + +export class Bar extends Foo { +>Bar : Bar +>Foo : Foo + + b: string; +>b : string +} diff --git a/tests/cases/compiler/systemModuleWithSuperClass.ts b/tests/cases/compiler/systemModuleWithSuperClass.ts new file mode 100644 index 0000000000..2f1c21f4d4 --- /dev/null +++ b/tests/cases/compiler/systemModuleWithSuperClass.ts @@ -0,0 +1,12 @@ +// @module: system + +// @Filename: foo.ts +export class Foo { + a: string; +} + +// @Filename: bar.ts +import {Foo} from './foo'; +export class Bar extends Foo { + b: string; +} \ No newline at end of file From bfc4dd14da4ee7c3df2ef6dc5fa148530db12ecd Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 31 Jul 2015 11:54:03 -0700 Subject: [PATCH 06/13] Emit the helpers inside the module body Fixes #3655 --- src/compiler/emitter.ts | 24 ++++++++++++------- .../reference/systemModuleWithSuperClass.js | 10 ++++---- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 98c551027f..bef04e5030 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -6259,6 +6259,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write(`], function(${exportFunctionForFile}) {`); writeLine(); increaseIndent(); + emitEmitHelpers(node); emitCaptureThisForNodeIfNecessary(node); emitSystemModuleBody(node, startIndex); decreaseIndent(); @@ -6330,6 +6331,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitAMDModule(node: SourceFile, startIndex: number) { + emitEmitHelpers(node); collectExternalModuleInfo(node); writeLine(); @@ -6351,6 +6353,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitCommonJSModule(node: SourceFile, startIndex: number) { + emitEmitHelpers(node); collectExternalModuleInfo(node); emitExportStarHelper(); emitCaptureThisForNodeIfNecessary(node); @@ -6360,6 +6363,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitUMDModule(node: SourceFile, startIndex: number) { + emitEmitHelpers(node); collectExternalModuleInfo(node); // Module is detected first to support Browserify users that load into a browser with an AMD loader @@ -6389,6 +6393,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi exportSpecifiers = undefined; exportEquals = undefined; hasExportStars = false; + emitEmitHelpers(node); emitCaptureThisForNodeIfNecessary(node); emitLinesStartingAt(node.statements, startIndex); emitTempDeclarations(/*newLine*/ true); @@ -6527,14 +6532,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } } - function emitSourceFileNode(node: SourceFile) { - // Start new file on new line - writeLine(); - emitDetachedComments(node); - - // emit prologue directives prior to __extends - let startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ false); - + function emitEmitHelpers(node: SourceFile): void { // Only emit helpers if the user did not say otherwise. if (!compilerOptions.noEmitHelpers) { // Only Emit __extends function when target ES5. @@ -6562,6 +6560,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi awaiterEmitted = true; } } + } + + function emitSourceFileNode(node: SourceFile) { + // Start new file on new line + writeLine(); + emitDetachedComments(node); + + // emit prologue directives prior to __extends + let startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ false); if (isExternalModule(node) || compilerOptions.isolatedModules) { if (languageVersion >= ScriptTarget.ES6) { @@ -6585,6 +6592,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi exportSpecifiers = undefined; exportEquals = undefined; hasExportStars = false; + emitEmitHelpers(node); emitCaptureThisForNodeIfNecessary(node); emitLinesStartingAt(node.statements, startIndex); emitTempDeclarations(/*newLine*/ true); diff --git a/tests/baselines/reference/systemModuleWithSuperClass.js b/tests/baselines/reference/systemModuleWithSuperClass.js index f0c41d34fc..3484606ee0 100644 --- a/tests/baselines/reference/systemModuleWithSuperClass.js +++ b/tests/baselines/reference/systemModuleWithSuperClass.js @@ -28,12 +28,12 @@ System.register([], function(exports_1) { } }); //// [bar.js] -var __extends = (this && this.__extends) || function (d, b) { - for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); -}; System.register(['./foo'], function(exports_1) { + var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; var foo_1; var Bar; return { From 068889f7b3cff48770f3fd83d45c71f21c1cba3b Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Fri, 31 Jul 2015 18:40:01 -0500 Subject: [PATCH 07/13] Run builds, tests, etc. without global jake --- package.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index db39e0e923..2079c41fdd 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,11 @@ "tslint": "latest" }, "scripts": { - "test": "jake runtests" + "pretest": "jake tests", + "test": "jake runtests", + "build": "npm run build:compiler && npm run build:tests", + "build:compiler": "jake local", + "build:tests": "jake tests", + "clean": "jake clean" } } From 6ea64637e150e6d2dadd8e12f1e2ec6ed0b95002 Mon Sep 17 00:00:00 2001 From: basarat Date: Sat, 1 Aug 2015 18:52:15 +1000 Subject: [PATCH 08/13] scanner for trivia + accept baselines --- src/compiler/scanner.ts | 36 +++++++++++++++++++ src/compiler/types.ts | 3 ++ tests/baselines/reference/APISample_linter.js | 22 ++++++------ 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index d52f96c912..b0ce58ace8 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -401,6 +401,9 @@ namespace ts { case CharacterCodes.greaterThan: // Starts of conflict marker trivia return true; + case CharacterCodes.hash: + // Only if its the beginning can we have #! trivia + return pos === 0; default: return ch > CharacterCodes.maxAsciiCharacter; } @@ -461,6 +464,13 @@ namespace ts { } break; + case CharacterCodes.hash: + if (isShebangTrivia(text, pos)) { + pos = scanShebangTrivia(text, pos); + continue; + } + break; + default: if (ch > CharacterCodes.maxAsciiCharacter && (isWhiteSpace(ch) || isLineBreak(ch))) { pos++; @@ -528,6 +538,20 @@ namespace ts { return pos; } + let shebangTriviaRegex = /^#!.*/; + + function isShebangTrivia(text: string, pos: number) { + // Shebangs check must only be done at the start of the file + Debug.assert(pos === 0); + return shebangTriviaRegex.test(text); + } + + function scanShebangTrivia(text: string, pos: number) { + let shebang = shebangTriviaRegex.exec(text)[0]; + pos = pos + shebang.length; + return pos; + } + // Extract comments from the given source text starting at the given position. If trailing is // false, whitespace is skipped until the first line break and comments between that location // and the next token are returned.If trailing is true, comments occurring between the given @@ -1087,6 +1111,18 @@ namespace ts { return token = SyntaxKind.EndOfFileToken; } let ch = text.charCodeAt(pos); + + // Special handling for shebang + if (ch == CharacterCodes.hash && pos === 0 && isShebangTrivia(text, pos)) { + pos = scanShebangTrivia(text ,pos); + if (skipTrivia) { + continue; + } + else { + return token = SyntaxKind.ShebangTrivia; + } + } + switch (ch) { case CharacterCodes.lineFeed: case CharacterCodes.carriageReturn: diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c5d7f879c2..da43984ee1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -17,6 +17,7 @@ namespace ts { } // token > SyntaxKind.Identifer => token is a keyword + // Also, If you add a new SyntaxKind be sure to keep the `Markers` section at the bottom in sync export const enum SyntaxKind { Unknown, EndOfFileToken, @@ -24,6 +25,8 @@ namespace ts { MultiLineCommentTrivia, NewLineTrivia, WhitespaceTrivia, + // We detect and preserve #! on the first line + ShebangTrivia, // We detect and provide better error recovery when we encounter a git merge marker. This // allows us to edit files with git-conflict markers in them in a much more pleasant manner. ConflictMarkerTrivia, diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index 30951b90fc..9d44dfdc03 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -75,28 +75,28 @@ function delint(sourceFile) { delintNode(sourceFile); function delintNode(node) { switch (node.kind) { - case 196 /* ForStatement */: - case 197 /* ForInStatement */: - case 195 /* WhileStatement */: - case 194 /* DoStatement */: - if (node.statement.kind !== 189 /* Block */) { + case 197 /* ForStatement */: + case 198 /* ForInStatement */: + case 196 /* WhileStatement */: + case 195 /* DoStatement */: + if (node.statement.kind !== 190 /* Block */) { report(node, "A looping statement's contents should be wrapped in a block body."); } break; - case 193 /* IfStatement */: + case 194 /* IfStatement */: var ifStatement = node; - if (ifStatement.thenStatement.kind !== 189 /* Block */) { + if (ifStatement.thenStatement.kind !== 190 /* Block */) { report(ifStatement.thenStatement, "An if statement's contents should be wrapped in a block body."); } if (ifStatement.elseStatement && - ifStatement.elseStatement.kind !== 189 /* Block */ && - ifStatement.elseStatement.kind !== 193 /* IfStatement */) { + ifStatement.elseStatement.kind !== 190 /* Block */ && + ifStatement.elseStatement.kind !== 194 /* IfStatement */) { report(ifStatement.elseStatement, "An else statement's contents should be wrapped in a block body."); } break; - case 178 /* BinaryExpression */: + case 179 /* BinaryExpression */: var op = node.operatorToken.kind; - if (op === 29 /* EqualsEqualsToken */ || op == 30 /* ExclamationEqualsToken */) { + if (op === 30 /* EqualsEqualsToken */ || op == 31 /* ExclamationEqualsToken */) { report(node, "Use '===' and '!=='."); } break; From 82d5a9c1bb1c35050e733c92cb57e28b9d71836d Mon Sep 17 00:00:00 2001 From: basarat Date: Sun, 2 Aug 2015 11:25:55 +1000 Subject: [PATCH 09/13] test(shebang) desired outcome --- tests/baselines/reference/shebang.js | 8 ++++++++ tests/baselines/reference/shebang.symbols | 5 +++++ tests/baselines/reference/shebang.types | 6 ++++++ tests/cases/compiler/shebang.ts | 2 ++ 4 files changed, 21 insertions(+) create mode 100644 tests/baselines/reference/shebang.js create mode 100644 tests/baselines/reference/shebang.symbols create mode 100644 tests/baselines/reference/shebang.types create mode 100644 tests/cases/compiler/shebang.ts diff --git a/tests/baselines/reference/shebang.js b/tests/baselines/reference/shebang.js new file mode 100644 index 0000000000..d7e3a4d835 --- /dev/null +++ b/tests/baselines/reference/shebang.js @@ -0,0 +1,8 @@ +//// [shebang.ts] +#!/usr/bin/env node +var foo = 'I wish the generated JS to be executed in node'; + + +//// [shebang.js] +#!/usr/bin/env node +var foo = 'I wish the generated JS to be executed in node'; diff --git a/tests/baselines/reference/shebang.symbols b/tests/baselines/reference/shebang.symbols new file mode 100644 index 0000000000..37ad543667 --- /dev/null +++ b/tests/baselines/reference/shebang.symbols @@ -0,0 +1,5 @@ +=== tests/cases/compiler/shebang.ts === +#!/usr/bin/env node +var foo = 'I wish the generated JS to be executed in node'; +>foo : Symbol(foo, Decl(shebang.ts, 1, 3)) + diff --git a/tests/baselines/reference/shebang.types b/tests/baselines/reference/shebang.types new file mode 100644 index 0000000000..5fd6f0533e --- /dev/null +++ b/tests/baselines/reference/shebang.types @@ -0,0 +1,6 @@ +=== tests/cases/compiler/shebang.ts === +#!/usr/bin/env node +var foo = 'I wish the generated JS to be executed in node'; +>foo : string +>'I wish the generated JS to be executed in node' : string + diff --git a/tests/cases/compiler/shebang.ts b/tests/cases/compiler/shebang.ts new file mode 100644 index 0000000000..3456df0fad --- /dev/null +++ b/tests/cases/compiler/shebang.ts @@ -0,0 +1,2 @@ +#!/usr/bin/env node +var foo = 'I wish the generated JS to be executed in node'; From 5fcf3d7c902d6e96e81f7dc0880c7e97e451439d Mon Sep 17 00:00:00 2001 From: basarat Date: Sun, 2 Aug 2015 12:24:18 +1000 Subject: [PATCH 10/13] emit shebang --- src/compiler/emitter.ts | 8 ++++++++ src/compiler/scanner.ts | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index bef04e5030..cb5eb86466 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -6565,6 +6565,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi function emitSourceFileNode(node: SourceFile) { // Start new file on new line writeLine(); + emitShebang(); emitDetachedComments(node); // emit prologue directives prior to __extends @@ -6986,6 +6987,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } } } + + function emitShebang() { + let shebang = getShebang(currentSourceFile.text); + if (shebang) { + write(shebang); + } + } function isPinnedOrTripleSlashComment(comment: CommentRange) { if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) { diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index b0ce58ace8..01efc96a86 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -641,6 +641,16 @@ namespace ts { export function getTrailingCommentRanges(text: string, pos: number): CommentRange[] { return getCommentRanges(text, pos, /*trailing*/ true); } + + /** Optionally, get the shebang */ + export function getShebang(text: string): string { + if (!shebangTriviaRegex.test(text)) { + return undefined; + } + else { + return shebangTriviaRegex.exec(text)[0]; + } + } export function isIdentifierStart(ch: number, languageVersion: ScriptTarget): boolean { return ch >= CharacterCodes.A && ch <= CharacterCodes.Z || ch >= CharacterCodes.a && ch <= CharacterCodes.z || From 24c8a8ee5fdd175d1f945fa91fd88dda762ec15a Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Sun, 2 Aug 2015 08:51:50 -0700 Subject: [PATCH 11/13] always set NodeCheckFlags when checking super expression --- src/compiler/checker.ts | 144 ++++++++++-------- .../reference/errorSuperPropertyAccess.js | 12 +- .../reference/parserSuperExpression1.js | 4 +- .../reference/parserSuperExpression2.js | 2 +- .../reference/parserSuperExpression4.js | 4 +- tests/baselines/reference/super.js | 2 +- tests/baselines/reference/super1.js | 2 +- .../superCallWithMissingBaseClass.errors.txt | 15 ++ .../superCallWithMissingBaseClass.js | 30 ++++ .../compiler/superCallWithMissingBaseClass.ts | 9 ++ 10 files changed, 144 insertions(+), 80 deletions(-) create mode 100644 tests/baselines/reference/superCallWithMissingBaseClass.errors.txt create mode 100644 tests/baselines/reference/superCallWithMissingBaseClass.js create mode 100644 tests/cases/compiler/superCallWithMissingBaseClass.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2ff2c8590d..c37189488b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6436,22 +6436,79 @@ namespace ts { let classType = classDeclaration && getDeclaredTypeOfSymbol(getSymbolOfNode(classDeclaration)); let baseClassType = classType && getBaseTypes(classType)[0]; + let container = getSuperContainer(node, /*includeFunctions*/ true); + let needToCaptureLexicalThis = false; + + if (!isCallExpression) { + // adjust the container reference in case if super is used inside arrow functions with arbitrary deep nesting + while (container && container.kind === SyntaxKind.ArrowFunction) { + container = getSuperContainer(container, /*includeFunctions*/ true); + needToCaptureLexicalThis = languageVersion < ScriptTarget.ES6; + } + } + + let canUseSuperExpression = isLegalUsageOfSuperExpression(container); + let nodeCheckFlag: NodeCheckFlags = 0; + + // always set NodeCheckFlags for 'super' expression node + if (canUseSuperExpression) { + if ((container.flags & NodeFlags.Static) || isCallExpression) { + nodeCheckFlag = NodeCheckFlags.SuperStatic; + } + else { + nodeCheckFlag = NodeCheckFlags.SuperInstance; + } + + getNodeLinks(node).flags |= nodeCheckFlag; + + if (needToCaptureLexicalThis) { + // call expressions are allowed only in constructors so they should always capture correct 'this' + // super property access expressions can also appear in arrow functions - + // in this case they should also use correct lexical this + captureLexicalThis(node.parent, container); + } + } + if (!baseClassType) { if (!classDeclaration || !getClassExtendsHeritageClauseElement(classDeclaration)) { error(node, Diagnostics.super_can_only_be_referenced_in_a_derived_class); } + return unknownType; + } + + if (!canUseSuperExpression) { + if (container && container.kind === SyntaxKind.ComputedPropertyName) { + error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name); + } + else if (isCallExpression) { + error(node, Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors); + } + else { + error(node, Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class); + } + return unknownType; } + + if (container.kind === SyntaxKind.Constructor && isInConstructorArgumentInitializer(node, container)) { + // issue custom error message for super property access in constructor arguments (to be aligned with old compiler) + error(node, Diagnostics.super_cannot_be_referenced_in_constructor_arguments); + return unknownType; + } + + return nodeCheckFlag === NodeCheckFlags.SuperStatic + ? getBaseConstructorTypeOfClass(classType) + : baseClassType; + + function isLegalUsageOfSuperExpression(container: Node): boolean { + if (!container) { + return false; + } - let container = getSuperContainer(node, /*includeFunctions*/ true); - - if (container) { - let canUseSuperExpression = false; - let needToCaptureLexicalThis: boolean; if (isCallExpression) { // TS 1.0 SPEC (April 2014): 4.8.1 // Super calls are only permitted in constructors of derived classes - canUseSuperExpression = container.kind === SyntaxKind.Constructor; + return container.kind === SyntaxKind.Constructor; } else { // TS 1.0 SPEC (April 2014) @@ -6459,75 +6516,28 @@ namespace ts { // - In a constructor, instance member function, instance member accessor, or instance member variable initializer where this references a derived class instance // - In a static member function or static member accessor - // super property access might appear in arrow functions with arbitrary deep nesting - needToCaptureLexicalThis = false; - while (container && container.kind === SyntaxKind.ArrowFunction) { - container = getSuperContainer(container, /*includeFunctions*/ true); - needToCaptureLexicalThis = languageVersion < ScriptTarget.ES6; - } - // topmost container must be something that is directly nested in the class declaration if (container && isClassLike(container.parent)) { if (container.flags & NodeFlags.Static) { - canUseSuperExpression = - container.kind === SyntaxKind.MethodDeclaration || - container.kind === SyntaxKind.MethodSignature || - container.kind === SyntaxKind.GetAccessor || - container.kind === SyntaxKind.SetAccessor; + return container.kind === SyntaxKind.MethodDeclaration || + container.kind === SyntaxKind.MethodSignature || + container.kind === SyntaxKind.GetAccessor || + container.kind === SyntaxKind.SetAccessor; } else { - canUseSuperExpression = - container.kind === SyntaxKind.MethodDeclaration || - container.kind === SyntaxKind.MethodSignature || - container.kind === SyntaxKind.GetAccessor || - container.kind === SyntaxKind.SetAccessor || - container.kind === SyntaxKind.PropertyDeclaration || - container.kind === SyntaxKind.PropertySignature || - container.kind === SyntaxKind.Constructor; + return container.kind === SyntaxKind.MethodDeclaration || + container.kind === SyntaxKind.MethodSignature || + container.kind === SyntaxKind.GetAccessor || + container.kind === SyntaxKind.SetAccessor || + container.kind === SyntaxKind.PropertyDeclaration || + container.kind === SyntaxKind.PropertySignature || + container.kind === SyntaxKind.Constructor; } } } - - if (canUseSuperExpression) { - let returnType: Type; - - if ((container.flags & NodeFlags.Static) || isCallExpression) { - getNodeLinks(node).flags |= NodeCheckFlags.SuperStatic; - returnType = getBaseConstructorTypeOfClass(classType); - } - else { - getNodeLinks(node).flags |= NodeCheckFlags.SuperInstance; - returnType = baseClassType; - } - - if (container.kind === SyntaxKind.Constructor && isInConstructorArgumentInitializer(node, container)) { - // issue custom error message for super property access in constructor arguments (to be aligned with old compiler) - error(node, Diagnostics.super_cannot_be_referenced_in_constructor_arguments); - returnType = unknownType; - } - - if (!isCallExpression && needToCaptureLexicalThis) { - // call expressions are allowed only in constructors so they should always capture correct 'this' - // super property access expressions can also appear in arrow functions - - // in this case they should also use correct lexical this - captureLexicalThis(node.parent, container); - } - - return returnType; - } - } - - if (container && container.kind === SyntaxKind.ComputedPropertyName) { - error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name); - } - else if (isCallExpression) { - error(node, Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors); - } - else { - error(node, Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class); - } - - return unknownType; + + return false; + } } // Return contextual type of parameter or undefined if no contextual type is available diff --git a/tests/baselines/reference/errorSuperPropertyAccess.js b/tests/baselines/reference/errorSuperPropertyAccess.js index 57a574d8a0..6e35248cd3 100644 --- a/tests/baselines/reference/errorSuperPropertyAccess.js +++ b/tests/baselines/reference/errorSuperPropertyAccess.js @@ -139,14 +139,14 @@ var __extends = (this && this.__extends) || function (d, b) { //super property access in instance member accessor(get and set) of class with no base type var NoBase = (function () { function NoBase() { - this.m = _super.prototype; - this.n = _super.hasOwnProperty.call(this, ''); - var a = _super.prototype; - var b = _super.hasOwnProperty.call(this, ''); + this.m = _super.prototype.prototype; + this.n = _super.prototype.hasOwnProperty.call(this, ''); + var a = _super.prototype.prototype; + var b = _super.prototype.hasOwnProperty.call(this, ''); } NoBase.prototype.fn = function () { - var a = _super.prototype; - var b = _super.hasOwnProperty.call(this, ''); + var a = _super.prototype.prototype; + var b = _super.prototype.hasOwnProperty.call(this, ''); }; //super static property access in static member function of class with no base type //super static property access in static member accessor(get and set) of class with no base type diff --git a/tests/baselines/reference/parserSuperExpression1.js b/tests/baselines/reference/parserSuperExpression1.js index 0d312f7910..0d219afad3 100644 --- a/tests/baselines/reference/parserSuperExpression1.js +++ b/tests/baselines/reference/parserSuperExpression1.js @@ -18,7 +18,7 @@ var C = (function () { function C() { } C.prototype.foo = function () { - _super.foo.call(this); + _super.prototype.foo.call(this); }; return C; })(); @@ -30,7 +30,7 @@ var M1; function C() { } C.prototype.foo = function () { - _super.foo.call(this); + _super.prototype.foo.call(this); }; return C; })(); diff --git a/tests/baselines/reference/parserSuperExpression2.js b/tests/baselines/reference/parserSuperExpression2.js index 7a77c28ef5..eb3c2c697e 100644 --- a/tests/baselines/reference/parserSuperExpression2.js +++ b/tests/baselines/reference/parserSuperExpression2.js @@ -10,7 +10,7 @@ var C = (function () { function C() { } C.prototype.M = function () { - _super..call(this, 0); + _super.prototype..call(this, 0); }; return C; })(); diff --git a/tests/baselines/reference/parserSuperExpression4.js b/tests/baselines/reference/parserSuperExpression4.js index 46ffc65f57..59ba63bb2c 100644 --- a/tests/baselines/reference/parserSuperExpression4.js +++ b/tests/baselines/reference/parserSuperExpression4.js @@ -18,7 +18,7 @@ var C = (function () { function C() { } C.prototype.foo = function () { - _super.foo = 1; + _super.prototype.foo = 1; }; return C; })(); @@ -30,7 +30,7 @@ var M1; function C() { } C.prototype.foo = function () { - _super.foo = 1; + _super.prototype.foo = 1; }; return C; })(); diff --git a/tests/baselines/reference/super.js b/tests/baselines/reference/super.js index a6b698413e..1d060672ce 100644 --- a/tests/baselines/reference/super.js +++ b/tests/baselines/reference/super.js @@ -79,7 +79,7 @@ var Base2 = (function () { function Base2() { } Base2.prototype.foo = function () { - _super.foo.call(this); + _super.prototype.foo.call(this); }; return Base2; })(); diff --git a/tests/baselines/reference/super1.js b/tests/baselines/reference/super1.js index 6a52cfcd9e..5c2182d8af 100644 --- a/tests/baselines/reference/super1.js +++ b/tests/baselines/reference/super1.js @@ -165,7 +165,7 @@ var Base4; function Sub4E() { } Sub4E.prototype.x = function () { - return _super.x.call(this); + return _super.prototype.x.call(this); }; return Sub4E; })(); diff --git a/tests/baselines/reference/superCallWithMissingBaseClass.errors.txt b/tests/baselines/reference/superCallWithMissingBaseClass.errors.txt new file mode 100644 index 0000000000..0f4e4b7dd1 --- /dev/null +++ b/tests/baselines/reference/superCallWithMissingBaseClass.errors.txt @@ -0,0 +1,15 @@ +tests/cases/compiler/superCallWithMissingBaseClass.ts(1,19): error TS2304: Cannot find name 'Bar'. + + +==== tests/cases/compiler/superCallWithMissingBaseClass.ts (1 errors) ==== + class Foo extends Bar { + ~~~ +!!! error TS2304: Cannot find name 'Bar'. + m1() { + return super.m1(); + } + + static m2() { + return super.m2(); + } + } \ No newline at end of file diff --git a/tests/baselines/reference/superCallWithMissingBaseClass.js b/tests/baselines/reference/superCallWithMissingBaseClass.js new file mode 100644 index 0000000000..101e709653 --- /dev/null +++ b/tests/baselines/reference/superCallWithMissingBaseClass.js @@ -0,0 +1,30 @@ +//// [superCallWithMissingBaseClass.ts] +class Foo extends Bar { + m1() { + return super.m1(); + } + + static m2() { + return super.m2(); + } +} + +//// [superCallWithMissingBaseClass.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var Foo = (function (_super) { + __extends(Foo, _super); + function Foo() { + _super.apply(this, arguments); + } + Foo.prototype.m1 = function () { + return _super.prototype.m1.call(this); + }; + Foo.m2 = function () { + return _super.m2.call(this); + }; + return Foo; +})(Bar); diff --git a/tests/cases/compiler/superCallWithMissingBaseClass.ts b/tests/cases/compiler/superCallWithMissingBaseClass.ts new file mode 100644 index 0000000000..6f7ede1019 --- /dev/null +++ b/tests/cases/compiler/superCallWithMissingBaseClass.ts @@ -0,0 +1,9 @@ +class Foo extends Bar { + m1() { + return super.m1(); + } + + static m2() { + return super.m2(); + } +} \ No newline at end of file From 9754ec10e2f8f9906bc8f21f5b2744fd919ea0c2 Mon Sep 17 00:00:00 2001 From: Basarat Syed Date: Mon, 3 Aug 2015 11:20:43 +1000 Subject: [PATCH 12/13] test(shebang) error case --- .../reference/shebangError.errors.txt | 20 +++++++++++++++++++ tests/baselines/reference/shebangError.js | 8 ++++++++ tests/cases/compiler/shebangError.ts | 2 ++ 3 files changed, 30 insertions(+) create mode 100644 tests/baselines/reference/shebangError.errors.txt create mode 100644 tests/baselines/reference/shebangError.js create mode 100644 tests/cases/compiler/shebangError.ts diff --git a/tests/baselines/reference/shebangError.errors.txt b/tests/baselines/reference/shebangError.errors.txt new file mode 100644 index 0000000000..e8197d8bc5 --- /dev/null +++ b/tests/baselines/reference/shebangError.errors.txt @@ -0,0 +1,20 @@ +tests/cases/compiler/shebangError.ts(2,1): error TS1127: Invalid character. +tests/cases/compiler/shebangError.ts(2,2): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type. +tests/cases/compiler/shebangError.ts(2,12): error TS2304: Cannot find name 'env'. +tests/cases/compiler/shebangError.ts(2,16): error TS1005: ';' expected. +tests/cases/compiler/shebangError.ts(2,16): error TS2304: Cannot find name 'node'. + + +==== tests/cases/compiler/shebangError.ts (5 errors) ==== + var foo = 'Shebang is only allowed on the first line'; + #!/usr/bin/env node + +!!! error TS1127: Invalid character. + ~~~~~~~~~ +!!! error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type. + ~~~ +!!! error TS2304: Cannot find name 'env'. + ~~~~ +!!! error TS1005: ';' expected. + ~~~~ +!!! error TS2304: Cannot find name 'node'. \ No newline at end of file diff --git a/tests/baselines/reference/shebangError.js b/tests/baselines/reference/shebangError.js new file mode 100644 index 0000000000..a8fb376d8a --- /dev/null +++ b/tests/baselines/reference/shebangError.js @@ -0,0 +1,8 @@ +//// [shebangError.ts] +var foo = 'Shebang is only allowed on the first line'; +#!/usr/bin/env node + +//// [shebangError.js] +var foo = 'Shebang is only allowed on the first line'; +!/usr/bin / env; +node; diff --git a/tests/cases/compiler/shebangError.ts b/tests/cases/compiler/shebangError.ts new file mode 100644 index 0000000000..91a27a65aa --- /dev/null +++ b/tests/cases/compiler/shebangError.ts @@ -0,0 +1,2 @@ +var foo = 'Shebang is only allowed on the first line'; +#!/usr/bin/env node \ No newline at end of file From e0a7627f12844d0a2c4827bf903881c595c7134b Mon Sep 17 00:00:00 2001 From: Basarat Syed Date: Mon, 3 Aug 2015 11:28:47 +1000 Subject: [PATCH 13/13] CR feedback --- src/compiler/scanner.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 01efc96a86..379177a9b9 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -538,7 +538,7 @@ namespace ts { return pos; } - let shebangTriviaRegex = /^#!.*/; + const shebangTriviaRegex = /^#!.*/; function isShebangTrivia(text: string, pos: number) { // Shebangs check must only be done at the start of the file @@ -644,12 +644,9 @@ namespace ts { /** Optionally, get the shebang */ export function getShebang(text: string): string { - if (!shebangTriviaRegex.test(text)) { - return undefined; - } - else { - return shebangTriviaRegex.exec(text)[0]; - } + return shebangTriviaRegex.test(text) + ? shebangTriviaRegex.exec(text)[0] + : undefined; } export function isIdentifierStart(ch: number, languageVersion: ScriptTarget): boolean { @@ -1123,7 +1120,7 @@ namespace ts { let ch = text.charCodeAt(pos); // Special handling for shebang - if (ch == CharacterCodes.hash && pos === 0 && isShebangTrivia(text, pos)) { + if (ch === CharacterCodes.hash && pos === 0 && isShebangTrivia(text, pos)) { pos = scanShebangTrivia(text ,pos); if (skipTrivia) { continue;