From 8a8a412a7f24542a6b9ed1255ec7e67eadaa2c48 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 14 Jul 2015 16:51:22 -0700 Subject: [PATCH 01/37] Fix file endings. --- src/compiler/program.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 5ce4846b43b..ca12f6de03d 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -341,7 +341,7 @@ namespace ts { }); } - function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] { + function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] { return runWithCancellationToken(() => { if (!isDeclarationFile(sourceFile)) { let resolver = getDiagnosticsProducingTypeChecker().getEmitResolver(sourceFile, cancellationToken); @@ -350,7 +350,7 @@ namespace ts { return ts.getDeclarationDiagnostics(getEmitHost(writeFile), resolver, sourceFile); } }); - } + } function getOptionsDiagnostics(): Diagnostic[] { let allDiagnostics: Diagnostic[] = []; From b8b4c0f5d4a5b72f3418e502f97ef1ede6769ed9 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 14 Jul 2015 17:25:34 -0700 Subject: [PATCH 02/37] Bump version number. --- package.json | 2 +- src/compiler/program.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 82ab734d6f1..54162c53a57 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "typescript", "author": "Microsoft Corp.", "homepage": "http://typescriptlang.org/", - "version": "1.5.3", + "version": "1.6.0", "license": "Apache-2.0", "description": "TypeScript is a language for application scale JavaScript development", "keywords": [ diff --git a/src/compiler/program.ts b/src/compiler/program.ts index ca12f6de03d..d79f617e1cf 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -8,7 +8,7 @@ namespace ts { /* @internal */ export let ioWriteTime = 0; /** The version of the TypeScript compiler release */ - export const version = "1.5.3"; + export const version = "1.6.0"; export function findConfigFile(searchPath: string): string { let fileName = "tsconfig.json"; From 86b84054506ce6669175141de9655482ed510241 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 14 Jul 2015 18:09:42 -0700 Subject: [PATCH 03/37] Add configureNightly script. --- .gitignore | 1 + scripts/configureNightly.ts | 69 +++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 scripts/configureNightly.ts diff --git a/.gitignore b/.gitignore index 3147b8e8724..58a45545939 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ tests/baselines/reference/projectOutput/* tests/baselines/local/projectOutput/* tests/services/baselines/prototyping/local/* tests/services/browser/typescriptServices.js +scripts/configureNightly.js scripts/processDiagnosticMessages.d.ts scripts/processDiagnosticMessages.js scripts/importDefinitelyTypedTests.js diff --git a/scripts/configureNightly.ts b/scripts/configureNightly.ts new file mode 100644 index 00000000000..a0e30b007cf --- /dev/null +++ b/scripts/configureNightly.ts @@ -0,0 +1,69 @@ +/// + +/** + * A minimal description for a parsed package.json object. + */ +interface PackageJson { + name: string; + version: string; + keywords: string[]; +} + +function main(): void { + const sys = ts.sys; + if (sys.args.length < 2) { + sys.write("Usage:" + sys.newLine) + sys.write("\tnode configureNightly.js " + sys.newLine); + return; + } + + // Acquire the version from the package.json file and modify it appropriately. + const packageJsonFilePath = ts.normalizePath(sys.args[0]); + const packageJsonContents = sys.readFile(packageJsonFilePath); + const packageJsonValue: PackageJson = JSON.parse(packageJsonContents); + + const nightlyVersion = getNightlyVersionString(packageJsonValue.version); + + // Modify the package.json structure + packageJsonValue.version = nightlyVersion; + + if (packageJsonValue.name !== "typescript-nightly") { + packageJsonValue.name = "typescript-nightly"; + packageJsonValue.keywords.push("nightly", "alpha", "beta", "prerelease"); + } + + // Acquire and modify the source file that exposes the version string. + const tsFilePath = ts.normalizePath(sys.args[1]); + const tsFileContents = sys.readFile(tsFilePath); + const versionAssignmentRegExp = /export\s+const\s+version\s+=\s+".*";/; + const modifiedTsFileContents = tsFileContents.replace(versionAssignmentRegExp, `export const version = "${nightlyVersion}";`); + + // Ensure we are actually changing something - the user probably wants to know that the update failed. + if (tsFileContents === modifiedTsFileContents) { + throw `File '${tsFilePath}' did not contain pattern ${versionAssignmentRegExp}`; + } + + // Finally write the changes to disk. + sys.writeFile(packageJsonFilePath, JSON.stringify(packageJsonValue, /*replacer:*/ undefined, /*space:*/ 4)) + sys.writeFile(tsFilePath, modifiedTsFileContents); +} + +function getNightlyVersionString(versionString: string): string { + // If the version string already contains "-nightly", + // then get the base string and update based on that. + const dashNightlyPos = versionString.indexOf("-nightly"); + if (dashNightlyPos >= 0) { + versionString = versionString.slice(0, dashNightlyPos); + } + + // We're going to append a representation of the current time at the end of the current version. + // String.prototype.toISOString() returns a 24-character string formatted as 'YYYY-MM-DDTHH:mm:ss.sssZ', + // but we'd prefer to just use hyphens as separators instead of 'T', ':', and '.'. + // The trailing 'Z' in this string can be removed; UTC time will always be implicit here. + const now = new Date(); + const timeStr = now.toISOString().slice(0, -1).replace(/:|T|\./g, "-"); + + return `${versionString}-nightly-${timeStr}`; +} + +main(); \ No newline at end of file From 230ccd6262115605b295802861da175b9f254580 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 15 Jul 2015 12:56:00 -0700 Subject: [PATCH 04/37] Added a 'publish-nightly' task to to the Jakefile. --- Jakefile.js | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/Jakefile.js b/Jakefile.js index 33ad46c8b58..b1ec9f3024c 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -311,7 +311,7 @@ var processDiagnosticMessagesTs = path.join(scriptsDirectory, "processDiagnostic var diagnosticMessagesJson = path.join(compilerDirectory, "diagnosticMessages.json"); var diagnosticInfoMapTs = path.join(compilerDirectory, "diagnosticInformationMap.generated.ts"); -file(processDiagnosticMessagesTs) +file(processDiagnosticMessagesTs); // processDiagnosticMessages script compileFile(processDiagnosticMessagesJs, @@ -342,6 +342,65 @@ desc("Generates a diagnostic file in TypeScript based on an input JSON file"); task("generate-diagnostics", [diagnosticInfoMapTs]) +// Publish nightly +var configureNightlyJs = path.join(scriptsDirectory, "configureNightly.js"); +var configureNightlyTs = path.join(scriptsDirectory, "configureNightly.ts"); +var packageJson = "package.json"; +var programTs = path.join(compilerDirectory, "program.ts") + +file(configureNightlyTs); + +compileFile(/*outfile*/configureNightlyJs, + /*sources*/ [configureNightlyTs], + /*prereqs*/ [configureNightlyTs], + /*prefixes*/ [], + /*useBuiltCompiler*/ false, + /*noOutFile*/ false, + /*generateDeclarations*/ false, + /*outDir*/ undefined, + /*preserveConstEnums*/ undefined, + /*keepComments*/ false, + /*noResolve*/ false, + /*stripInternal*/ false, + /*callback*/ function () { + var cmd = "node " + configureNightlyJs + " " + packageJson + " " + programTs; + console.log(cmd); + var ex = jake.createExec([cmd]); + // Add listeners for output and error + ex.addListener("stdout", function(output) { + process.stdout.write(output); + }); + ex.addListener("stderr", function(error) { + process.stderr.write(error); + }); + ex.addListener("cmdEnd", function() { + complete(); + }); + ex.run(); + }); + +task("setDebugModeTrue", function() { + useDebugMode = true; +}); + +desc("Configure, build, test, and publish the nightly release."); +task("publish-nightly", [configureNightlyJs, "LKG", "clean", "setDebugModeTrue", "runtests"], function () { + var cmd = "npm publish"; + console.log(cmd); + var ex = jake.createExec([cmd]); + // Add listeners for output and error + ex.addListener("stdout", function(output) { + process.stdout.write(output); + }); + ex.addListener("stderr", function(error) { + process.stderr.write(error); + }); + ex.addListener("cmdEnd", function() { + complete(); + }); + ex.run(); +}, {async: true}); + // Local target to build the compiler and services var tscFile = path.join(builtLocalDirectory, compilerFilename); compileFile(tscFile, compilerSources, [builtLocalDirectory, copyright].concat(compilerSources), [copyright], /*useBuiltCompiler:*/ false); From 50198247bbd8093923aead123617d9c0c1eae4db Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 15 Jul 2015 14:02:47 -0700 Subject: [PATCH 05/37] Use 'exec'. --- Jakefile.js | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/Jakefile.js b/Jakefile.js index b1ec9f3024c..edfd14fc1af 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -365,18 +365,7 @@ compileFile(/*outfile*/configureNightlyJs, /*callback*/ function () { var cmd = "node " + configureNightlyJs + " " + packageJson + " " + programTs; console.log(cmd); - var ex = jake.createExec([cmd]); - // Add listeners for output and error - ex.addListener("stdout", function(output) { - process.stdout.write(output); - }); - ex.addListener("stderr", function(error) { - process.stderr.write(error); - }); - ex.addListener("cmdEnd", function() { - complete(); - }); - ex.run(); + exec(cmd, completeHandler, errorHandler) }); task("setDebugModeTrue", function() { @@ -387,18 +376,7 @@ desc("Configure, build, test, and publish the nightly release."); task("publish-nightly", [configureNightlyJs, "LKG", "clean", "setDebugModeTrue", "runtests"], function () { var cmd = "npm publish"; console.log(cmd); - var ex = jake.createExec([cmd]); - // Add listeners for output and error - ex.addListener("stdout", function(output) { - process.stdout.write(output); - }); - ex.addListener("stderr", function(error) { - process.stderr.write(error); - }); - ex.addListener("cmdEnd", function() { - complete(); - }); - ex.run(); + exec(cmd, completeHandler, errorHandler) }, {async: true}); // Local target to build the compiler and services From a756b561c5eed5166e26a1f5c1f32ab116ca54a5 Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Fri, 17 Jul 2015 20:54:14 +0300 Subject: [PATCH 06/37] fixed issue #3859 --- src/compiler/checker.ts | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7d022825ea7..e16eb3655d8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10260,7 +10260,8 @@ namespace ts { if (getClassExtendsHeritageClauseElement(node.parent)) { if (containsSuperCall(node.body)) { - // The first statement in the body of a constructor must be a super call if both of the following are true: + // The first statement in the body of a constructor must be a super call(or prologue directives followed by a super call) + // if both of the following are true: // - The containing class is a derived class. // - The constructor declares parameter properties // or the containing class declares instance member variables with initializers. @@ -10270,12 +10271,22 @@ namespace ts { if (superCallShouldBeFirst) { let statements = (node.body).statements; - if (!statements.length || statements[0].kind !== SyntaxKind.ExpressionStatement || !isSuperCallExpression((statements[0]).expression)) { - error(node, Diagnostics.A_super_call_must_be_the_first_statement_in_the_constructor_when_a_class_contains_initialized_properties_or_has_parameter_properties); + let superCallStatement: ExpressionStatement; + for (let i = 0; i < statements.length; i++) { + let statement = statements[i]; + if (statement.kind === SyntaxKind.ExpressionStatement && isSuperCallExpression((statement).expression)) { + superCallStatement = statement; + break; + } + if (!isPrologueDirective(statement)) { + break; + } } - else { + if (!superCallStatement) { + error(node, Diagnostics.A_super_call_must_be_the_first_statement_in_the_constructor_when_a_class_contains_initialized_properties_or_has_parameter_properties); + } else { // In such a required super call, it is a compile-time error for argument expressions to reference this. - markThisReferencesAsErrors((statements[0]).expression); + markThisReferencesAsErrors(superCallStatement.expression); } } } From 62e08fc1ebea105bb85723557a71e8feeaad155a Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Fri, 17 Jul 2015 21:00:46 +0300 Subject: [PATCH 07/37] fixed strictModeInConstructor.error.txt baseline --- .../reference/strictModeInConstructor.errors.txt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/tests/baselines/reference/strictModeInConstructor.errors.txt b/tests/baselines/reference/strictModeInConstructor.errors.txt index 11ba2e26a68..9a80732842a 100644 --- a/tests/baselines/reference/strictModeInConstructor.errors.txt +++ b/tests/baselines/reference/strictModeInConstructor.errors.txt @@ -1,8 +1,7 @@ -tests/cases/compiler/strictModeInConstructor.ts(9,5): error TS2376: A 'super' call must be the first statement in the constructor when a class contains initialized properties or has parameter properties. tests/cases/compiler/strictModeInConstructor.ts(27,5): error TS2376: A 'super' call must be the first statement in the constructor when a class contains initialized properties or has parameter properties. -==== tests/cases/compiler/strictModeInConstructor.ts (2 errors) ==== +==== tests/cases/compiler/strictModeInConstructor.ts (1 errors) ==== class A { } @@ -12,14 +11,9 @@ tests/cases/compiler/strictModeInConstructor.ts(27,5): error TS2376: A 'super' c public s: number = 9; constructor () { - ~~~~~~~~~~~~~~~~ "use strict"; // No error - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ super(); - ~~~~~~~~~~~~~~~~ } - ~~~~~ -!!! error TS2376: A 'super' call must be the first statement in the constructor when a class contains initialized properties or has parameter properties. } class C extends A { From b4f82aa3f7f9cdec6c62f42e08a04d4205930c06 Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Sat, 18 Jul 2015 01:36:59 +0300 Subject: [PATCH 08/37] fixed indent issue, changed "for" loop to "for of" loop --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e16eb3655d8..dd5bbacaa3b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10272,8 +10272,7 @@ namespace ts { if (superCallShouldBeFirst) { let statements = (node.body).statements; let superCallStatement: ExpressionStatement; - for (let i = 0; i < statements.length; i++) { - let statement = statements[i]; + for (let statement of statements) { if (statement.kind === SyntaxKind.ExpressionStatement && isSuperCallExpression((statement).expression)) { superCallStatement = statement; break; @@ -10284,7 +10283,8 @@ namespace ts { } if (!superCallStatement) { error(node, Diagnostics.A_super_call_must_be_the_first_statement_in_the_constructor_when_a_class_contains_initialized_properties_or_has_parameter_properties); - } else { + } + else { // In such a required super call, it is a compile-time error for argument expressions to reference this. markThisReferencesAsErrors(superCallStatement.expression); } From 58cf926b2677a1c2f994beb5c42555210d1927e2 Mon Sep 17 00:00:00 2001 From: "shyyko.serhiy@gmail.com" Date: Sat, 18 Jul 2015 02:45:26 +0300 Subject: [PATCH 09/37] added comments --- src/compiler/checker.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dd5bbacaa3b..81f6deaa09b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10260,7 +10260,7 @@ namespace ts { if (getClassExtendsHeritageClauseElement(node.parent)) { if (containsSuperCall(node.body)) { - // The first statement in the body of a constructor must be a super call(or prologue directives followed by a super call) + // The first statement in the body of a constructor (excluding prologue directives) must be a super call // if both of the following are true: // - The containing class is a derived class. // - The constructor declares parameter properties @@ -10269,6 +10269,8 @@ namespace ts { forEach((node.parent).members, isInstancePropertyWithInitializer) || forEach(node.parameters, p => p.flags & (NodeFlags.Public | NodeFlags.Private | NodeFlags.Protected)); + // Skip past any prologue directives to find the first statement + // to ensure that it was a super call. if (superCallShouldBeFirst) { let statements = (node.body).statements; let superCallStatement: ExpressionStatement; From d86fd85bd5423910afa8880aed7b136a4f1f0680 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 21 Jul 2015 11:35:05 -0700 Subject: [PATCH 10/37] Correctly identify identifiers inside JSX exprs as expression identifiers --- src/compiler/emitter.ts | 2 ++ .../reference/jsxImportInAttribute.js | 21 ++++++++++++++++++ .../reference/jsxImportInAttribute.symbols | 19 ++++++++++++++++ .../reference/jsxImportInAttribute.types | 22 +++++++++++++++++++ tests/cases/compiler/jsxImportInAttribute.tsx | 14 ++++++++++++ 5 files changed, 78 insertions(+) create mode 100644 tests/baselines/reference/jsxImportInAttribute.js create mode 100644 tests/baselines/reference/jsxImportInAttribute.symbols create mode 100644 tests/baselines/reference/jsxImportInAttribute.types create mode 100644 tests/cases/compiler/jsxImportInAttribute.tsx diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index fd0d4ad796e..3dd06ea4515 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1425,6 +1425,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi case SyntaxKind.IfStatement: case SyntaxKind.JsxSelfClosingElement: case SyntaxKind.JsxOpeningElement: + case SyntaxKind.JsxExpression: case SyntaxKind.NewExpression: case SyntaxKind.ParenthesizedExpression: case SyntaxKind.PostfixUnaryExpression: @@ -1484,6 +1485,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } } else if (languageVersion < ScriptTarget.ES6) { + debugger; let declaration = resolver.getReferencedImportDeclaration(node); if (declaration) { if (declaration.kind === SyntaxKind.ImportClause) { diff --git a/tests/baselines/reference/jsxImportInAttribute.js b/tests/baselines/reference/jsxImportInAttribute.js new file mode 100644 index 00000000000..40b21e87c3f --- /dev/null +++ b/tests/baselines/reference/jsxImportInAttribute.js @@ -0,0 +1,21 @@ +//// [tests/cases/compiler/jsxImportInAttribute.tsx] //// + +//// [component.d.ts] + +declare module "Test" { + export default class Text { } +} + +//// [consumer.tsx] +/// +import Test from 'Test'; + +let x = Test; // emit test_1.default +; // ? + + +//// [consumer.jsx] +/// +var Test_1 = require('Test'); +var x = Test_1["default"]; // emit test_1.default +; // ? diff --git a/tests/baselines/reference/jsxImportInAttribute.symbols b/tests/baselines/reference/jsxImportInAttribute.symbols new file mode 100644 index 00000000000..8481771f085 --- /dev/null +++ b/tests/baselines/reference/jsxImportInAttribute.symbols @@ -0,0 +1,19 @@ +=== tests/cases/compiler/consumer.tsx === +/// +import Test from 'Test'; +>Test : Symbol(Test, Decl(consumer.tsx, 1, 6)) + +let x = Test; // emit test_1.default +>x : Symbol(x, Decl(consumer.tsx, 3, 3)) +>Test : Symbol(Test, Decl(consumer.tsx, 1, 6)) + +; // ? +>attr : Symbol(unknown) + +=== tests/cases/compiler/component.d.ts === + +declare module "Test" { + export default class Text { } +>Text : Symbol(Text, Decl(component.d.ts, 1, 23)) +} + diff --git a/tests/baselines/reference/jsxImportInAttribute.types b/tests/baselines/reference/jsxImportInAttribute.types new file mode 100644 index 00000000000..8dfbe292fe0 --- /dev/null +++ b/tests/baselines/reference/jsxImportInAttribute.types @@ -0,0 +1,22 @@ +=== tests/cases/compiler/consumer.tsx === +/// +import Test from 'Test'; +>Test : typeof Test + +let x = Test; // emit test_1.default +>x : typeof Test +>Test : typeof Test + +; // ? +> : any +>anything : any +>attr : any +>Test : any + +=== tests/cases/compiler/component.d.ts === + +declare module "Test" { + export default class Text { } +>Text : Text +} + diff --git a/tests/cases/compiler/jsxImportInAttribute.tsx b/tests/cases/compiler/jsxImportInAttribute.tsx new file mode 100644 index 00000000000..c4f16f55ddb --- /dev/null +++ b/tests/cases/compiler/jsxImportInAttribute.tsx @@ -0,0 +1,14 @@ +//@jsx: preserve +//@module: commonjs + +//@filename: component.d.ts +declare module "Test" { + export default class Text { } +} + +//@filename: consumer.tsx +/// +import Test from 'Test'; + +let x = Test; // emit test_1.default +; // ? From 4ac078be0e086a43c225b0baacb738f1bc89f6ea Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 21 Jul 2015 12:32:24 -0700 Subject: [PATCH 11/37] Remove debugger statement --- src/compiler/emitter.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 3dd06ea4515..afafc983845 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1485,7 +1485,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } } else if (languageVersion < ScriptTarget.ES6) { - debugger; let declaration = resolver.getReferencedImportDeclaration(node); if (declaration) { if (declaration.kind === SyntaxKind.ImportClause) { From 09caacd4cfceef2fb382689a58729f7ac9cd696d Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Tue, 21 Jul 2015 15:29:12 -0700 Subject: [PATCH 12/37] Move declarations to top of tests\cases\fourslash.ts --- tests/cases/fourslash/fourslash.ts | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index a0463073d8c..b963e9a573c 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -1,3 +1,21 @@ +/// + +// declare var FourSlash; +// module ts { +// export interface SymbolDisplayPart { +// text: string; +// kind: string; +// } +// } + +// DO NOT EDIT ABOVE THIS LINE! +// We want type-completion while we edit this file, but at compile time we don't want to include the above reference +// because we are compiling this file in "--out" mode and don't want to rope in the entire codebase +// for each fourslash test. +// So, the compile script manually modifies the aboce code so that we compile correctly. + +//--------------------------------------------- + // Welcome to the FourSlash syntax guide! // A line in the source text is indicated by four slashes (////) @@ -29,7 +47,7 @@ // type 'fs.' as an alternate way of accessing the top-level objects // (e.g. 'fs.goTo.eof();') -declare var FourSlash; +//--------------------------------------- // Return code used by getEmitOutput function to indicate status of the function // It is a duplicate of the one in types.ts to expose it to testcases in fourslash @@ -698,12 +716,7 @@ module fs { export var format = new FourSlashInterface.format(); export var cancellation = new FourSlashInterface.cancellation(); } -module ts { - export interface SymbolDisplayPart { - text: string; - kind: string; - } -} + function verifyOperationIsCancelled(f) { FourSlash.verifyOperationIsCancelled(f); } From b244d0d26307d3241453f6359c4dd3cb1cd339c6 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Tue, 21 Jul 2015 15:31:30 -0700 Subject: [PATCH 13/37] fixed a reference in a test --- tests/cases/fourslash/addDeclareToFunction.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/cases/fourslash/addDeclareToFunction.ts b/tests/cases/fourslash/addDeclareToFunction.ts index 46e5d123632..a31713fc56f 100644 --- a/tests/cases/fourslash/addDeclareToFunction.ts +++ b/tests/cases/fourslash/addDeclareToFunction.ts @@ -1,7 +1,8 @@ +/// + //// /*1*/function parseInt(s/*2*/:string):number; goTo.marker('2'); edit.deleteAtCaret(':string'.length); goTo.marker('1'); -edit.insert('declare '); - +edit.insert('declare '); \ No newline at end of file From 425941782124d70b82277749523640c37fbf0876 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 21 Jul 2015 15:56:30 -0700 Subject: [PATCH 14/37] hoist top level import equals declarations in System modules --- src/compiler/emitter.ts | 54 ++++++++++++++++--- src/compiler/utilities.ts | 2 +- .../aliasesInSystemModule1.errors.txt | 22 ++++++++ .../reference/aliasesInSystemModule1.js | 42 +++++++++++++++ .../aliasesInSystemModule2.errors.txt | 21 ++++++++ .../reference/aliasesInSystemModule2.js | 41 ++++++++++++++ .../cases/compiler/aliasesInSystemModule1.ts | 18 +++++++ .../cases/compiler/aliasesInSystemModule2.ts | 17 ++++++ 8 files changed, 208 insertions(+), 9 deletions(-) create mode 100644 tests/baselines/reference/aliasesInSystemModule1.errors.txt create mode 100644 tests/baselines/reference/aliasesInSystemModule1.js create mode 100644 tests/baselines/reference/aliasesInSystemModule2.errors.txt create mode 100644 tests/baselines/reference/aliasesInSystemModule2.js create mode 100644 tests/cases/compiler/aliasesInSystemModule1.ts create mode 100644 tests/cases/compiler/aliasesInSystemModule2.ts diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index cca3a8d6713..c77324eefd4 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -5429,17 +5429,43 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi (!isExternalModule(currentSourceFile) && resolver.isTopLevelValueImportEqualsWithEntityName(node))) { emitLeadingComments(node); emitStart(node); - if (isES6ExportedDeclaration(node)) { - write("export "); - write("var "); + + // variable declaration for import-equals declaration can be hoisted in system modules + // in this case 'var' should be omitted and emit should contain only initialization + let variableDeclarationIsHoisted = shouldHoistVariable(node, /*checkIfSourceFileLevelDecl*/ true); + + // is it top level export import v = a.b.c in system module? + // if yes - it needs to be rewritten as exporter('v', v = a.b.c) + let isExported = isSourceFileLevelDeclarationInSystemJsModule(node, /*isExported*/ true); + + if (!variableDeclarationIsHoisted) { + Debug.assert(!isExported); + + if (isES6ExportedDeclaration(node)) { + write("export "); + write("var "); + } + else if (!(node.flags & NodeFlags.Export)) { + write("var "); + } } - else if (!(node.flags & NodeFlags.Export)) { - write("var "); + + + if (isExported) { + write(`${exportFunctionForFile}("`); + emitNodeWithoutSourceMap(node.name); + write(`", `); } + emitModuleMemberName(node); write(" = "); emit(node.moduleReference); - write(";"); + + if (isExported) { + write(")"); + } + + write(";"); emitEnd(node); emitExportImportAssignments(node); emitTrailingComments(node); @@ -5965,6 +5991,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } return; } + + if (isInternalModuleImportEqualsDeclaration(node)) { + if (!hoistedVars) { + hoistedVars = []; + } + + hoistedVars.push(node.name); + return; + } if (isBindingPattern(node)) { forEach((node).elements, visit); @@ -6169,14 +6204,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi writeLine(); for (let i = startIndex; i < node.statements.length; ++i) { let statement = node.statements[i]; - // - imports/exports are not emitted for system modules + // - external module related imports/exports are not emitted for system modules // - function declarations are not emitted because they were already hoisted switch (statement.kind) { case SyntaxKind.ExportDeclaration: case SyntaxKind.ImportDeclaration: - case SyntaxKind.ImportEqualsDeclaration: case SyntaxKind.FunctionDeclaration: continue; + case SyntaxKind.ImportEqualsDeclaration: + if (!isInternalModuleImportEqualsDeclaration(statement)) { + continue; + } } writeLine(); emit(statement); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 9d7877ca6e3..56eb2415cf9 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -965,7 +965,7 @@ namespace ts { return ((node).moduleReference).expression; } - export function isInternalModuleImportEqualsDeclaration(node: Node) { + export function isInternalModuleImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration { return node.kind === SyntaxKind.ImportEqualsDeclaration && (node).moduleReference.kind !== SyntaxKind.ExternalModuleReference; } diff --git a/tests/baselines/reference/aliasesInSystemModule1.errors.txt b/tests/baselines/reference/aliasesInSystemModule1.errors.txt new file mode 100644 index 00000000000..9b89332e458 --- /dev/null +++ b/tests/baselines/reference/aliasesInSystemModule1.errors.txt @@ -0,0 +1,22 @@ +tests/cases/compiler/aliasesInSystemModule1.ts(2,24): error TS2307: Cannot find module 'foo'. + + +==== tests/cases/compiler/aliasesInSystemModule1.ts (1 errors) ==== + + import alias = require('foo'); + ~~~~~ +!!! error TS2307: Cannot find module 'foo'. + import cls = alias.Class; + export import cls2 = alias.Class; + + let x = new alias.Class(); + let y = new cls(); + let z = new cls2(); + + module M { + export import cls = alias.Class; + let x = new alias.Class(); + let y = new cls(); + let z = new cls2(); + } + \ No newline at end of file diff --git a/tests/baselines/reference/aliasesInSystemModule1.js b/tests/baselines/reference/aliasesInSystemModule1.js new file mode 100644 index 00000000000..28ac1e9b4ad --- /dev/null +++ b/tests/baselines/reference/aliasesInSystemModule1.js @@ -0,0 +1,42 @@ +//// [aliasesInSystemModule1.ts] + +import alias = require('foo'); +import cls = alias.Class; +export import cls2 = alias.Class; + +let x = new alias.Class(); +let y = new cls(); +let z = new cls2(); + +module M { + export import cls = alias.Class; + let x = new alias.Class(); + let y = new cls(); + let z = new cls2(); +} + + +//// [aliasesInSystemModule1.js] +System.register(['foo'], function(exports_1) { + var alias; + var cls, cls2, x, y, z, M; + return { + setters:[ + function (_alias) { + alias = _alias; + }], + execute: function() { + cls = alias.Class; + exports_1("cls2", cls2 = alias.Class); + x = new alias.Class(); + y = new cls(); + z = new cls2(); + (function (M) { + M.cls = alias.Class; + var x = new alias.Class(); + var y = new M.cls(); + var z = new cls2(); + })(M || (M = {})); + } + } +}); diff --git a/tests/baselines/reference/aliasesInSystemModule2.errors.txt b/tests/baselines/reference/aliasesInSystemModule2.errors.txt new file mode 100644 index 00000000000..618e61c7f3c --- /dev/null +++ b/tests/baselines/reference/aliasesInSystemModule2.errors.txt @@ -0,0 +1,21 @@ +tests/cases/compiler/aliasesInSystemModule2.ts(2,21): error TS2307: Cannot find module 'foo'. + + +==== tests/cases/compiler/aliasesInSystemModule2.ts (1 errors) ==== + + import {alias} from "foo"; + ~~~~~ +!!! error TS2307: Cannot find module 'foo'. + import cls = alias.Class; + export import cls2 = alias.Class; + + let x = new alias.Class(); + let y = new cls(); + let z = new cls2(); + + module M { + export import cls = alias.Class; + let x = new alias.Class(); + let y = new cls(); + let z = new cls2(); + } \ No newline at end of file diff --git a/tests/baselines/reference/aliasesInSystemModule2.js b/tests/baselines/reference/aliasesInSystemModule2.js new file mode 100644 index 00000000000..0256d03a179 --- /dev/null +++ b/tests/baselines/reference/aliasesInSystemModule2.js @@ -0,0 +1,41 @@ +//// [aliasesInSystemModule2.ts] + +import {alias} from "foo"; +import cls = alias.Class; +export import cls2 = alias.Class; + +let x = new alias.Class(); +let y = new cls(); +let z = new cls2(); + +module M { + export import cls = alias.Class; + let x = new alias.Class(); + let y = new cls(); + let z = new cls2(); +} + +//// [aliasesInSystemModule2.js] +System.register(["foo"], function(exports_1) { + var foo_1; + var cls, cls2, x, y, z, M; + return { + setters:[ + function (_foo_1) { + foo_1 = _foo_1; + }], + execute: function() { + cls = foo_1.alias.Class; + exports_1("cls2", cls2 = foo_1.alias.Class); + x = new foo_1.alias.Class(); + y = new cls(); + z = new cls2(); + (function (M) { + M.cls = foo_1.alias.Class; + var x = new foo_1.alias.Class(); + var y = new M.cls(); + var z = new cls2(); + })(M || (M = {})); + } + } +}); diff --git a/tests/cases/compiler/aliasesInSystemModule1.ts b/tests/cases/compiler/aliasesInSystemModule1.ts new file mode 100644 index 00000000000..33d205e5a07 --- /dev/null +++ b/tests/cases/compiler/aliasesInSystemModule1.ts @@ -0,0 +1,18 @@ +// @module: system +// @isolatedModules: true + +import alias = require('foo'); +import cls = alias.Class; +export import cls2 = alias.Class; + +let x = new alias.Class(); +let y = new cls(); +let z = new cls2(); + +module M { + export import cls = alias.Class; + let x = new alias.Class(); + let y = new cls(); + let z = new cls2(); +} + \ No newline at end of file diff --git a/tests/cases/compiler/aliasesInSystemModule2.ts b/tests/cases/compiler/aliasesInSystemModule2.ts new file mode 100644 index 00000000000..3daa7e5a7bd --- /dev/null +++ b/tests/cases/compiler/aliasesInSystemModule2.ts @@ -0,0 +1,17 @@ +// @module: system +// @isolatedModules: true + +import {alias} from "foo"; +import cls = alias.Class; +export import cls2 = alias.Class; + +let x = new alias.Class(); +let y = new cls(); +let z = new cls2(); + +module M { + export import cls = alias.Class; + let x = new alias.Class(); + let y = new cls(); + let z = new cls2(); +} \ No newline at end of file From 8e93a49c7b6e2e8b964b45a4d0ed651e1aecc182 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 21 Jul 2015 16:05:03 -0700 Subject: [PATCH 15/37] Narrow exported session API, Unit tests for session API --- Jakefile.js | 1 + src/harness/harness.ts | 1 + src/server/session.ts | 90 +++--- tests/cases/unittests/session.ts | 458 +++++++++++++++++++++++++++++++ 4 files changed, 505 insertions(+), 45 deletions(-) create mode 100644 tests/cases/unittests/session.ts diff --git a/Jakefile.js b/Jakefile.js index 33ad46c8b58..9ff73d5af14 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -136,6 +136,7 @@ var harnessSources = [ "services/documentRegistry.ts", "services/preProcessFile.ts", "services/patternMatcher.ts", + "session.ts", "versionCache.ts", "convertToBase64.ts", "transpile.ts" diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 9f26887ff90..cf81e172527 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -29,6 +29,7 @@ var Buffer: BufferConstructor = require('buffer').Buffer; // this will work in the browser via browserify var _chai: typeof chai = require('chai'); var assert: typeof _chai.assert = _chai.assert; +var expect: typeof _chai.expect = _chai.expect; declare var __dirname: string; // Node-specific var global = Function("return this").call(null); diff --git a/src/server/session.ts b/src/server/session.ts index e0c540db18b..47c605f5b47 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -109,13 +109,13 @@ namespace ts.server { } export class Session { - projectService: ProjectService; - pendingOperation = false; - fileHash: ts.Map = {}; - nextFileId = 1; - errorTimer: any; /*NodeJS.Timer | number*/ - immediateId: any; - changeSeq = 0; + protected projectService: ProjectService; + private pendingOperation = false; + private fileHash: ts.Map = {}; + private nextFileId = 1; + private errorTimer: any; /*NodeJS.Timer | number*/ + private immediateId: any; + private changeSeq = 0; constructor( private host: ServerHost, @@ -129,7 +129,7 @@ namespace ts.server { }); } - handleEvent(eventName: string, project: Project, fileName: string) { + private handleEvent(eventName: string, project: Project, fileName: string) { if (eventName == "context") { this.projectService.log("got context event, updating diagnostics for" + fileName, "Info"); this.updateErrorCheck([{ fileName, project }], this.changeSeq, @@ -137,7 +137,7 @@ namespace ts.server { } } - logError(err: Error, cmd: string) { + public logError(err: Error, cmd: string) { var typedErr = err; var msg = "Exception on executing command " + cmd; if (typedErr.message) { @@ -149,11 +149,11 @@ namespace ts.server { this.projectService.log(msg); } - sendLineToClient(line: string) { + private sendLineToClient(line: string) { this.host.write(line + this.host.newLine); } - send(msg: protocol.Message) { + public send(msg: protocol.Message) { var json = JSON.stringify(msg); if (this.logger.isVerbose()) { this.logger.info(msg.type + ": " + json); @@ -162,7 +162,7 @@ namespace ts.server { '\r\n\r\n' + json); } - event(info: any, eventName: string) { + public event(info: any, eventName: string) { var ev: protocol.Event = { seq: 0, type: "event", @@ -172,7 +172,7 @@ namespace ts.server { this.send(ev); } - response(info: any, cmdName: string, reqSeq = 0, errorMsg?: string) { + private response(info: any, cmdName: string, reqSeq = 0, errorMsg?: string) { var res: protocol.Response = { seq: 0, type: "response", @@ -189,11 +189,11 @@ namespace ts.server { this.send(res); } - output(body: any, commandName: string, requestSequence = 0, errorMessage?: string) { + public output(body: any, commandName: string, requestSequence = 0, errorMessage?: string) { this.response(body, commandName, requestSequence, errorMessage); } - semanticCheck(file: string, project: Project) { + private semanticCheck(file: string, project: Project) { try { var diags = project.compilerService.languageService.getSemanticDiagnostics(file); @@ -207,7 +207,7 @@ namespace ts.server { } } - syntacticCheck(file: string, project: Project) { + private syntacticCheck(file: string, project: Project) { try { var diags = project.compilerService.languageService.getSyntacticDiagnostics(file); if (diags) { @@ -220,12 +220,12 @@ namespace ts.server { } } - errorCheck(file: string, project: Project) { + private errorCheck(file: string, project: Project) { this.syntacticCheck(file, project); this.semanticCheck(file, project); } - updateProjectStructure(seq: number, matchSeq: (seq: number) => boolean, ms = 1500) { + private updateProjectStructure(seq: number, matchSeq: (seq: number) => boolean, ms = 1500) { setTimeout(() => { if (matchSeq(seq)) { this.projectService.updateProjectStructure(); @@ -233,7 +233,7 @@ namespace ts.server { }, ms); } - updateErrorCheck(checkList: PendingErrorCheck[], seq: number, + private updateErrorCheck(checkList: PendingErrorCheck[], seq: number, matchSeq: (seq: number) => boolean, ms = 1500, followMs = 200) { if (followMs > ms) { followMs = ms; @@ -269,7 +269,7 @@ namespace ts.server { } } - getDefinition(line: number, offset: number, fileName: string): protocol.FileSpan[] { + private getDefinition(line: number, offset: number, fileName: string): protocol.FileSpan[] { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); if (!project) { @@ -291,7 +291,7 @@ namespace ts.server { })); } - getTypeDefinition(line: number, offset: number, fileName: string): protocol.FileSpan[] { + private getTypeDefinition(line: number, offset: number, fileName: string): protocol.FileSpan[] { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); if (!project) { @@ -313,7 +313,7 @@ namespace ts.server { })); } - getOccurrences(line: number, offset: number, fileName: string): protocol.OccurrencesResponseItem[]{ + private getOccurrences(line: number, offset: number, fileName: string): protocol.OccurrencesResponseItem[]{ fileName = ts.normalizePath(fileName); let project = this.projectService.getProjectForFile(fileName); @@ -343,7 +343,7 @@ namespace ts.server { }); } - getProjectInfo(fileName: string, needFileNameList: boolean): protocol.ProjectInfo { + private getProjectInfo(fileName: string, needFileNameList: boolean): protocol.ProjectInfo { fileName = ts.normalizePath(fileName) let project = this.projectService.getProjectForFile(fileName) @@ -358,7 +358,7 @@ namespace ts.server { return projectInfo; } - getRenameLocations(line: number, offset: number, fileName: string,findInComments: boolean, findInStrings: boolean): protocol.RenameResponseBody { + private getRenameLocations(line: number, offset: number, fileName: string,findInComments: boolean, findInStrings: boolean): protocol.RenameResponseBody { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); if (!project) { @@ -426,7 +426,7 @@ namespace ts.server { return { info: renameInfo, locs: bakedRenameLocs }; } - getReferences(line: number, offset: number, fileName: string): protocol.ReferencesResponseBody { + private getReferences(line: number, offset: number, fileName: string): protocol.ReferencesResponseBody { // TODO: get all projects for this file; report refs for all projects deleting duplicates // can avoid duplicates by eliminating same ref file from subsequent projects var file = ts.normalizePath(fileName); @@ -473,12 +473,12 @@ namespace ts.server { }; } - openClientFile(fileName: string) { + private openClientFile(fileName: string) { var file = ts.normalizePath(fileName); this.projectService.openClientFile(file); } - getQuickInfo(line: number, offset: number, fileName: string): protocol.QuickInfoResponseBody { + private getQuickInfo(line: number, offset: number, fileName: string): protocol.QuickInfoResponseBody { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); if (!project) { @@ -504,7 +504,7 @@ namespace ts.server { }; } - getFormattingEditsForRange(line: number, offset: number, endLine: number, endOffset: number, fileName: string): protocol.CodeEdit[] { + private getFormattingEditsForRange(line: number, offset: number, endLine: number, endOffset: number, fileName: string): protocol.CodeEdit[] { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); if (!project) { @@ -531,7 +531,7 @@ namespace ts.server { }); } - getFormattingEditsAfterKeystroke(line: number, offset: number, key: string, fileName: string): protocol.CodeEdit[] { + private getFormattingEditsAfterKeystroke(line: number, offset: number, key: string, fileName: string): protocol.CodeEdit[] { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); @@ -607,7 +607,7 @@ namespace ts.server { }); } - getCompletions(line: number, offset: number, prefix: string, fileName: string): protocol.CompletionEntry[] { + private getCompletions(line: number, offset: number, prefix: string, fileName: string): protocol.CompletionEntry[] { if (!prefix) { prefix = ""; } @@ -633,7 +633,7 @@ namespace ts.server { }, []).sort((a, b) => a.name.localeCompare(b.name)); } - getCompletionEntryDetails(line: number, offset: number, + private getCompletionEntryDetails(line: number, offset: number, entryNames: string[], fileName: string): protocol.CompletionEntryDetails[] { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); @@ -653,7 +653,7 @@ namespace ts.server { }, []); } - getSignatureHelpItems(line: number, offset: number, fileName: string): protocol.SignatureHelpItems { + private getSignatureHelpItems(line: number, offset: number, fileName: string): protocol.SignatureHelpItems { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); if (!project) { @@ -682,7 +682,7 @@ namespace ts.server { return result; } - getDiagnostics(delay: number, fileNames: string[]) { + private getDiagnostics(delay: number, fileNames: string[]) { var checkList = fileNames.reduce((accum: PendingErrorCheck[], fileName: string) => { fileName = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(fileName); @@ -697,7 +697,7 @@ namespace ts.server { } } - change(line: number, offset: number, endLine: number, endOffset: number, insertString: string, fileName: string) { + private change(line: number, offset: number, endLine: number, endOffset: number, insertString: string, fileName: string) { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); if (project) { @@ -712,7 +712,7 @@ namespace ts.server { } } - reload(fileName: string, tempFileName: string, reqSeq = 0) { + private reload(fileName: string, tempFileName: string, reqSeq = 0) { var file = ts.normalizePath(fileName); var tmpfile = ts.normalizePath(tempFileName); var project = this.projectService.getProjectForFile(file); @@ -725,7 +725,7 @@ namespace ts.server { } } - saveToTmp(fileName: string, tempFileName: string) { + private saveToTmp(fileName: string, tempFileName: string) { var file = ts.normalizePath(fileName); var tmpfile = ts.normalizePath(tempFileName); @@ -735,12 +735,12 @@ namespace ts.server { } } - closeClientFile(fileName: string) { + private closeClientFile(fileName: string) { var file = ts.normalizePath(fileName); this.projectService.closeClientFile(file); } - decorateNavigationBarItem(project: Project, fileName: string, items: ts.NavigationBarItem[]): protocol.NavigationBarItem[] { + private decorateNavigationBarItem(project: Project, fileName: string, items: ts.NavigationBarItem[]): protocol.NavigationBarItem[] { if (!items) { return undefined; } @@ -759,7 +759,7 @@ namespace ts.server { })); } - getNavigationBarItems(fileName: string): protocol.NavigationBarItem[] { + private getNavigationBarItems(fileName: string): protocol.NavigationBarItem[] { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); if (!project) { @@ -775,7 +775,7 @@ namespace ts.server { return this.decorateNavigationBarItem(project, fileName, items); } - getNavigateToItems(searchValue: string, fileName: string, maxResultCount?: number): protocol.NavtoItem[] { + private getNavigateToItems(searchValue: string, fileName: string, maxResultCount?: number): protocol.NavtoItem[] { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); if (!project) { @@ -814,7 +814,7 @@ namespace ts.server { }); } - getBraceMatching(line: number, offset: number, fileName: string): protocol.TextSpan[] { + private getBraceMatching(line: number, offset: number, fileName: string): protocol.TextSpan[] { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); @@ -836,7 +836,7 @@ namespace ts.server { })); } - exit() { + public exit() { } private handlers : Map<(request: protocol.Request) => {response?: any, responseRequired?: boolean}> = { @@ -942,14 +942,14 @@ namespace ts.server { return {response: this.getProjectInfo(file, needFileNameList)}; }, }; - addProtocolHandler(command: string, handler: (request: protocol.Request) => {response?: any, responseRequired: boolean}) { + public addProtocolHandler(command: string, handler: (request: protocol.Request) => {response?: any, responseRequired: boolean}) { if (this.handlers[command]) { throw new Error(`Protocol handler already exists for command "${command}"`); } this.handlers[command] = handler; } - executeCommand(request: protocol.Request) : {response?: any, responseRequired?: boolean} { + public executeCommand(request: protocol.Request) : {response?: any, responseRequired?: boolean} { var handler = this.handlers[request.command]; if (handler) { return handler(request); @@ -960,7 +960,7 @@ namespace ts.server { } } - onMessage(message: string) { + public onMessage(message: string) { if (this.logger.isVerbose()) { this.logger.info("request: " + message); var start = this.hrtime(); diff --git a/tests/cases/unittests/session.ts b/tests/cases/unittests/session.ts new file mode 100644 index 00000000000..53353c12dda --- /dev/null +++ b/tests/cases/unittests/session.ts @@ -0,0 +1,458 @@ +/// + +module ts.server { + let lastWrittenToHost: string, + mockHost: ServerHost = { + args: [], + newLine: '\n', + useCaseSensitiveFileNames: true, + write: (s) => lastWrittenToHost = s, + readFile: () => void 0, + writeFile: () => void 0, + resolvePath: () => void 0, + fileExists: () => false, + directoryExists: () => false, + createDirectory: () => void 0, + getExecutingFilePath: () => void 0, + getCurrentDirectory: () => void 0, + readDirectory: () => void 0, + exit: () => void 0 + }, + mockLogger: Logger = { + close(): void {}, + isVerbose(): boolean { return false; }, + loggingEnabled(): boolean { return false; }, + perftrc(s: string): void {}, + info(s: string): void {}, + startGroup(): void {}, + endGroup(): void {}, + msg(s: string, type?: string): void {}, + }; + + describe('the Session class', () => { + let session:Session, + lastSent:protocol.Message; + + beforeEach(() => { + session = new Session(mockHost, Buffer.byteLength, process.hrtime, mockLogger); + session.send = (msg: protocol.Message) => { + lastSent = msg; + }; + }); + + describe('executeCommand', () => { + it('should throw when commands are executed with invalid arguments', () => { + let req : protocol.FileRequest = { + command: CommandNames.Open, + seq: 0, + type: 'command', + arguments: { + file: undefined + } + }; + + expect(() => session.executeCommand(req)).to.throw(); + }); + it('should output an error response when a command does not exist', () => { + let req : protocol.Request = { + command: 'foobar', + seq: 0, + type: 'command' + }; + + session.executeCommand(req); + + expect(lastSent).to.deep.equal({ + command: CommandNames.Unknown, + type: 'response', + seq: 0, + message: 'Unrecognized JSON command: foobar', + request_seq: 0, + success: false + }); + }); + it('should return a tuple containing the response and if a response is required on success', () => { + let req : protocol.ConfigureRequest = { + command: CommandNames.Configure, + seq: 0, + type: 'command', + arguments: { + hostInfo: 'unit test', + formatOptions: { + newLineCharacter: '`n' + } + } + }; + + expect(session.executeCommand(req)).to.deep.equal({ + responseRequired: false + }); + expect(lastSent).to.deep.equal({ + command: CommandNames.Configure, + type: 'response', + success: true, + request_seq: 0, + seq: 0, + body: undefined + }); + }); + }); + + describe('onMessage', () => { + it('should not throw when commands are executed with invalid arguments', () => { + let i = 0; + for (name in CommandNames) { + if (!Object.prototype.hasOwnProperty.call(CommandNames, name)) { + continue; + } + let req : protocol.Request = { + command: name, + seq: i++, + type: 'command' + }; + session.onMessage(JSON.stringify(req)); + req.seq+=2; + req.arguments = {}; + session.onMessage(JSON.stringify(req)); + req.seq+=2; + req.arguments = null; + session.onMessage(JSON.stringify(req)); + } + }); + it('should output the response for a correctly handled message', () => { + let req : protocol.ConfigureRequest = { + command: CommandNames.Configure, + seq: 0, + type: 'command', + arguments: { + hostInfo: 'unit test', + formatOptions: { + newLineCharacter: '`n' + } + } + }; + + session.onMessage(JSON.stringify(req)); + + expect(lastSent).to.deep.equal({ + command: CommandNames.Configure, + type: 'response', + success: true, + request_seq: 0, + seq: 0, + body: undefined + }); + }); + }); + + describe('exit', () => { + it('is a noop which can be handled by subclasses', () => { + session.exit(); //does nothing, should keep running tests + expect(session).to.exist; + }); + }); + + describe('send', () => { + it('is an overrideable handle which sends protocol messages over the wire', () => { + let msg = {seq: 0, type: 'none'}, + strmsg = JSON.stringify(msg), + len = 1+Buffer.byteLength(strmsg, 'utf8'), + resultMsg = `Content-Length: ${len}\r\n\r\n${strmsg}\n`; + + session.send = Session.prototype.send; + assert(session.send); + expect(session.send(msg)).to.not.exist; + expect(lastWrittenToHost).to.equal(resultMsg); + }); + }); + + describe('addProtocolHandler', () => { + it('can add protocol handlers', () => { + let respBody = { + item: false + }, + command = 'newhandle', + result = { + response: respBody, + responseRequired: true + }; + + session.addProtocolHandler(command, (req) => result); + + expect(session.executeCommand({ + command, + seq: 0, + type: 'command' + })).to.deep.equal(result); + }); + it('throws when a duplicate handler is passed', () => { + let respBody = { + item: false + }, + resp = { + response: respBody, + responseRequired: true + }, + command = 'newhandle'; + + session.addProtocolHandler(command, (req) => resp); + + expect(() => session.addProtocolHandler(command, (req) => resp)) + .to.throw(`Protocol handler already exists for command "${command}"`); + }); + }); + + describe('event', () => { + it('can format event responses and send them', () => { + let evt = 'notify-test', + info = { + test: true + }; + + session.event(info, evt); + + expect(lastSent).to.deep.equal({ + type: 'event', + seq: 0, + event: evt, + body: info + }); + }); + }); + + describe('output', () => { + it('can format command responses and send them', () => { + let body = { + block: { + key: 'value' + } + }, + command = 'test'; + + session.output(body, command); + + expect(lastSent).to.deep.equal({ + seq: 0, + request_seq: 0, + type: 'response', + command, + body: body, + success: true + }); + }); + }); + }); + + describe('how Session is extendable via subclassing', () => { + let TestSession = class extends Session { + lastSent: protocol.Message; + customHandler:string = 'testhandler'; + constructor(){ + super(mockHost, Buffer.byteLength, process.hrtime, mockLogger); + this.addProtocolHandler(this.customHandler, () => { + return {response: undefined, responseRequired: true}; + }); + } + send(msg: protocol.Message) { + this.lastSent = msg; + } + }; + + it('can override methods such as send', () => { + let session = new TestSession(), + body = { + block: { + key: 'value' + } + }, + command = 'test'; + + session.output(body, command); + + expect(session.lastSent).to.deep.equal({ + seq: 0, + request_seq: 0, + type: 'response', + command, + body: body, + success: true + }); + }); + it('can add and respond to new protocol handlers', () => { + let session = new TestSession(); + + expect(session.executeCommand({ + seq: 0, + type: 'command', + command: session.customHandler + })).to.deep.equal({ + response: undefined, + responseRequired: true + }); + }); + it('has access to the project service', () => { + let ServiceSession = class extends TestSession { + constructor() { + super(); + assert(this.projectService); + expect(this.projectService).to.be.instanceOf(ProjectService); + } + }; + new ServiceSession(); + }); + }); + + describe('an example of using the Session API to create an in-process server', () => { + let inProcHost: ServerHost = { + args: [], + newLine: '\n', + useCaseSensitiveFileNames: true, + write: (s) => lastWrittenToHost = s, + readFile: () => void 0, + writeFile: () => void 0, + resolvePath: () => void 0, + fileExists: () => false, + directoryExists: () => false, + createDirectory: () => void 0, + getExecutingFilePath: () => void 0, + getCurrentDirectory: () => void 0, + readDirectory: () => void 0, + exit: () => void 0 + }, + InProcSession = class extends Session { + private queue: protocol.Request[] = []; + constructor(private client: {handle: (msg: protocol.Message) => void}) { + super(inProcHost, Buffer.byteLength, process.hrtime, mockLogger); + this.addProtocolHandler('echo', (req: protocol.Request) => ({ + response: req.arguments, + responseRequired: true + })); + } + + send(msg: protocol.Message) { + this.client.handle(msg); + } + + enqueue(msg: protocol.Request) { + this.queue = [msg].concat(this.queue); + } + + handleRequest(msg: protocol.Request) { + try { + var {response} = this.executeCommand(msg); + } catch (e) { + this.output(undefined, msg.command, msg.seq, e.toString()); + return; + } + if (response) { + this.output(response, msg.command, msg.seq); + } + } + + consumeQueue() { + while (this.queue.length > 0) { + let elem = this.queue[this.queue.length-1]; + this.queue = this.queue.slice(0,this.queue.length-1); + this.handleRequest(elem); + } + } + }, + InProcClient = class { + private server: Session&{enqueue: (msg: protocol.Request) => void}; + private seq: number = 0; + private callbacks: ts.Map<(resp: protocol.Response) => void> = {}; + private eventHandlers: ts.Map<(args: any) => void> = {}; + + handle(msg: protocol.Message): void { + if (msg.type === 'response') { + var response = msg; + if (this.callbacks[response.request_seq]) { + this.callbacks[response.request_seq](response); + delete this.callbacks[response.request_seq]; + } + } else if (msg.type === 'event') { + var event = msg; + this.emit(event.event, event.body); + } + } + + emit(name: string, args: any): void { + if (!this.eventHandlers[name]) { + return; + } + this.eventHandlers[name](args); + } + + on(name: string, handler: (args: any) => void): void { + this.eventHandlers[name] = handler; + } + + connect(session: Session&{enqueue: (msg: protocol.Request) => void}): void { + this.server = session; + } + + execute(command: string, args: any, callback: (resp: protocol.Response) => void): void { + if (!this.server) { + return; + } + this.seq++; + this.server.enqueue({ + seq: this.seq, + type: 'command', + command, + arguments: args + }); + this.callbacks[this.seq] = callback; + } + }; + + it('can be constructed and respond to commands', (done) => { + let cli = new InProcClient(), + session = new InProcSession(cli), + toEcho = { + data: true + }, + toEvent = { + data: false + }, + responses = 0; + + //Connect the client + cli.connect(session); + + //add an event handler + cli.on('testevent', (eventinfo) => { + expect(eventinfo).to.equal(toEvent); + responses++; + expect(responses).to.equal(1); + }); + + //trigger said event from the server + session.event(toEvent,'testevent'); + + //Queue an echo command + cli.execute('echo', toEcho, (resp) => { + assert(resp.success, resp.message); + responses++; + expect(responses).to.equal(2); + expect(resp.body).to.deep.equal(toEcho); + }); + + //Queue a configure command + cli.execute('configure', { + hostInfo: 'unit test', + formatOptions: { + newLineCharacter: '`n' + } + }, (resp) => { + assert(resp.success, resp.message); + responses++; + expect(responses).to.equal(3); + done(); + }); + + //Consume the queue and trigger the callbacks + session.consumeQueue(); + }); + }); +} \ No newline at end of file From d7e6fba4d3a24c641b47a694c4bc8b1a217cb717 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Tue, 21 Jul 2015 16:20:17 -0700 Subject: [PATCH 16/37] fixed some warts --- src/harness/fourslash.ts | 13 +++++-------- tests/cases/fourslash/fourslash.ts | 25 +++---------------------- 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 02ca17cefd7..272f4c1c1dd 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -1875,7 +1875,7 @@ module FourSlash { } } - private verifyProjectInfo(expected: string[]) { + public verifyProjectInfo(expected: string[]) { if (this.testType === FourSlashTestType.Server) { let actual = (this.languageService).getProjectInfo( this.activeFile.fileName, @@ -2057,11 +2057,8 @@ module FourSlash { return result; } - public verifGetScriptLexicalStructureListContains( - name: string, - kind: string, - markerPosition?: number) { - this.taoInvalidReason = 'verifGetScriptLexicalStructureListContains impossible'; + public verifyGetScriptLexicalStructureListContains(name: string, kind: string) { + this.taoInvalidReason = 'verifyGetScriptLexicalStructureListContains impossible'; let items = this.languageService.getNavigationBarItems(this.activeFile.fileName); @@ -2263,7 +2260,7 @@ module FourSlash { return 'line ' + (pos.line + 1) + ', col ' + pos.character; } - private getMarkerByName(markerName: string) { + public getMarkerByName(markerName: string) { let markerPos = this.testData.markerPositions[markerName]; if (markerPos === undefined) { let markerNames: string[] = []; @@ -2738,4 +2735,4 @@ module FourSlash { fileName: fileName }; } -} +} \ No newline at end of file diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index b963e9a573c..3abb7f1cee4 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -1,4 +1,4 @@ -/// +/// // declare var FourSlash; // module ts { @@ -60,7 +60,6 @@ enum EmitReturnStatus { } module FourSlashInterface { - declare var FourSlash; export interface Marker { fileName: string; @@ -219,15 +218,6 @@ module FourSlashInterface { FourSlash.currentTestState.verifyReferencesAtPositionListContains(range.fileName, range.start, range.end, isWriteAccess); } - public implementorsCountIs(count: number) { - FourSlash.currentTestState.verifyImplementorsCountIs(count); - } - - // Add tests for this. - public currentParameterIsVariable() { - FourSlash.currentTestState.verifyCurrentParameterIsVariable(!this.negative); - } - public signatureHelpPresent() { FourSlash.currentTestState.verifySignatureHelpPresent(!this.negative); } @@ -379,14 +369,11 @@ module FourSlashInterface { FourSlash.currentTestState.verifyNoMatchingBracePosition(bracePosition); } - public setVerifyDocComments(val: boolean) { - FourSlash.currentTestState.setVerifyDocComments(val); - } - public getScriptLexicalStructureListCount(count: number) { FourSlash.currentTestState.verifyGetScriptLexicalStructureListCount(count); } + // TODO: figure out what to do with the unused arguments. public getScriptLexicalStructureListContains( name: string, kind: string, @@ -394,13 +381,7 @@ module FourSlashInterface { parentName?: string, isAdditionalSpan?: boolean, markerPosition?: number) { - FourSlash.currentTestState.verifGetScriptLexicalStructureListContains( - name, - kind, - fileName, - parentName, - isAdditionalSpan, - markerPosition); + FourSlash.currentTestState.verifyGetScriptLexicalStructureListContains(name, kind); } public navigationItemsListCount(count: number, searchValue: string, matchKind?: string) { From 8884f3b4f60881f00c510ab71ecf2776900151aa Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 21 Jul 2015 16:26:03 -0700 Subject: [PATCH 17/37] Fix tslint issues --- tests/cases/unittests/session.ts | 43 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/tests/cases/unittests/session.ts b/tests/cases/unittests/session.ts index 53353c12dda..1d7b9572bbb 100644 --- a/tests/cases/unittests/session.ts +++ b/tests/cases/unittests/session.ts @@ -30,8 +30,8 @@ module ts.server { }; describe('the Session class', () => { - let session:Session, - lastSent:protocol.Message; + let session: Session, + lastSent: protocol.Message; beforeEach(() => { session = new Session(mockHost, Buffer.byteLength, process.hrtime, mockLogger); @@ -111,10 +111,10 @@ module ts.server { type: 'command' }; session.onMessage(JSON.stringify(req)); - req.seq+=2; + req.seq += 2; req.arguments = {}; session.onMessage(JSON.stringify(req)); - req.seq+=2; + req.seq += 2; req.arguments = null; session.onMessage(JSON.stringify(req)); } @@ -147,7 +147,7 @@ module ts.server { describe('exit', () => { it('is a noop which can be handled by subclasses', () => { - session.exit(); //does nothing, should keep running tests + session.exit(); // Does nothing, should keep running tests expect(session).to.exist; }); }); @@ -156,7 +156,7 @@ module ts.server { it('is an overrideable handle which sends protocol messages over the wire', () => { let msg = {seq: 0, type: 'none'}, strmsg = JSON.stringify(msg), - len = 1+Buffer.byteLength(strmsg, 'utf8'), + len = 1 + Buffer.byteLength(strmsg, 'utf8'), resultMsg = `Content-Length: ${len}\r\n\r\n${strmsg}\n`; session.send = Session.prototype.send; @@ -246,7 +246,7 @@ module ts.server { describe('how Session is extendable via subclassing', () => { let TestSession = class extends Session { lastSent: protocol.Message; - customHandler:string = 'testhandler'; + customHandler: string = 'testhandler'; constructor(){ super(mockHost, Buffer.byteLength, process.hrtime, mockLogger); this.addProtocolHandler(this.customHandler, () => { @@ -338,8 +338,9 @@ module ts.server { } handleRequest(msg: protocol.Request) { + let response: protocol.Response; try { - var {response} = this.executeCommand(msg); + response = this.executeCommand(msg).response; } catch (e) { this.output(undefined, msg.command, msg.seq, e.toString()); return; @@ -351,27 +352,27 @@ module ts.server { consumeQueue() { while (this.queue.length > 0) { - let elem = this.queue[this.queue.length-1]; - this.queue = this.queue.slice(0,this.queue.length-1); + let elem = this.queue[this.queue.length - 1]; + this.queue = this.queue.slice(0, this.queue.length - 1); this.handleRequest(elem); } } }, InProcClient = class { - private server: Session&{enqueue: (msg: protocol.Request) => void}; + private server: Session & {enqueue: (msg: protocol.Request) => void}; private seq: number = 0; private callbacks: ts.Map<(resp: protocol.Response) => void> = {}; private eventHandlers: ts.Map<(args: any) => void> = {}; handle(msg: protocol.Message): void { if (msg.type === 'response') { - var response = msg; + let response = msg; if (this.callbacks[response.request_seq]) { this.callbacks[response.request_seq](response); delete this.callbacks[response.request_seq]; } } else if (msg.type === 'event') { - var event = msg; + let event = msg; this.emit(event.event, event.body); } } @@ -387,7 +388,7 @@ module ts.server { this.eventHandlers[name] = handler; } - connect(session: Session&{enqueue: (msg: protocol.Request) => void}): void { + connect(session: Session & {enqueue: (msg: protocol.Request) => void}): void { this.server = session; } @@ -417,20 +418,20 @@ module ts.server { }, responses = 0; - //Connect the client + // Connect the client cli.connect(session); - //add an event handler + // Add an event handler cli.on('testevent', (eventinfo) => { expect(eventinfo).to.equal(toEvent); responses++; expect(responses).to.equal(1); }); - //trigger said event from the server - session.event(toEvent,'testevent'); + // Trigger said event from the server + session.event(toEvent, 'testevent'); - //Queue an echo command + // Queue an echo command cli.execute('echo', toEcho, (resp) => { assert(resp.success, resp.message); responses++; @@ -438,7 +439,7 @@ module ts.server { expect(resp.body).to.deep.equal(toEcho); }); - //Queue a configure command + // Queue a configure command cli.execute('configure', { hostInfo: 'unit test', formatOptions: { @@ -451,7 +452,7 @@ module ts.server { done(); }); - //Consume the queue and trigger the callbacks + // Consume the queue and trigger the callbacks session.consumeQueue(); }); }); From 851d361a7dfa4527dd4006de395eb8af68f8bdb9 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Tue, 21 Jul 2015 18:08:41 -0700 Subject: [PATCH 18/37] Move message after guide --- tests/cases/fourslash/fourslash.ts | 44 ++++++++++++++++++------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 3abb7f1cee4..31817fb6890 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -1,21 +1,3 @@ -/// - -// declare var FourSlash; -// module ts { -// export interface SymbolDisplayPart { -// text: string; -// kind: string; -// } -// } - -// DO NOT EDIT ABOVE THIS LINE! -// We want type-completion while we edit this file, but at compile time we don't want to include the above reference -// because we are compiling this file in "--out" mode and don't want to rope in the entire codebase -// for each fourslash test. -// So, the compile script manually modifies the aboce code so that we compile correctly. - -//--------------------------------------------- - // Welcome to the FourSlash syntax guide! // A line in the source text is indicated by four slashes (////) @@ -48,6 +30,32 @@ // (e.g. 'fs.goTo.eof();') //--------------------------------------- +// When editting this file, and only while editing this file, enable the reference comments +// and comment out the declarations in this section to get proper type information. +// Undo these changes before compiling/committing/editing any other fourslash tests. +// The test suite will likely crash if you try 'jake runtests' with reference comments enabled. +// +// Explanation: +// We want type-completion while we edit this file, but at compile time/while editting fourslash tests, +// we don't want to include the following reference because we are compiling this file in "--out" mode and don't want to rope +// in the entire codebase into the compilattion each fourslash test. Additionally, we don't want to expose the +// src/harness/fourslash.ts API's (or the rest of the compiler) because they are unstable and complicate the +// fourslash testing DSL. Finally, in this case, runtime reflection is (much) faster. +// +// TODO: figure out a better solution to the API exposure problem. + +// /// +// /// + +declare var FourSlash; +module ts { + export interface SymbolDisplayPart { + text: string; + kind: string; + } +} + +//--------------------------------------------- // Return code used by getEmitOutput function to indicate status of the function // It is a duplicate of the one in types.ts to expose it to testcases in fourslash From 2f7a597dcaaf8e877ad972878b63516b43f966e1 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Tue, 21 Jul 2015 18:27:01 -0700 Subject: [PATCH 19/37] Qualification --- tests/cases/fourslash/fourslash.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 31817fb6890..0008b33673f 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -30,6 +30,7 @@ // (e.g. 'fs.goTo.eof();') //--------------------------------------- +// For API editors: // When editting this file, and only while editing this file, enable the reference comments // and comment out the declarations in this section to get proper type information. // Undo these changes before compiling/committing/editing any other fourslash tests. From 500cadac5cec5f81a89cf4bbf90f10bd5c69738d Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Wed, 22 Jul 2015 11:58:27 -0700 Subject: [PATCH 20/37] add transpileModule function that can return emitted source map --- .../diagnosticInformationMap.generated.ts | 1 - src/compiler/diagnosticMessages.json | 4 - src/compiler/program.ts | 8 +- src/services/services.ts | 63 +++++++--- .../isolatedModulesSourceMap.errors.txt | 7 -- .../reference/isolatedModulesSourceMap.js | 4 +- .../reference/isolatedModulesSourceMap.js.map | 2 +- .../isolatedModulesSourceMap.sourcemap.txt | 16 ++- .../isolatedModulesSourceMap.symbols | 5 + .../reference/isolatedModulesSourceMap.types | 6 + .../compiler/isolatedModulesSourceMap.ts | 2 +- tests/cases/unittests/transpile.ts | 117 ++++++++++++++---- 12 files changed, 167 insertions(+), 68 deletions(-) delete mode 100644 tests/baselines/reference/isolatedModulesSourceMap.errors.txt create mode 100644 tests/baselines/reference/isolatedModulesSourceMap.symbols create mode 100644 tests/baselines/reference/isolatedModulesSourceMap.types diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index b91399e8ee1..ecea3a76673 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -509,7 +509,6 @@ namespace ts { Option_noEmit_cannot_be_specified_with_option_out_or_outDir: { code: 5040, category: DiagnosticCategory.Error, key: "Option 'noEmit' cannot be specified with option 'out' or 'outDir'." }, Option_noEmit_cannot_be_specified_with_option_declaration: { code: 5041, category: DiagnosticCategory.Error, key: "Option 'noEmit' cannot be specified with option 'declaration'." }, Option_project_cannot_be_mixed_with_source_files_on_a_command_line: { code: 5042, category: DiagnosticCategory.Error, key: "Option 'project' cannot be mixed with source files on a command line." }, - Option_sourceMap_cannot_be_specified_with_option_isolatedModules: { code: 5043, category: DiagnosticCategory.Error, key: "Option 'sourceMap' cannot be specified with option 'isolatedModules'." }, Option_declaration_cannot_be_specified_with_option_isolatedModules: { code: 5044, category: DiagnosticCategory.Error, key: "Option 'declaration' cannot be specified with option 'isolatedModules'." }, Option_noEmitOnError_cannot_be_specified_with_option_isolatedModules: { code: 5045, category: DiagnosticCategory.Error, key: "Option 'noEmitOnError' cannot be specified with option 'isolatedModules'." }, Option_out_cannot_be_specified_with_option_isolatedModules: { code: 5046, category: DiagnosticCategory.Error, key: "Option 'out' cannot be specified with option 'isolatedModules'." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 9fda73740ba..2765d04f400 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2025,10 +2025,6 @@ "category": "Error", "code": 5042 }, - "Option 'sourceMap' cannot be specified with option 'isolatedModules'.": { - "category": "Error", - "code": 5043 - }, "Option 'declaration' cannot be specified with option 'isolatedModules'.": { "category": "Error", "code": 5044 diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 5ce4846b43b..b8f48a0fd63 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -341,7 +341,7 @@ namespace ts { }); } - function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] { + function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] { return runWithCancellationToken(() => { if (!isDeclarationFile(sourceFile)) { let resolver = getDiagnosticsProducingTypeChecker().getEmitResolver(sourceFile, cancellationToken); @@ -350,7 +350,7 @@ namespace ts { return ts.getDeclarationDiagnostics(getEmitHost(writeFile), resolver, sourceFile); } }); - } + } function getOptionsDiagnostics(): Diagnostic[] { let allDiagnostics: Diagnostic[] = []; @@ -602,10 +602,6 @@ namespace ts { function verifyCompilerOptions() { if (options.isolatedModules) { - if (options.sourceMap) { - diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_sourceMap_cannot_be_specified_with_option_isolatedModules)); - } - if (options.declaration) { diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_declaration_cannot_be_specified_with_option_isolatedModules)); } diff --git a/src/services/services.ts b/src/services/services.ts index 16f5b0b91fe..de4004000d4 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1754,18 +1754,31 @@ namespace ts { sourceFile.version = version; sourceFile.scriptSnapshot = scriptSnapshot; } - + + export interface TranspileOptions { + compilerOptions?: CompilerOptions; + fileName?: string; + reportDiagnostics?: boolean; + moduleName?: string; + } + + export interface TranspileOutput { + outputText: string; + diagnostics?: Diagnostic[]; + sourceMapText?: string; + } + /* * This function will compile source text from 'input' argument using specified compiler options. * If not options are provided - it will use a set of default compiler options. - * Extra compiler options that will unconditionally be used bu this function are: + * Extra compiler options that will unconditionally be used by this function are: * - isolatedModules = true * - allowNonTsExtensions = true * - noLib = true * - noResolve = true - */ - export function transpile(input: string, compilerOptions?: CompilerOptions, fileName?: string, diagnostics?: Diagnostic[], moduleName?: string): string { - let options = compilerOptions ? clone(compilerOptions) : getDefaultCompilerOptions(); + */ + export function transpileModule(input: string, transpileOptions?: TranspileOptions): TranspileOutput { + let options = transpileOptions.compilerOptions ? clone(transpileOptions.compilerOptions) : getDefaultCompilerOptions(); options.isolatedModules = true; @@ -1781,23 +1794,30 @@ namespace ts { options.noResolve = true; // Parse - let inputFileName = fileName || "module.ts"; + let inputFileName = transpileOptions.fileName || "module.ts"; let sourceFile = createSourceFile(inputFileName, input, options.target); - if (moduleName) { - sourceFile.moduleName = moduleName; + if (transpileOptions.moduleName) { + sourceFile.moduleName = transpileOptions.moduleName; } let newLine = getNewLineCharacter(options); // Output let outputText: string; + let sourceMapText: string; // Create a compilerHost object to allow the compiler to read and write files let compilerHost: CompilerHost = { getSourceFile: (fileName, target) => fileName === inputFileName ? sourceFile : undefined, writeFile: (name, text, writeByteOrderMark) => { - Debug.assert(outputText === undefined, "Unexpected multiple outputs for the file: " + name); - outputText = text; + if (fileExtensionIs(name, ".map")) { + Debug.assert(sourceMapText === undefined, `Unexpected multiple source map outputs for the file '${name}'`); + sourceMapText = text; + } + else { + Debug.assert(outputText === undefined, "Unexpected multiple outputs for the file: " + name); + outputText = text; + } }, getDefaultLibFileName: () => "lib.d.ts", useCaseSensitiveFileNames: () => false, @@ -1807,16 +1827,29 @@ namespace ts { }; let program = createProgram([inputFileName], options, compilerHost); - - addRange(/*to*/ diagnostics, /*from*/ program.getSyntacticDiagnostics(sourceFile)); - addRange(/*to*/ diagnostics, /*from*/ program.getOptionsDiagnostics()); - + + let diagnostics: Diagnostic[]; + if (transpileOptions.reportDiagnostics) { + diagnostics = []; + addRange(/*to*/ diagnostics, /*from*/ program.getSyntacticDiagnostics(sourceFile)); + addRange(/*to*/ diagnostics, /*from*/ program.getOptionsDiagnostics()); + } // Emit program.emit(); Debug.assert(outputText !== undefined, "Output generation failed"); - return outputText; + return { outputText, diagnostics, sourceMapText }; + } + + /* + * This is a shortcut function for transpileModule - it accepts transpileOptions as parameters and returns only outputText part of the result. + */ + export function transpile(input: string, compilerOptions?: CompilerOptions, fileName?: string, diagnostics?: Diagnostic[], moduleName?: string): string { + let output = transpileModule(input, { compilerOptions, fileName, reportDiagnostics: !!diagnostics, moduleName }); + // addRange correctly handles cases when wither 'from' or 'to' argument is missing + addRange(diagnostics, output.diagnostics); + return output.outputText; } export function createLanguageServiceSourceFile(fileName: string, scriptSnapshot: IScriptSnapshot, scriptTarget: ScriptTarget, version: string, setNodeParents: boolean): SourceFile { diff --git a/tests/baselines/reference/isolatedModulesSourceMap.errors.txt b/tests/baselines/reference/isolatedModulesSourceMap.errors.txt deleted file mode 100644 index 6383e85ecd5..00000000000 --- a/tests/baselines/reference/isolatedModulesSourceMap.errors.txt +++ /dev/null @@ -1,7 +0,0 @@ -error TS5043: Option 'sourceMap' cannot be specified with option 'isolatedModules'. - - -!!! error TS5043: Option 'sourceMap' cannot be specified with option 'isolatedModules'. -==== tests/cases/compiler/isolatedModulesSourceMap.ts (0 errors) ==== - - export var x; \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesSourceMap.js b/tests/baselines/reference/isolatedModulesSourceMap.js index ca6f4b4190e..2722a3ce7ab 100644 --- a/tests/baselines/reference/isolatedModulesSourceMap.js +++ b/tests/baselines/reference/isolatedModulesSourceMap.js @@ -1,7 +1,7 @@ //// [isolatedModulesSourceMap.ts] -export var x; +export var x = 1; //// [isolatedModulesSourceMap.js] -export var x; +export var x = 1; //# sourceMappingURL=isolatedModulesSourceMap.js.map \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesSourceMap.js.map b/tests/baselines/reference/isolatedModulesSourceMap.js.map index 8e505dcda7a..9fa3e0da0d6 100644 --- a/tests/baselines/reference/isolatedModulesSourceMap.js.map +++ b/tests/baselines/reference/isolatedModulesSourceMap.js.map @@ -1,2 +1,2 @@ //// [isolatedModulesSourceMap.js.map] -{"version":3,"file":"isolatedModulesSourceMap.js","sourceRoot":"","sources":["isolatedModulesSourceMap.ts"],"names":[],"mappings":"AACA,WAAW,CAAC,CAAC"} \ No newline at end of file +{"version":3,"file":"isolatedModulesSourceMap.js","sourceRoot":"","sources":["isolatedModulesSourceMap.ts"],"names":[],"mappings":"AACA,WAAW,CAAC,GAAG,CAAC,CAAC"} \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesSourceMap.sourcemap.txt b/tests/baselines/reference/isolatedModulesSourceMap.sourcemap.txt index 5c6b7659bc6..d31445505f7 100644 --- a/tests/baselines/reference/isolatedModulesSourceMap.sourcemap.txt +++ b/tests/baselines/reference/isolatedModulesSourceMap.sourcemap.txt @@ -8,20 +8,26 @@ sources: isolatedModulesSourceMap.ts emittedFile:tests/cases/compiler/isolatedModulesSourceMap.js sourceFile:isolatedModulesSourceMap.ts ------------------------------------------------------------------- ->>>export var x; +>>>export var x = 1; 1 > 2 >^^^^^^^^^^^ 3 > ^ -4 > ^ -5 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +4 > ^^^ +5 > ^ +6 > ^ +7 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >export var 3 > x -4 > ; +4 > = +5 > 1 +6 > ; 1 >Emitted(1, 1) Source(2, 1) + SourceIndex(0) 2 >Emitted(1, 12) Source(2, 12) + SourceIndex(0) 3 >Emitted(1, 13) Source(2, 13) + SourceIndex(0) -4 >Emitted(1, 14) Source(2, 14) + SourceIndex(0) +4 >Emitted(1, 16) Source(2, 16) + SourceIndex(0) +5 >Emitted(1, 17) Source(2, 17) + SourceIndex(0) +6 >Emitted(1, 18) Source(2, 18) + SourceIndex(0) --- >>>//# sourceMappingURL=isolatedModulesSourceMap.js.map \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesSourceMap.symbols b/tests/baselines/reference/isolatedModulesSourceMap.symbols new file mode 100644 index 00000000000..d4ae3c34cf1 --- /dev/null +++ b/tests/baselines/reference/isolatedModulesSourceMap.symbols @@ -0,0 +1,5 @@ +=== tests/cases/compiler/isolatedModulesSourceMap.ts === + +export var x = 1; +>x : Symbol(x, Decl(isolatedModulesSourceMap.ts, 1, 10)) + diff --git a/tests/baselines/reference/isolatedModulesSourceMap.types b/tests/baselines/reference/isolatedModulesSourceMap.types new file mode 100644 index 00000000000..1955fe5da6e --- /dev/null +++ b/tests/baselines/reference/isolatedModulesSourceMap.types @@ -0,0 +1,6 @@ +=== tests/cases/compiler/isolatedModulesSourceMap.ts === + +export var x = 1; +>x : number +>1 : number + diff --git a/tests/cases/compiler/isolatedModulesSourceMap.ts b/tests/cases/compiler/isolatedModulesSourceMap.ts index 31dd4d9f0cf..465941d9a8b 100644 --- a/tests/cases/compiler/isolatedModulesSourceMap.ts +++ b/tests/cases/compiler/isolatedModulesSourceMap.ts @@ -3,4 +3,4 @@ // @target: es6 // @filename: file1.ts -export var x; \ No newline at end of file +export var x = 1; \ No newline at end of file diff --git a/tests/cases/unittests/transpile.ts b/tests/cases/unittests/transpile.ts index fcce034b227..1fd8c860d01 100644 --- a/tests/cases/unittests/transpile.ts +++ b/tests/cases/unittests/transpile.ts @@ -2,58 +2,120 @@ module ts { describe("Transpile", () => { - - function runTest(input: string, compilerOptions: ts.CompilerOptions = {}, fileName?: string, moduleName?: string, expectedOutput?: string, expectedDiagnosticCodes: number[] = []): void { - let diagnostics: Diagnostic[] = []; - let result = transpile(input, compilerOptions, fileName || "file.ts", diagnostics, moduleName); - + + interface TranspileTestSettings { + options?: TranspileOptions; + expectedOutput?: string; + expectedDiagnosticCodes?: number[]; + } + + function checkDiagnostics(diagnostics: Diagnostic[], expectedDiagnosticCodes?: number[]) { + if(!expectedDiagnosticCodes) { + return; + } + for (let i = 0; i < expectedDiagnosticCodes.length; i++) { assert.equal(expectedDiagnosticCodes[i], diagnostics[i] && diagnostics[i].code, `Could not find expeced diagnostic.`); } - assert.equal(diagnostics.length, expectedDiagnosticCodes.length, "Resuting diagnostics count does not match expected"); - - if (expectedOutput !== undefined) { - assert.equal(result, expectedOutput); - } + assert.equal(diagnostics.length, expectedDiagnosticCodes.length, "Resuting diagnostics count does not match expected"); } + + function test(input: string, testSettings: TranspileTestSettings): void { + let diagnostics: Diagnostic[] = []; + + let transpileOptions: TranspileOptions = testSettings.options || {}; + let transpileResult = transpile(input, transpileOptions.compilerOptions, transpileOptions.fileName, diagnostics, transpileOptions.moduleName); + + transpileOptions.reportDiagnostics = true; + let transpileModuleResult = transpileModule(input, transpileOptions); + + checkDiagnostics(diagnostics, testSettings.expectedDiagnosticCodes); + checkDiagnostics(transpileModuleResult.diagnostics, testSettings.expectedDiagnosticCodes); + + if (testSettings.expectedOutput !== undefined) { + assert.equal(transpileResult, testSettings.expectedOutput); + assert.equal(transpileModuleResult.outputText, testSettings.expectedOutput); + } + + // check source maps + if (!transpileOptions.compilerOptions) { + transpileOptions.compilerOptions = {}; + } + + if (!transpileOptions.fileName) { + transpileOptions.fileName = "file.ts"; + } + + transpileOptions.compilerOptions.sourceMap = true; + let transpileModuleResultWithSourceMap = transpileModule(input, transpileOptions); + assert.isTrue(transpileModuleResultWithSourceMap.sourceMapText !== undefined); + + let expectedSourceMapFileName = removeFileExtension(transpileOptions.fileName) + ".js.map"; + let expectedSourceMappingUrlLine = `//# sourceMappingURL=${expectedSourceMapFileName}`; + + if (testSettings.expectedOutput !== undefined) { + assert.equal(transpileModuleResultWithSourceMap.outputText, testSettings.expectedOutput + expectedSourceMappingUrlLine); + } + else { + // expected output is not set, just verify that output text has sourceMappingURL as a last line + let output = transpileModuleResultWithSourceMap.outputText; + assert.isTrue(output.length >= expectedSourceMappingUrlLine.length); + if (output.length === expectedSourceMappingUrlLine.length) { + assert.equal(output, expectedSourceMappingUrlLine); + } + else { + let suffix = getNewLineCharacter(transpileOptions.compilerOptions) + expectedSourceMappingUrlLine + assert.isTrue(output.indexOf(suffix, output.length - suffix.length) !== -1); + } + } + } + it("Generates correct compilerOptions diagnostics", () => { // Expecting 5047: "Option 'isolatedModules' can only be used when either option'--module' is provided or option 'target' is 'ES6' or higher." - runTest(`var x = 0;`, {}, /*fileName*/ undefined, /*moduleName*/undefined, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ [5047]); + test(`var x = 0;`, { expectedDiagnosticCodes: [5047] }); }); it("Generates no diagnostics with valid inputs", () => { // No errors - runTest(`var x = 0;`, { module: ModuleKind.CommonJS }, /*fileName*/ undefined, /*moduleName*/undefined, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ []); + test(`var x = 0;`, { options: { compilerOptions: { module: ModuleKind.CommonJS } } }); }); it("Generates no diagnostics for missing file references", () => { - runTest(`/// -var x = 0;`, - { module: ModuleKind.CommonJS }, /*fileName*/ undefined, /*moduleName*/undefined, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ []); + test(`/// +var x = 0;`, + { options: { compilerOptions: { module: ModuleKind.CommonJS } } }); }); it("Generates no diagnostics for missing module imports", () => { - runTest(`import {a} from "module2";`, - { module: ModuleKind.CommonJS }, /*fileName*/ undefined,/*moduleName*/undefined, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ []); + test(`import {a} from "module2";`, + { options: { compilerOptions: { module: ModuleKind.CommonJS } } }); }); it("Generates expected syntactic diagnostics", () => { - runTest(`a b`, - { module: ModuleKind.CommonJS }, /*fileName*/ undefined, /*moduleName*/undefined, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ [1005]); /// 1005: ';' Expected + test(`a b`, + { options: { compilerOptions: { module: ModuleKind.CommonJS } }, expectedDiagnosticCodes: [1005] }); /// 1005: ';' Expected }); it("Does not generate semantic diagnostics", () => { - runTest(`var x: string = 0;`, - { module: ModuleKind.CommonJS }, /*fileName*/ undefined, /*moduleName*/undefined, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/ []); + test(`var x: string = 0;`, + { options: { compilerOptions: { module: ModuleKind.CommonJS } } }); }); it("Generates module output", () => { - runTest(`var x = 0;`, { module: ModuleKind.AMD }, /*fileName*/ undefined, /*moduleName*/undefined, `define(["require", "exports"], function (require, exports) {\r\n var x = 0;\r\n});\r\n`); + test(`var x = 0;`, + { + options: { compilerOptions: { module: ModuleKind.AMD } }, + expectedOutput: `define(["require", "exports"], function (require, exports) {\r\n var x = 0;\r\n});\r\n` + }); }); it("Uses correct newLine character", () => { - runTest(`var x = 0;`, { module: ModuleKind.CommonJS, newLine: NewLineKind.LineFeed }, /*fileName*/ undefined, /*moduleName*/undefined, `var x = 0;\n`, /*expectedDiagnosticCodes*/ []); + test(`var x = 0;`, + { + options: { compilerOptions: { module: ModuleKind.CommonJS, newLine: NewLineKind.LineFeed } }, + expectedOutput: `var x = 0;\n` + }); }); it("Sets module name", () => { @@ -66,12 +128,15 @@ var x = 0;`, ` }\n` + ` }\n` + `});\n`; - runTest("var x = 1;", { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, /*fileName*/ undefined, "NamedModule", output) + test("var x = 1;", + { + options: { compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, moduleName: "NamedModule" }, + expectedOutput: output + }) }); it("No extra errors for file without extension", () => { - runTest(`var x = 0;`, { module: ModuleKind.CommonJS }, "file", /*moduleName*/undefined, /*expectedOutput*/ undefined, /*expectedDiagnosticCodes*/[]); + test(`var x = 0;`, { options: { compilerOptions: { module: ModuleKind.CommonJS }, fileName: "file" } }); }); - }); } From d6998da76129f8574c4c3b947abd9ba9519cd58b Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Wed, 22 Jul 2015 15:27:25 -0700 Subject: [PATCH 21/37] Add getBaseTypes on TypeObject in services --- src/compiler/checker.ts | 1 + src/compiler/types.ts | 3 +++ src/services/services.ts | 6 ++++++ 3 files changed, 10 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c09b069bee6..cc3341fb594 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -68,6 +68,7 @@ namespace ts { getPropertyOfType, getSignaturesOfType, getIndexTypeOfType, + getBaseTypes, getReturnTypeOfSignature, getSymbolsInScope, getSymbolAtLocation, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8d5596c6f64..21eed30c244 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1404,6 +1404,7 @@ namespace ts { getPropertyOfType(type: Type, propertyName: string): Symbol; getSignaturesOfType(type: Type, kind: SignatureKind): Signature[]; getIndexTypeOfType(type: Type, kind: IndexKind): Type; + getBaseTypes(type: InterfaceType): ObjectType[]; getReturnTypeOfSignature(signature: Signature): Type; getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[]; @@ -1808,7 +1809,9 @@ namespace ts { typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic) outerTypeParameters: TypeParameter[]; // Outer type parameters (undefined if none) localTypeParameters: TypeParameter[]; // Local type parameters (undefined if none) + /* @internal */ resolvedBaseConstructorType?: Type; // Resolved base constructor type of class + /* @internal */ resolvedBaseTypes: ObjectType[]; // Resolved base types } diff --git a/src/services/services.ts b/src/services/services.ts index 16f5b0b91fe..47ccc5c73aa 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -48,6 +48,7 @@ namespace ts { getConstructSignatures(): Signature[]; getStringIndexType(): Type; getNumberIndexType(): Type; + getBaseTypes(): ObjectType[] } export interface Signature { @@ -682,6 +683,11 @@ namespace ts { getNumberIndexType(): Type { return this.checker.getIndexTypeOfType(this, IndexKind.Number); } + getBaseTypes(): ObjectType[] { + return this.flags & (TypeFlags.Class | TypeFlags.Interface) + ? this.checker.getBaseTypes(this) + : undefined; + } } class SignatureObject implements Signature { From 55b2eca48e272b33191bdcc81f1b6b48021f455e Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 22 Jul 2015 16:48:03 -0700 Subject: [PATCH 22/37] Add AUTHORS.md --- AUTHORS.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 AUTHORS.md diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 00000000000..1c45bf17cf5 --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,45 @@ +TypeScript is authored by: + +* Ahmad Farid +* Anders Hejlsberg +* Arnav Singh +* Basarat Ali Syed +* Bill Ticehurst +* Bryan Forbes +* Caitlin Potter +* Chris Bubernak +* Colin Snover +* Cyrus Najmabadi +* Dan Quirk +* Daniel Rosenwasser +* Dick van den Brink +* Dirk Bäumer +* Frank Wallis +* Guillaume Salles +* Ivo Gabe de Wolff +* James Whitney +* Jason Freeman +* Jason Ramsay +* Johannes Rieken +* Jonathan Bond- Caron +* Kagami Sascha Rosylight +* Keith Mashinter +* Lorant Pinter +* Masahiro Wakame +* Mohamed Hegazy +* Oleg Mihailik +* Paul van Brenk +* Pedro Maltez +* Ron Buckton +* Ryan Cavanaugh +* Sheetal Nandi +* Shengping Zhong +* Stan Thomas +* Steve Lucco +* Tingan Ho +* Tomas Grubliauskas +* TruongSinh Tran-Nguyen +* Vladimir Matveev +* Yui Tanglertsampan +* Zev Spitz +* Zhengbo Li \ No newline at end of file From 98d747415183d2f924e9af0e7fd52f3b07ccbcfd Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 22 Jul 2015 17:19:42 -0700 Subject: [PATCH 23/37] Update AUTHORS.md for release 1.6 --- AUTHORS.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index 1c45bf17cf5..0ade4c31221 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -1,45 +1,70 @@ TypeScript is authored by: +* Adam Freidin * Ahmad Farid * Anders Hejlsberg * Arnav Singh +* Arthur Ozga * Basarat Ali Syed +* Ben Duffield * Bill Ticehurst * Bryan Forbes * Caitlin Potter * Chris Bubernak +* Colby Russell * Colin Snover * Cyrus Najmabadi * Dan Quirk * Daniel Rosenwasser +* David Li * Dick van den Brink * Dirk Bäumer * Frank Wallis +* Gabriel Isenberg +* Gilad Peleg * Guillaume Salles +* Harald Niesche +* Ingvar Stepanyan * Ivo Gabe de Wolff * James Whitney * Jason Freeman * Jason Ramsay +* Jed Mao * Johannes Rieken -* Jonathan Bond- Caron +* Jonathan Bond-Caron +* Jonathan Park +* Jonathan Turner +* Josh Kalderimis * Kagami Sascha Rosylight * Keith Mashinter +* Kenji Imamula * Lorant Pinter * Masahiro Wakame +* Max Deepfield +* Micah Zoltu * Mohamed Hegazy * Oleg Mihailik +* Oleksandr Chekhovskyi * Paul van Brenk * Pedro Maltez +* Philip Bulley +* piloopin * Ron Buckton * Ryan Cavanaugh * Sheetal Nandi * Shengping Zhong +* Shyyko Serhiy +* Simon Hürlimann +* Solal Pirelli * Stan Thomas * Steve Lucco +* Tien Hoanhtien * Tingan Ho +* togru * Tomas Grubliauskas * TruongSinh Tran-Nguyen * Vladimir Matveev +* Wesley Wigham * Yui Tanglertsampan * Zev Spitz * Zhengbo Li \ No newline at end of file From c42b9f84fe9896567f467bed996825ceb9094049 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Thu, 23 Jul 2015 10:53:57 -0700 Subject: [PATCH 24/37] fixed a typo --- tests/cases/fourslash/fourslash.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 0008b33673f..cbba2e916ce 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -39,7 +39,7 @@ // Explanation: // We want type-completion while we edit this file, but at compile time/while editting fourslash tests, // we don't want to include the following reference because we are compiling this file in "--out" mode and don't want to rope -// in the entire codebase into the compilattion each fourslash test. Additionally, we don't want to expose the +// in the entire codebase into the compilation each fourslash test. Additionally, we don't want to expose the // src/harness/fourslash.ts API's (or the rest of the compiler) because they are unstable and complicate the // fourslash testing DSL. Finally, in this case, runtime reflection is (much) faster. // From 5fb5b244fbd9c1360b539798dd36ec9ab868badf Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 23 Jul 2015 11:14:19 -0700 Subject: [PATCH 25/37] Feedback from PR, lint fixes --- tests/cases/unittests/session.ts | 819 +++++++++++++++---------------- 1 file changed, 407 insertions(+), 412 deletions(-) diff --git a/tests/cases/unittests/session.ts b/tests/cases/unittests/session.ts index 1d7b9572bbb..1d2efbb498c 100644 --- a/tests/cases/unittests/session.ts +++ b/tests/cases/unittests/session.ts @@ -1,24 +1,24 @@ /// module ts.server { - let lastWrittenToHost: string, - mockHost: ServerHost = { - args: [], - newLine: '\n', - useCaseSensitiveFileNames: true, - write: (s) => lastWrittenToHost = s, - readFile: () => void 0, - writeFile: () => void 0, - resolvePath: () => void 0, - fileExists: () => false, - directoryExists: () => false, - createDirectory: () => void 0, - getExecutingFilePath: () => void 0, - getCurrentDirectory: () => void 0, - readDirectory: () => void 0, - exit: () => void 0 - }, - mockLogger: Logger = { + let lastWrittenToHost: string; + const mockHost: ServerHost = { + args: [], + newLine: "\n", + useCaseSensitiveFileNames: true, + write(s): void { lastWrittenToHost = s; }, + readFile(): string { return void 0; }, + writeFile(): void {}, + resolvePath(): string { return void 0; }, + fileExists: () => false, + directoryExists: () => false, + createDirectory(): void {}, + getExecutingFilePath(): string { return void 0; }, + getCurrentDirectory(): string { return void 0; }, + readDirectory(): string[] { return []; }, + exit(): void {} + }; + const mockLogger: Logger = { close(): void {}, isVerbose(): boolean { return false; }, loggingEnabled(): boolean { return false; }, @@ -27,433 +27,428 @@ module ts.server { startGroup(): void {}, endGroup(): void {}, msg(s: string, type?: string): void {}, - }; - - describe('the Session class', () => { - let session: Session, - lastSent: protocol.Message; + }; + + describe("the Session class", () => { + let session: Session; + let lastSent: protocol.Message; - beforeEach(() => { - session = new Session(mockHost, Buffer.byteLength, process.hrtime, mockLogger); - session.send = (msg: protocol.Message) => { - lastSent = msg; - }; - }); + beforeEach(() => { + session = new Session(mockHost, Buffer.byteLength, process.hrtime, mockLogger); + session.send = (msg: protocol.Message) => { + lastSent = msg; + }; + }); - describe('executeCommand', () => { - it('should throw when commands are executed with invalid arguments', () => { - let req : protocol.FileRequest = { - command: CommandNames.Open, - seq: 0, - type: 'command', - arguments: { - file: undefined - } - }; + describe("executeCommand", () => { + it("should throw when commands are executed with invalid arguments", () => { + const req: protocol.FileRequest = { + command: CommandNames.Open, + seq: 0, + type: "command", + arguments: { + file: undefined + } + }; - expect(() => session.executeCommand(req)).to.throw(); - }); - it('should output an error response when a command does not exist', () => { - let req : protocol.Request = { - command: 'foobar', - seq: 0, - type: 'command' - }; + expect(() => session.executeCommand(req)).to.throw(); + }); + it("should output an error response when a command does not exist", () => { + const req: protocol.Request = { + command: "foobar", + seq: 0, + type: "command" + }; - session.executeCommand(req); + session.executeCommand(req); - expect(lastSent).to.deep.equal({ - command: CommandNames.Unknown, - type: 'response', - seq: 0, - message: 'Unrecognized JSON command: foobar', - request_seq: 0, - success: false - }); - }); - it('should return a tuple containing the response and if a response is required on success', () => { - let req : protocol.ConfigureRequest = { - command: CommandNames.Configure, - seq: 0, - type: 'command', - arguments: { - hostInfo: 'unit test', - formatOptions: { - newLineCharacter: '`n' - } - } - }; + expect(lastSent).to.deep.equal({ + command: CommandNames.Unknown, + type: "response", + seq: 0, + message: "Unrecognized JSON command: foobar", + request_seq: 0, + success: false + }); + }); + it("should return a tuple containing the response and if a response is required on success", () => { + const req: protocol.ConfigureRequest = { + command: CommandNames.Configure, + seq: 0, + type: "command", + arguments: { + hostInfo: "unit test", + formatOptions: { + newLineCharacter: "`n" + } + } + }; - expect(session.executeCommand(req)).to.deep.equal({ - responseRequired: false - }); - expect(lastSent).to.deep.equal({ - command: CommandNames.Configure, - type: 'response', - success: true, - request_seq: 0, - seq: 0, - body: undefined - }); - }); - }); + expect(session.executeCommand(req)).to.deep.equal({ + responseRequired: false + }); + expect(lastSent).to.deep.equal({ + command: CommandNames.Configure, + type: "response", + success: true, + request_seq: 0, + seq: 0, + body: undefined + }); + }); + }); - describe('onMessage', () => { - it('should not throw when commands are executed with invalid arguments', () => { - let i = 0; - for (name in CommandNames) { - if (!Object.prototype.hasOwnProperty.call(CommandNames, name)) { - continue; - } - let req : protocol.Request = { - command: name, - seq: i++, - type: 'command' - }; - session.onMessage(JSON.stringify(req)); - req.seq += 2; - req.arguments = {}; - session.onMessage(JSON.stringify(req)); - req.seq += 2; - req.arguments = null; - session.onMessage(JSON.stringify(req)); - } - }); - it('should output the response for a correctly handled message', () => { - let req : protocol.ConfigureRequest = { - command: CommandNames.Configure, - seq: 0, - type: 'command', - arguments: { - hostInfo: 'unit test', - formatOptions: { - newLineCharacter: '`n' - } - } - }; + describe("onMessage", () => { + it("should not throw when commands are executed with invalid arguments", () => { + let i = 0; + for (name in CommandNames) { + if (!Object.prototype.hasOwnProperty.call(CommandNames, name)) { + continue; + } + const req: protocol.Request = { + command: name, + seq: i++, + type: "command" + }; + session.onMessage(JSON.stringify(req)); + req.seq = i++; + req.arguments = {}; + session.onMessage(JSON.stringify(req)); + req.seq = i++; + req.arguments = null; + session.onMessage(JSON.stringify(req)); + req.seq = i++; + req.arguments = ""; + session.onMessage(JSON.stringify(req)); + req.seq = i++; + req.arguments = 0; + session.onMessage(JSON.stringify(req)); + req.seq = i++; + req.arguments = []; + session.onMessage(JSON.stringify(req)); + } + session.onMessage("GARBAGE NON_JSON DATA"); + }); + it("should output the response for a correctly handled message", () => { + const req: protocol.ConfigureRequest = { + command: CommandNames.Configure, + seq: 0, + type: "command", + arguments: { + hostInfo: "unit test", + formatOptions: { + newLineCharacter: "`n" + } + } + }; - session.onMessage(JSON.stringify(req)); + session.onMessage(JSON.stringify(req)); - expect(lastSent).to.deep.equal({ - command: CommandNames.Configure, - type: 'response', - success: true, - request_seq: 0, - seq: 0, - body: undefined - }); - }); - }); + expect(lastSent).to.deep.equal({ + command: CommandNames.Configure, + type: "response", + success: true, + request_seq: 0, + seq: 0, + body: undefined + }); + }); + }); - describe('exit', () => { - it('is a noop which can be handled by subclasses', () => { - session.exit(); // Does nothing, should keep running tests - expect(session).to.exist; - }); - }); + describe("exit", () => { + it("is a noop which can be handled by subclasses", () => { + session.exit(); // Does nothing, should keep running tests + expect(session).to.exist; + }); + }); - describe('send', () => { - it('is an overrideable handle which sends protocol messages over the wire', () => { - let msg = {seq: 0, type: 'none'}, - strmsg = JSON.stringify(msg), - len = 1 + Buffer.byteLength(strmsg, 'utf8'), - resultMsg = `Content-Length: ${len}\r\n\r\n${strmsg}\n`; + describe("send", () => { + it("is an overrideable handle which sends protocol messages over the wire", () => { + const msg = {seq: 0, type: "none"}; + const strmsg = JSON.stringify(msg); + const len = 1 + Buffer.byteLength(strmsg, "utf8"); + const resultMsg = `Content-Length: ${len}\r\n\r\n${strmsg}\n`; - session.send = Session.prototype.send; - assert(session.send); - expect(session.send(msg)).to.not.exist; - expect(lastWrittenToHost).to.equal(resultMsg); - }); - }); + session.send = Session.prototype.send; + assert(session.send); + expect(session.send(msg)).to.not.exist; + expect(lastWrittenToHost).to.equal(resultMsg); + }); + }); - describe('addProtocolHandler', () => { - it('can add protocol handlers', () => { - let respBody = { - item: false - }, - command = 'newhandle', - result = { - response: respBody, - responseRequired: true - }; + describe("addProtocolHandler", () => { + it("can add protocol handlers", () => { + const respBody = { + item: false + }; + const command = "newhandle"; + const result = { + response: respBody, + responseRequired: true + }; - session.addProtocolHandler(command, (req) => result); + session.addProtocolHandler(command, (req) => result); - expect(session.executeCommand({ - command, - seq: 0, - type: 'command' - })).to.deep.equal(result); - }); - it('throws when a duplicate handler is passed', () => { - let respBody = { - item: false - }, - resp = { - response: respBody, - responseRequired: true - }, - command = 'newhandle'; + expect(session.executeCommand({ + command, + seq: 0, + type: "command" + })).to.deep.equal(result); + }); + it("throws when a duplicate handler is passed", () => { + const respBody = { + item: false + }; + const resp = { + response: respBody, + responseRequired: true + }; + const command = "newhandle"; - session.addProtocolHandler(command, (req) => resp); + session.addProtocolHandler(command, (req) => resp); - expect(() => session.addProtocolHandler(command, (req) => resp)) - .to.throw(`Protocol handler already exists for command "${command}"`); - }); - }); - - describe('event', () => { - it('can format event responses and send them', () => { - let evt = 'notify-test', - info = { - test: true - }; + expect(() => session.addProtocolHandler(command, (req) => resp)) + .to.throw(`Protocol handler already exists for command "${command}"`); + }); + }); + + describe("event", () => { + it("can format event responses and send them", () => { + const evt = "notify-test"; + const info = { + test: true + }; - session.event(info, evt); + session.event(info, evt); - expect(lastSent).to.deep.equal({ - type: 'event', - seq: 0, - event: evt, - body: info - }); - }); - }); + expect(lastSent).to.deep.equal({ + type: "event", + seq: 0, + event: evt, + body: info + }); + }); + }); - describe('output', () => { - it('can format command responses and send them', () => { - let body = { - block: { - key: 'value' - } - }, - command = 'test'; + describe("output", () => { + it("can format command responses and send them", () => { + const body = { + block: { + key: "value" + } + }; + const command = "test"; - session.output(body, command); + session.output(body, command); - expect(lastSent).to.deep.equal({ - seq: 0, - request_seq: 0, - type: 'response', - command, - body: body, - success: true - }); - }); - }); - }); + expect(lastSent).to.deep.equal({ + seq: 0, + request_seq: 0, + type: "response", + command, + body: body, + success: true + }); + }); + }); + }); - describe('how Session is extendable via subclassing', () => { - let TestSession = class extends Session { - lastSent: protocol.Message; - customHandler: string = 'testhandler'; - constructor(){ - super(mockHost, Buffer.byteLength, process.hrtime, mockLogger); - this.addProtocolHandler(this.customHandler, () => { - return {response: undefined, responseRequired: true}; - }); - } - send(msg: protocol.Message) { - this.lastSent = msg; - } - }; + describe("how Session is extendable via subclassing", () => { + class TestSession extends Session { + lastSent: protocol.Message; + customHandler: string = "testhandler"; + constructor(){ + super(mockHost, Buffer.byteLength, process.hrtime, mockLogger); + this.addProtocolHandler(this.customHandler, () => { + return {response: undefined, responseRequired: true}; + }); + } + send(msg: protocol.Message) { + this.lastSent = msg; + } + }; - it('can override methods such as send', () => { - let session = new TestSession(), - body = { - block: { - key: 'value' - } - }, - command = 'test'; + it("can override methods such as send", () => { + const session = new TestSession(); + const body = { + block: { + key: "value" + } + }; + const command = "test"; - session.output(body, command); + session.output(body, command); - expect(session.lastSent).to.deep.equal({ - seq: 0, - request_seq: 0, - type: 'response', - command, - body: body, - success: true - }); - }); - it('can add and respond to new protocol handlers', () => { - let session = new TestSession(); + expect(session.lastSent).to.deep.equal({ + seq: 0, + request_seq: 0, + type: "response", + command, + body: body, + success: true + }); + }); + it("can add and respond to new protocol handlers", () => { + const session = new TestSession(); - expect(session.executeCommand({ - seq: 0, - type: 'command', - command: session.customHandler - })).to.deep.equal({ - response: undefined, - responseRequired: true - }); - }); - it('has access to the project service', () => { - let ServiceSession = class extends TestSession { - constructor() { - super(); - assert(this.projectService); - expect(this.projectService).to.be.instanceOf(ProjectService); - } - }; - new ServiceSession(); - }); - }); + expect(session.executeCommand({ + seq: 0, + type: "command", + command: session.customHandler + })).to.deep.equal({ + response: undefined, + responseRequired: true + }); + }); + it("has access to the project service", () => { + class ServiceSession extends TestSession { + constructor() { + super(); + assert(this.projectService); + expect(this.projectService).to.be.instanceOf(ProjectService); + } + }; + new ServiceSession(); + }); + }); - describe('an example of using the Session API to create an in-process server', () => { - let inProcHost: ServerHost = { - args: [], - newLine: '\n', - useCaseSensitiveFileNames: true, - write: (s) => lastWrittenToHost = s, - readFile: () => void 0, - writeFile: () => void 0, - resolvePath: () => void 0, - fileExists: () => false, - directoryExists: () => false, - createDirectory: () => void 0, - getExecutingFilePath: () => void 0, - getCurrentDirectory: () => void 0, - readDirectory: () => void 0, - exit: () => void 0 - }, - InProcSession = class extends Session { - private queue: protocol.Request[] = []; - constructor(private client: {handle: (msg: protocol.Message) => void}) { - super(inProcHost, Buffer.byteLength, process.hrtime, mockLogger); - this.addProtocolHandler('echo', (req: protocol.Request) => ({ - response: req.arguments, - responseRequired: true - })); - } - - send(msg: protocol.Message) { - this.client.handle(msg); - } + describe("an example of using the Session API to create an in-process server", () => { + class InProcSession extends Session { + private queue: protocol.Request[] = []; + constructor(private client: {handle: (msg: protocol.Message) => void}) { + super(mockHost, Buffer.byteLength, process.hrtime, mockLogger); + this.addProtocolHandler("echo", (req: protocol.Request) => ({ + response: req.arguments, + responseRequired: true + })); + } + + send(msg: protocol.Message) { + this.client.handle(msg); + } - enqueue(msg: protocol.Request) { - this.queue = [msg].concat(this.queue); - } - - handleRequest(msg: protocol.Request) { - let response: protocol.Response; - try { - response = this.executeCommand(msg).response; - } catch (e) { - this.output(undefined, msg.command, msg.seq, e.toString()); - return; - } - if (response) { - this.output(response, msg.command, msg.seq); - } - } + enqueue(msg: protocol.Request) { + this.queue.unshift(msg); + } + + handleRequest(msg: protocol.Request) { + let response: protocol.Response; + try { + ({response} = this.executeCommand(msg)); + } + catch (e) { + this.output(undefined, msg.command, msg.seq, e.toString()); + return; + } + if (response) { + this.output(response, msg.command, msg.seq); + } + } - consumeQueue() { - while (this.queue.length > 0) { - let elem = this.queue[this.queue.length - 1]; - this.queue = this.queue.slice(0, this.queue.length - 1); - this.handleRequest(elem); - } - } - }, - InProcClient = class { - private server: Session & {enqueue: (msg: protocol.Request) => void}; - private seq: number = 0; - private callbacks: ts.Map<(resp: protocol.Response) => void> = {}; - private eventHandlers: ts.Map<(args: any) => void> = {}; + consumeQueue() { + while (this.queue.length > 0) { + const elem = this.queue.pop(); + this.handleRequest(elem); + } + } + } + + class InProcClient { + private server: InProcSession; + private seq: number = 0; + private callbacks: ts.Map<(resp: protocol.Response) => void> = {}; + private eventHandlers: ts.Map<(args: any) => void> = {}; - handle(msg: protocol.Message): void { - if (msg.type === 'response') { - let response = msg; - if (this.callbacks[response.request_seq]) { - this.callbacks[response.request_seq](response); - delete this.callbacks[response.request_seq]; - } - } else if (msg.type === 'event') { - let event = msg; - this.emit(event.event, event.body); - } - } + handle(msg: protocol.Message): void { + if (msg.type === "response") { + const response = msg; + if (this.callbacks[response.request_seq]) { + this.callbacks[response.request_seq](response); + delete this.callbacks[response.request_seq]; + } + } + else if (msg.type === "event") { + const event = msg; + this.emit(event.event, event.body); + } + } - emit(name: string, args: any): void { - if (!this.eventHandlers[name]) { - return; - } - this.eventHandlers[name](args); - } + emit(name: string, args: any): void { + if (this.eventHandlers[name]) { + this.eventHandlers[name](args); + } + } - on(name: string, handler: (args: any) => void): void { - this.eventHandlers[name] = handler; - } + on(name: string, handler: (args: any) => void): void { + this.eventHandlers[name] = handler; + } - connect(session: Session & {enqueue: (msg: protocol.Request) => void}): void { - this.server = session; - } - - execute(command: string, args: any, callback: (resp: protocol.Response) => void): void { - if (!this.server) { - return; - } - this.seq++; - this.server.enqueue({ - seq: this.seq, - type: 'command', - command, - arguments: args - }); - this.callbacks[this.seq] = callback; - } - }; - - it('can be constructed and respond to commands', (done) => { - let cli = new InProcClient(), - session = new InProcSession(cli), - toEcho = { - data: true - }, - toEvent = { - data: false - }, - responses = 0; + connect(session: InProcSession): void { + this.server = session; + } + + execute(command: string, args: any, callback: (resp: protocol.Response) => void): void { + if (!this.server) { + return; + } + this.seq++; + this.server.enqueue({ + seq: this.seq, + type: "command", + command, + arguments: args + }); + this.callbacks[this.seq] = callback; + } + }; + + it("can be constructed and respond to commands", (done) => { + const cli = new InProcClient(); + const session = new InProcSession(cli); + const toEcho = { + data: true + }; + const toEvent = { + data: false + }; + let responses = 0; - // Connect the client - cli.connect(session); - - // Add an event handler - cli.on('testevent', (eventinfo) => { - expect(eventinfo).to.equal(toEvent); - responses++; - expect(responses).to.equal(1); - }); - - // Trigger said event from the server - session.event(toEvent, 'testevent'); - - // Queue an echo command - cli.execute('echo', toEcho, (resp) => { - assert(resp.success, resp.message); - responses++; - expect(responses).to.equal(2); - expect(resp.body).to.deep.equal(toEcho); - }); - - // Queue a configure command - cli.execute('configure', { - hostInfo: 'unit test', - formatOptions: { - newLineCharacter: '`n' - } - }, (resp) => { - assert(resp.success, resp.message); - responses++; - expect(responses).to.equal(3); - done(); - }); - - // Consume the queue and trigger the callbacks - session.consumeQueue(); - }); - }); + // Connect the client + cli.connect(session); + + // Add an event handler + cli.on("testevent", (eventinfo) => { + expect(eventinfo).to.equal(toEvent); + responses++; + expect(responses).to.equal(1); + }); + + // Trigger said event from the server + session.event(toEvent, "testevent"); + + // Queue an echo command + cli.execute("echo", toEcho, (resp) => { + assert(resp.success, resp.message); + responses++; + expect(responses).to.equal(2); + expect(resp.body).to.deep.equal(toEcho); + }); + + // Queue a configure command + cli.execute("configure", { + hostInfo: "unit test", + formatOptions: { + newLineCharacter: "`n" + } + }, (resp) => { + assert(resp.success, resp.message); + responses++; + expect(responses).to.equal(3); + done(); + }); + + // Consume the queue and trigger the callbacks + session.consumeQueue(); + }); + }); } \ No newline at end of file From d1fe21dda965e917912c30fb9f2fbd1602b6cadc Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 23 Jul 2015 12:32:17 -0700 Subject: [PATCH 26/37] Publish to TypeScript itself, create a task to preview changes. --- Jakefile.js | 25 +++++++++++++------------ scripts/configureNightly.ts | 26 +++++++++++++++----------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/Jakefile.js b/Jakefile.js index edfd14fc1af..5f8fbfbfce6 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -361,23 +361,24 @@ compileFile(/*outfile*/configureNightlyJs, /*preserveConstEnums*/ undefined, /*keepComments*/ false, /*noResolve*/ false, - /*stripInternal*/ false, - /*callback*/ function () { - var cmd = "node " + configureNightlyJs + " " + packageJson + " " + programTs; - console.log(cmd); - exec(cmd, completeHandler, errorHandler) - }); + /*stripInternal*/ false); -task("setDebugModeTrue", function() { +task("setDebugMode", function() { useDebugMode = true; }); -desc("Configure, build, test, and publish the nightly release."); -task("publish-nightly", [configureNightlyJs, "LKG", "clean", "setDebugModeTrue", "runtests"], function () { - var cmd = "npm publish"; +task("configure-nightly", [configureNightlyJs], function() { + var cmd = "node " + configureNightlyJs + " " + packageJson + " " + programTs; console.log(cmd); - exec(cmd, completeHandler, errorHandler) -}, {async: true}); + exec(cmd); +}, { async: true }); + +desc("Configure, build, test, and publish the nightly release."); +task("publish-nightly", ["configure-nightly", "LKG", "clean", "setDebugMode", "runtests"], function () { + var cmd = "npm publish --tag next"; + console.log(cmd); + exec(cmd); +}); // Local target to build the compiler and services var tscFile = path.join(builtLocalDirectory, compilerFilename); diff --git a/scripts/configureNightly.ts b/scripts/configureNightly.ts index a0e30b007cf..640f330b376 100644 --- a/scripts/configureNightly.ts +++ b/scripts/configureNightly.ts @@ -27,11 +27,6 @@ function main(): void { // Modify the package.json structure packageJsonValue.version = nightlyVersion; - if (packageJsonValue.name !== "typescript-nightly") { - packageJsonValue.name = "typescript-nightly"; - packageJsonValue.keywords.push("nightly", "alpha", "beta", "prerelease"); - } - // Acquire and modify the source file that exposes the version string. const tsFilePath = ts.normalizePath(sys.args[1]); const tsFileContents = sys.readFile(tsFilePath); @@ -40,7 +35,16 @@ function main(): void { // Ensure we are actually changing something - the user probably wants to know that the update failed. if (tsFileContents === modifiedTsFileContents) { - throw `File '${tsFilePath}' did not contain pattern ${versionAssignmentRegExp}`; + let err = `\n '${tsFilePath}' was not updated while configuring for a nightly publish.\n `; + + if (tsFileContents.match(versionAssignmentRegExp)) { + err += `Ensure that you have not already run this script; otherwise, erase your changes using 'git checkout -- "${tsFilePath}"'.`; + } + else { + err += `The file seems to no longer have a string matching '${versionAssignmentRegExp}'.`; + } + + throw err + "\n"; } // Finally write the changes to disk. @@ -51,19 +55,19 @@ function main(): void { function getNightlyVersionString(versionString: string): string { // If the version string already contains "-nightly", // then get the base string and update based on that. - const dashNightlyPos = versionString.indexOf("-nightly"); + const dashNightlyPos = versionString.indexOf("-dev"); if (dashNightlyPos >= 0) { versionString = versionString.slice(0, dashNightlyPos); } // We're going to append a representation of the current time at the end of the current version. // String.prototype.toISOString() returns a 24-character string formatted as 'YYYY-MM-DDTHH:mm:ss.sssZ', - // but we'd prefer to just use hyphens as separators instead of 'T', ':', and '.'. - // The trailing 'Z' in this string can be removed; UTC time will always be implicit here. + // but we'd prefer to just remove separators and limit ourselves to YYYYMMDD. + // UTC time will always be implicit here. const now = new Date(); - const timeStr = now.toISOString().slice(0, -1).replace(/:|T|\./g, "-"); + const timeStr = now.toISOString().replace(/:|T|\.|-/g, "").slice(0, 8); - return `${versionString}-nightly-${timeStr}`; + return `${versionString}-dev.${timeStr}`; } main(); \ No newline at end of file From 90bbb7fb3c94300a406fc9deb6e3dcafdefed83b Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 23 Jul 2015 12:33:34 -0700 Subject: [PATCH 27/37] More linting from PR --- tests/cases/unittests/session.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/cases/unittests/session.ts b/tests/cases/unittests/session.ts index 1d2efbb498c..25be08293f2 100644 --- a/tests/cases/unittests/session.ts +++ b/tests/cases/unittests/session.ts @@ -1,6 +1,6 @@ /// -module ts.server { +namespace ts.server { let lastWrittenToHost: string; const mockHost: ServerHost = { args: [], @@ -256,8 +256,8 @@ module ts.server { describe("how Session is extendable via subclassing", () => { class TestSession extends Session { lastSent: protocol.Message; - customHandler: string = "testhandler"; - constructor(){ + customHandler = "testhandler"; + constructor() { super(mockHost, Buffer.byteLength, process.hrtime, mockLogger); this.addProtocolHandler(this.customHandler, () => { return {response: undefined, responseRequired: true}; @@ -315,7 +315,7 @@ module ts.server { describe("an example of using the Session API to create an in-process server", () => { class InProcSession extends Session { private queue: protocol.Request[] = []; - constructor(private client: {handle: (msg: protocol.Message) => void}) { + constructor(private client: InProcClient) { super(mockHost, Buffer.byteLength, process.hrtime, mockLogger); this.addProtocolHandler("echo", (req: protocol.Request) => ({ response: req.arguments, @@ -355,7 +355,7 @@ module ts.server { class InProcClient { private server: InProcSession; - private seq: number = 0; + private seq = 0; private callbacks: ts.Map<(resp: protocol.Response) => void> = {}; private eventHandlers: ts.Map<(args: any) => void> = {}; From ef0a289c771a09cf7c739df47cb6ca3d6489ed51 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 23 Jul 2015 12:50:24 -0700 Subject: [PATCH 28/37] Remove exit test --- tests/cases/unittests/session.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/cases/unittests/session.ts b/tests/cases/unittests/session.ts index 25be08293f2..c1dfd508942 100644 --- a/tests/cases/unittests/session.ts +++ b/tests/cases/unittests/session.ts @@ -155,13 +155,6 @@ namespace ts.server { }); }); - describe("exit", () => { - it("is a noop which can be handled by subclasses", () => { - session.exit(); // Does nothing, should keep running tests - expect(session).to.exist; - }); - }); - describe("send", () => { it("is an overrideable handle which sends protocol messages over the wire", () => { const msg = {seq: 0, type: "none"}; From b443cfecc9bb4f08439085afc031ce4a3d6aaca3 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 23 Jul 2015 12:53:41 -0700 Subject: [PATCH 29/37] Semicolons. --- Jakefile.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Jakefile.js b/Jakefile.js index 5f8fbfbfce6..5bfd4d7d278 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -336,17 +336,17 @@ file(diagnosticInfoMapTs, [processDiagnosticMessagesJs, diagnosticMessagesJson], complete(); }); ex.run(); -}, {async: true}) +}, {async: true}); desc("Generates a diagnostic file in TypeScript based on an input JSON file"); -task("generate-diagnostics", [diagnosticInfoMapTs]) +task("generate-diagnostics", [diagnosticInfoMapTs]); // Publish nightly var configureNightlyJs = path.join(scriptsDirectory, "configureNightly.js"); var configureNightlyTs = path.join(scriptsDirectory, "configureNightly.ts"); var packageJson = "package.json"; -var programTs = path.join(compilerDirectory, "program.ts") +var programTs = path.join(compilerDirectory, "program.ts"); file(configureNightlyTs); @@ -476,11 +476,11 @@ file(specMd, [word2mdJs, specWord], function () { child_process.exec(cmd, function () { complete(); }); -}, {async: true}) +}, {async: true}); desc("Generates a Markdown version of the Language Specification"); -task("generate-spec", [specMd]) +task("generate-spec", [specMd]); // Makes a new LKG. This target does not build anything, but errors if not all the outputs are present in the built/local directory @@ -612,7 +612,7 @@ task("runtests", ["tests", builtLocalDirectory], function() { exec(cmd, deleteTemporaryProjectOutput); }, {async: true}); -desc("Generates code coverage data via instanbul") +desc("Generates code coverage data via instanbul"); task("generate-code-coverage", ["tests", builtLocalDirectory], function () { var cmd = 'istanbul cover node_modules/mocha/bin/_mocha -- -R min -t ' + testTimeout + ' ' + run; console.log(cmd); @@ -655,7 +655,7 @@ task("runtests-browser", ["tests", "browserify", builtLocalDirectory], function( function getDiffTool() { var program = process.env['DIFF'] if (!program) { - fail("Add the 'DIFF' environment variable to the path of the program you want to use.") + fail("Add the 'DIFF' environment variable to the path of the program you want to use."); } return program; } @@ -664,14 +664,14 @@ function getDiffTool() { desc("Diffs the compiler baselines using the diff tool specified by the 'DIFF' environment variable"); task('diff', function () { var cmd = '"' + getDiffTool() + '" ' + refBaseline + ' ' + localBaseline; - console.log(cmd) + console.log(cmd); exec(cmd); }, {async: true}); desc("Diffs the RWC baselines using the diff tool specified by the 'DIFF' environment variable"); task('diff-rwc', function () { var cmd = '"' + getDiffTool() + '" ' + refRwcBaseline + ' ' + localRwcBaseline; - console.log(cmd) + console.log(cmd); exec(cmd); }, {async: true}); From f040386eff39013ce9902a3cafc19494a0194838 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 23 Jul 2015 13:42:25 -0700 Subject: [PATCH 30/37] Fix jake lint with newest tslint --- Jakefile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jakefile.js b/Jakefile.js index bd5074b43d6..4e400a0b6a8 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -738,7 +738,7 @@ task("lint", [], function() { var lintTargets = compilerSources.concat(harnessCoreSources); for(var i in lintTargets) { var f = lintTargets[i]; - var cmd = 'tslint -f ' + f; + var cmd = 'tslint -c tslint.json ' + f; exec(cmd, success(f), failure(f)); } }, { async: true }); From a759687a12a40408c1a6259a70d8db8366dcb927 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 23 Jul 2015 13:59:41 -0700 Subject: [PATCH 31/37] Adds space --- Jakefile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jakefile.js b/Jakefile.js index 4e400a0b6a8..541537d589c 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -736,7 +736,7 @@ task("lint", [], function() { function failure(f) { return function() { console.log('FAILURE: Please fix linting errors in ' + f + '\n') }}; var lintTargets = compilerSources.concat(harnessCoreSources); - for(var i in lintTargets) { + for (var i in lintTargets) { var f = lintTargets[i]; var cmd = 'tslint -c tslint.json ' + f; exec(cmd, success(f), failure(f)); From ab713827a542662cce294ebd3dd1851306622a57 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 23 Jul 2015 15:57:58 -0700 Subject: [PATCH 32/37] Add `jake lint` to README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 57dfe06c67c..f7f1838c8fb 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,8 @@ jake runtests # Run tests using the built compiler and test infrastructu # Use host= or tests=. jake runtests-browser # Runs the tests using the built run.js file. Syntax is jake runtests. Optional parameters 'host=', 'tests=[regex], reporter=[list|spec|json|]'. -jake baseline-accept # This replaces the baseline test results with the results obtained from jake runtests. +jake baseline-accept # This replaces the baseline test results with the results obtained from jake runtests. +jake lint # Runs tslint over the compiler jake -T # List the above commands. ``` From a16920b577edd587763d9b1d2a361effbe5e4548 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 23 Jul 2015 16:06:46 -0700 Subject: [PATCH 33/37] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f7f1838c8fb..2912624c679 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ jake runtests # Run tests using the built compiler and test infrastructu jake runtests-browser # Runs the tests using the built run.js file. Syntax is jake runtests. Optional parameters 'host=', 'tests=[regex], reporter=[list|spec|json|]'. jake baseline-accept # This replaces the baseline test results with the results obtained from jake runtests. -jake lint # Runs tslint over the compiler +jake lint # Runs tslint over the TypeScript source code jake -T # List the above commands. ``` From 7cd7ae7c1571716f13d2c13d3193bbd0dfdf69eb Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 23 Jul 2015 16:07:30 -0700 Subject: [PATCH 34/37] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2912624c679..8fdf088f6d9 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ jake runtests # Run tests using the built compiler and test infrastructu jake runtests-browser # Runs the tests using the built run.js file. Syntax is jake runtests. Optional parameters 'host=', 'tests=[regex], reporter=[list|spec|json|]'. jake baseline-accept # This replaces the baseline test results with the results obtained from jake runtests. -jake lint # Runs tslint over the TypeScript source code +jake lint # Runs tslint on the TypeScript source jake -T # List the above commands. ``` From c5c7e25c8f60daed17a925d4ed0a3e1f9ee2b673 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 23 Jul 2015 16:28:37 -0700 Subject: [PATCH 35/37] Added period. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8fdf088f6d9..77053fc9166 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ jake runtests # Run tests using the built compiler and test infrastructu jake runtests-browser # Runs the tests using the built run.js file. Syntax is jake runtests. Optional parameters 'host=', 'tests=[regex], reporter=[list|spec|json|]'. jake baseline-accept # This replaces the baseline test results with the results obtained from jake runtests. -jake lint # Runs tslint on the TypeScript source +jake lint # Runs tslint on the TypeScript source. jake -T # List the above commands. ``` From fa522e079628f77b4faddfda53d2dc56153b8fb4 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 24 Jul 2015 11:28:08 -0700 Subject: [PATCH 36/37] Add nightly info to README.md --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 77053fc9166..c8bc5936c24 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,19 @@ [TypeScript](http://www.typescriptlang.org/) is a language for application-scale JavaScript. TypeScript adds optional types, classes, and modules to JavaScript. TypeScript supports tools for large-scale JavaScript applications for any browser, for any host, on any OS. TypeScript compiles to readable, standards-based JavaScript. Try it out at the [playground](http://www.typescriptlang.org/Playground), and stay up to date via [our blog](http://blogs.msdn.com/typescript) and [twitter account](https://twitter.com/typescriptlang). +## Installing + +For the latest stable version: + +``` +npm install -g typescript +``` + +For our nightly builds: + +``` +npm install -g typescript@next +``` ## Contribute From 1251b46eb647d91312ba07e159afc16b4aaca8e6 Mon Sep 17 00:00:00 2001 From: Basarat Ali Syed Date: Mon, 27 Jul 2015 17:42:49 +1000 Subject: [PATCH 37/37] SourceFile.fileWatcher should be optional --- src/compiler/tsc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index a657cc8c314..6872c4c876e 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -3,7 +3,7 @@ namespace ts { export interface SourceFile { - fileWatcher: FileWatcher; + fileWatcher?: FileWatcher; } /**