Merge branch 'master' into conformanceTests-624

Conflicts:
	tests/baselines/reference/parameterInitializersForwardReferencing.errors.txt
This commit is contained in:
Daniel Rosenwasser
2014-11-25 14:18:17 -08:00
4634 changed files with 156038 additions and 78200 deletions
+4
View File
@@ -32,8 +32,12 @@ build.json
tests/webhost/*.d.ts
tests/webhost/webtsc.js
tests/*.js
tests/*.js.map
tests/*.d.ts
*.config
scripts/debug.bat
scripts/run.bat
scripts/word2md.js
scripts/ior.js
scripts/*.js.map
coverage/
+4 -2
View File
@@ -1,12 +1,14 @@
language: node_js
node_js:
- '0.10'
- '0.10'
sudo: false
before_script: npm install -g codeclimate-test-reporter
after_script:
- cat coverage/lcov.info | codeclimate
- cat coverage/lcov.info | codeclimate
addons:
code_climate:
+2 -1
View File
@@ -9,7 +9,7 @@ Design changes will not be accepted at this time. If you have a design change pr
## Legal
You will need to complete a Contributor License Agreement (CLA). Briefly, this agreement testifies that you are granting us permission to use the submitted change according to the terms of the project's license, and that the work being submitted is under appropriate copyright.
Please submit a Contributor License Agreement (CLA) before submitting a pull request. Download the agreement ([Microsoft Contribution License Agreement.docx](https://www.codeplex.com/Download?ProjectName=typescript&DownloadId=822190)), sign, scan, and email it back to <cla@microsoft.com>. Be sure to include your github user name along with the agreement. Once we have received the signed CLA, we'll review the request. Please note that we're currently only accepting pull requests of bug fixes rather than new features.
Please submit a Contributor License Agreement (CLA) before submitting a pull request. Download the agreement ([Microsoft Contribution License Agreement.docx](https://www.codeplex.com/Download?ProjectName=typescript&DownloadId=822190) or [Microsoft Contribution License Agreement.pdf](https://www.codeplex.com/Download?ProjectName=typescript&DownloadId=921298)), sign, scan, and email it back to <cla@microsoft.com>. Be sure to include your github user name along with the agreement. Once we have received the signed CLA, we'll review the request. Please note that we're currently only accepting pull requests of bug fixes rather than new features.
## Housekeeping
Your pull request should:
@@ -26,6 +26,7 @@ Your pull request should:
* Include baseline changes with your change
* All changed code must have 100% code coverage
* Follow the code conventions descriped in [Coding guidlines](https://github.com/Microsoft/TypeScript/wiki/Coding-guidlines)
* To avoid line ending issues, set `autocrlf = input` and `whitespace = cr-at-eol` in your git configuration
## Running the Tests
To run all tests, invoke the runtests target using jake:
+68 -16
View File
@@ -2,6 +2,7 @@
var fs = require("fs");
var path = require("path");
var child_process = require("child_process");
// Variables
var compilerDirectory = "src/compiler/";
@@ -9,6 +10,8 @@ var servicesDirectory = "src/services/";
var harnessDirectory = "src/harness/";
var libraryDirectory = "src/lib/";
var scriptsDirectory = "scripts/";
var unittestsDirectory = "tests/cases/unittests/";
var docDirectory = "doc/";
var builtDirectory = "built/";
var builtLocalDirectory = "built/local/";
@@ -52,8 +55,13 @@ var servicesSources = [
].map(function (f) {
return path.join(compilerDirectory, f);
}).concat([
"breakpoints.ts",
"services.ts",
"shims.ts",
"signatureHelp.ts",
"utilities.ts",
"navigationBar.ts",
"outliningElementsCollector.ts"
].map(function (f) {
return path.join(servicesDirectory, f);
}));
@@ -63,19 +71,23 @@ var harnessSources = [
"sourceMapRecorder.ts",
"harnessLanguageService.ts",
"fourslash.ts",
"external/json2.ts",
"runnerbase.ts",
"compilerRunner.ts",
"typeWriter.ts",
"fourslashRunner.ts",
"projectsRunner.ts",
"unittestrunner.ts",
"loggedIO.ts",
"rwcRunner.ts",
"runner.ts"
].map(function (f) {
return path.join(harnessDirectory, f);
});
}).concat([
"services/colorization.ts",
"services/documentRegistry.ts",
"services/preProcessFile.ts"
].map(function (f) {
return path.join(unittestsDirectory, f);
}));
var librarySourceMap = [
{ target: "lib.core.d.ts", sources: ["core.d.ts"] },
@@ -122,7 +134,8 @@ function concatenateFiles(destinationFile, sourceFiles) {
fs.renameSync(temp, destinationFile);
}
var useDebugMode = false;
var useDebugMode = true;
var generateDeclarations = false;
var host = (process.env.host || process.env.TYPESCRIPT_HOST || "node");
var compilerFilename = "tsc.js";
/* Compiles a file from a list of sources
@@ -136,12 +149,16 @@ var compilerFilename = "tsc.js";
function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, noOutFile) {
file(outFile, prereqs, function() {
var dir = useBuiltCompiler ? builtLocalDirectory : LKGDirectory;
var options = "-removeComments --module commonjs -noImplicitAny "; //" -propagateEnumConstants "
var options = "-removeComments --module commonjs -noImplicitAny ";
if (generateDeclarations) {
options += "--declaration ";
}
if (useDebugMode) {
options += "--preserveConstEnums ";
}
var cmd = host + " " + dir + compilerFilename + " " + options + " ";
if (useDebugMode) {
cmd = cmd + " " + path.join(harnessDirectory, "external/es5compat.ts") + " " + path.join(harnessDirectory, "external/json2.ts") + " ";
}
cmd = cmd + sources.join(" ") + (!noOutFile ? " -out " + outFile : "");
if (useDebugMode) {
cmd = cmd + " -sourcemap -mapRoot file:///" + path.resolve(path.dirname(outFile));
@@ -243,12 +260,11 @@ task("local", ["generate-diagnostics", "lib", tscFile, servicesFile]);
// Local target to build the compiler and services
desc("Emit debug mode files with sourcemaps");
task("debug", function() {
useDebugMode = true;
desc("Sets release mode flag");
task("release", function() {
useDebugMode = false;
});
// Set the default task to "local"
task("default", ["local"]);
@@ -259,9 +275,45 @@ task("clean", function() {
jake.rmRf(builtDirectory);
});
// generate declarations for compiler and services
desc("Generate declarations for compiler and services");
task("declaration", function() {
generateDeclarations = true;
});
// Generate Markdown spec
var word2mdJs = path.join(scriptsDirectory, "word2md.js");
var word2mdTs = path.join(scriptsDirectory, "word2md.ts");
var specWord = path.join(docDirectory, "TypeScript Language Specification.docx");
var specMd = path.join(docDirectory, "spec.md");
file(word2mdTs);
// word2md script
compileFile(word2mdJs,
[word2mdTs],
[word2mdTs],
[],
false);
// The generated spec.md; built for the 'generate-spec' task
file(specMd, [word2mdJs, specWord], function () {
var specWordFullPath = path.resolve(specWord);
var cmd = "cscript //nologo " + word2mdJs + ' "' + specWordFullPath + '" ' + specMd;
console.log(cmd);
child_process.exec(cmd, function () {
complete();
});
}, {async: true})
desc("Generates a Markdown version of the Language Specification");
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
desc("Makes a new LKG out of the built js files");
task("LKG", libraryTargets, function() {
task("LKG", ["clean", "release", "local"].concat(libraryTargets), function() {
var expectedFiles = [tscFile, servicesFile].concat(libraryTargets);
var missingFiles = expectedFiles.filter(function (f) {
return !fs.existsSync(f);
@@ -318,7 +370,7 @@ function exec(cmd, completeHandler) {
complete();
})
try{
ex.run();
ex.run();
} catch(e) {
console.log('Exception: ' + e)
}
@@ -342,7 +394,7 @@ function cleanTestDirs() {
function writeTestConfigFile(tests, testConfigFile) {
console.log('Running test(s): ' + tests);
var testConfigContents = '{\n' + '\ttest: [\'' + tests + '\']\n}';
fs.writeFileSync('test.config', testConfigContents);
fs.writeFileSync('test.config', testConfigContents);
}
function deleteTemporaryProjectOutput() {
@@ -385,7 +437,7 @@ 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);
exec(cmd);
exec(cmd);
}, { async: true });
// Browser tests
+17 -11
View File
@@ -1,3 +1,7 @@
[![Build Status](https://travis-ci.org/Microsoft/TypeScript.svg?branch=master)](https://travis-ci.org/Microsoft/TypeScript)
[![Issue Stats](http://issuestats.com/github/Microsoft/TypeScript/badge/pr)](http://issuestats.com/github/microsoft/typescript)
[![Issue Stats](http://issuestats.com/github/Microsoft/TypeScript/badge/issue)](http://issuestats.com/github/microsoft/typescript)
# TypeScript
[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).
@@ -18,7 +22,7 @@ There are many ways to [contribute](https://github.com/Microsoft/TypeScript/blob
* [Quick tutorial](http://www.typescriptlang.org/Tutorial)
* [Programming handbook](http://www.typescriptlang.org/Handbook)
* [Language specification](http://go.microsoft.com/fwlink/?LinkId=267238)
* [Language specification](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md)
* [Homepage](http://www.typescriptlang.org/)
## Building
@@ -47,16 +51,18 @@ npm install
Use one of the following to build and test:
```
jake local # Build the compiler into built/local
jake clean # Delete the built compiler
jake LKG # Replace the last known good with the built one.
# Bootstrapping step to be executed when the built compiler reaches a stable state.
jake tests # Build the test infrastructure using the built compiler.
jake runtests # Run tests using the built compiler and test infrastructure.
# You can override the host or specify a test for this command.
# Use host=<hostName> or tests=<testPath>.
jake baseline-accept # This replaces the baseline test results with the results obtained from jake runtests.
jake -T # List the above commands.
jake local # Build the compiler into built/local
jake clean # Delete the built compiler
jake LKG # Replace the last known good with the built one.
# Bootstrapping step to be executed when the built compiler reaches a stable state.
jake tests # Build the test infrastructure using the built compiler.
jake runtests # Run tests using the built compiler and test infrastructure.
# You can override the host or specify a test for this command.
# Use host=<hostName> or tests=<testPath>.
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|<more>]'.
jake baseline-accept # This replaces the baseline test results with the results obtained from jake runtests.
jake -T # List the above commands.
```
-61
View File
@@ -19,67 +19,6 @@ limitations under the License.
---------------------------------------------
Third Party Code Components
--------------------------------------------
---- Mozilla Developer Code---------
The following Mozilla Developer Code is under Public Domain as updated after Aug. 20, 2012, see, https://developer.mozilla.org/en-US/docs/Project:Copyrights
1. Array filter Compatibility Method,
Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter
Any copyright is dedicated to the Public Domain.
2. Array forEach Compatibility Method,
Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach
Any copyright is dedicated to the Public Domain.
3. Array indexOf Compatibility Method,
Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf
Any copyright is dedicated to the Public Domain.
4. Array map Compatibility Method,
Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map
Any copyright is dedicated to the Public Domain.
5. Array Reduce Compatibility Method,
Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/Reduce
Any copyright is dedicated to the Public Domain.
6. String Trim Compatibility Method,
Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/Trim
Any copyright is dedicated to the Public Domain.
7. Date now Compatibility Method,
Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/now
Any copyright is dedicated to the Public Domain.
------------JSON2 Script------------------------
json2.js 2012-10-08
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See, http://www.JSON.org/js.html
--------------r.js----------------------
Copyright (c) 2010-2011 Dojo Foundation. All Rights Reserved.
Originally License under MIT License
-------------------------------------------------------------------------
Provided for Informational Purposes Only
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------- DefinitelyTyped --------------------
This file is based on or incorporates material from the projects listed below (collectively ?Third Party Code?). Microsoft is not the original author of the Third Party Code. The original copyright notice and the license, under which Microsoft received such Third Party Code, are set forth below. Such licenses and notices are provided for informational purposes only. Microsoft, not the third party, licenses the Third Party Code to you under the terms set forth in the EULA for the Microsoft Product. Microsoft reserves all other rights not expressly granted under this agreement, whether by implication, estoppel or otherwise.
+4
View File
@@ -499,6 +499,10 @@ declare var Number: {
POSITIVE_INFINITY: number;
}
interface TemplateStringsArray extends Array<string> {
raw: string[];
}
interface Math {
/** The mathematical constant e. This is Euler's number, the base of natural logarithms. */
E: number;
+77 -68
View File
@@ -499,6 +499,10 @@ declare var Number: {
POSITIVE_INFINITY: number;
}
interface TemplateStringsArray extends Array<string> {
raw: string[];
}
interface Math {
/** The mathematical constant e. This is Euler's number, the base of natural logarithms. */
E: number;
@@ -1182,14 +1186,14 @@ interface Int8Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Int8Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -1240,14 +1244,14 @@ interface Uint8Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Uint8Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -1298,14 +1302,14 @@ interface Int16Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Int16Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -1356,14 +1360,14 @@ interface Uint16Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Uint16Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -1414,14 +1418,14 @@ interface Int32Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Int32Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -1472,14 +1476,14 @@ interface Uint32Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Uint32Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -1530,14 +1534,14 @@ interface Float32Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Float32Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -1588,14 +1592,14 @@ interface Float64Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Float64Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -3807,30 +3811,42 @@ declare var Window: {
new(): Window;
}
interface FormData {
append(name: any, value: any, blobName?: string): void;
interface HTMLCollection extends MSHTMLCollectionExtensions {
/**
* Sets or retrieves the number of objects in a collection.
*/
length: number;
/**
* Retrieves an object from various collections.
*/
item(nameOrIndex?: any, optionalIndex?: any): Element;
/**
* Retrieves a select object or an object from an options collection.
*/
namedItem(name: string): Element;
// [name: string]: Element;
[index: number]: Element;
}
declare var FormData: {
prototype: FormData;
new (form?: HTMLFormElement): FormData;
declare var HTMLCollection: {
prototype: HTMLCollection;
new(): HTMLCollection;
}
interface SourceBuffer extends EventTarget {
updating: boolean;
appendWindowStart: number;
appendWindowEnd: number;
buffered: TimeRanges;
timestampOffset: number;
audioTracks: AudioTrackList;
appendBuffer(data: ArrayBufferView): void;
appendBuffer(data: ArrayBuffer): void;
remove(start: number, end: number): void;
abort(): void;
appendStream(stream: MSStream, maxSize?: number): void;
interface BlobPropertyBag {
type?: string;
endings?: string;
}
declare var SourceBuffer: {
prototype: SourceBuffer;
new(): SourceBuffer;
interface Blob {
type: string;
size: number;
msDetachStream(): any;
slice(start?: number, end?: number, contentType?: string): Blob;
msClose(): void;
}
declare var Blob: {
prototype: Blob;
new (blobParts?: any[], options?: BlobPropertyBag): Blob;
}
interface NavigatorID {
@@ -5739,26 +5755,6 @@ declare var MSCSSProperties: {
new(): MSCSSProperties;
}
interface HTMLCollection extends MSHTMLCollectionExtensions {
/**
* Sets or retrieves the number of objects in a collection.
*/
length: number;
/**
* Retrieves an object from various collections.
*/
item(nameOrIndex?: any, optionalIndex?: any): Element;
/**
* Retrieves a select object or an object from an options collection.
*/
namedItem(name: string): Element;
// [name: string]: Element;
}
declare var HTMLCollection: {
prototype: HTMLCollection;
new(): HTMLCollection;
}
interface SVGExternalResourcesRequired {
externalResourcesRequired: SVGAnimatedBoolean;
}
@@ -11994,18 +11990,6 @@ declare var FileReader: {
new(): FileReader;
}
interface Blob {
type: string;
size: number;
msDetachStream(): any;
slice(start?: number, end?: number, contentType?: string): Blob;
msClose(): void;
}
declare var Blob: {
prototype: Blob;
new(): Blob;
}
interface ApplicationCache extends EventTarget {
status: number;
ondownloading: (ev: Event) => any;
@@ -12164,6 +12148,14 @@ declare var MSManipulationEvent: {
MS_MANIPULATION_STATE_CANCELLED: number;
}
interface FormData {
append(name: any, value: any, blobName?: string): void;
}
declare var FormData: {
prototype: FormData;
new(): FormData;
}
interface HTMLDataListElement extends HTMLElement {
options: HTMLCollection;
}
@@ -12582,6 +12574,23 @@ interface RandomSource {
getRandomValues(array: ArrayBufferView): ArrayBufferView;
}
interface SourceBuffer extends EventTarget {
updating: boolean;
appendWindowStart: number;
appendWindowEnd: number;
buffered: TimeRanges;
timestampOffset: number;
audioTracks: AudioTrackList;
appendBuffer(data: ArrayBuffer): void;
remove(start: number, end: number): void;
abort(): void;
appendStream(stream: MSStream, maxSize?: number): void;
}
declare var SourceBuffer: {
prototype: SourceBuffer;
new(): SourceBuffer;
}
interface MSInputMethodContext extends EventTarget {
oncandidatewindowshow: (ev: any) => any;
target: HTMLElement;
+73 -68
View File
@@ -79,14 +79,14 @@ interface Int8Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Int8Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -137,14 +137,14 @@ interface Uint8Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Uint8Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -195,14 +195,14 @@ interface Int16Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Int16Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -253,14 +253,14 @@ interface Uint16Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Uint16Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -311,14 +311,14 @@ interface Int32Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Int32Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -369,14 +369,14 @@ interface Uint32Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Uint32Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -427,14 +427,14 @@ interface Float32Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Float32Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -485,14 +485,14 @@ interface Float64Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Float64Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -2704,30 +2704,42 @@ declare var Window: {
new(): Window;
}
interface FormData {
append(name: any, value: any, blobName?: string): void;
interface HTMLCollection extends MSHTMLCollectionExtensions {
/**
* Sets or retrieves the number of objects in a collection.
*/
length: number;
/**
* Retrieves an object from various collections.
*/
item(nameOrIndex?: any, optionalIndex?: any): Element;
/**
* Retrieves a select object or an object from an options collection.
*/
namedItem(name: string): Element;
// [name: string]: Element;
[index: number]: Element;
}
declare var FormData: {
prototype: FormData;
new (form?: HTMLFormElement): FormData;
declare var HTMLCollection: {
prototype: HTMLCollection;
new(): HTMLCollection;
}
interface SourceBuffer extends EventTarget {
updating: boolean;
appendWindowStart: number;
appendWindowEnd: number;
buffered: TimeRanges;
timestampOffset: number;
audioTracks: AudioTrackList;
appendBuffer(data: ArrayBufferView): void;
appendBuffer(data: ArrayBuffer): void;
remove(start: number, end: number): void;
abort(): void;
appendStream(stream: MSStream, maxSize?: number): void;
interface BlobPropertyBag {
type?: string;
endings?: string;
}
declare var SourceBuffer: {
prototype: SourceBuffer;
new(): SourceBuffer;
interface Blob {
type: string;
size: number;
msDetachStream(): any;
slice(start?: number, end?: number, contentType?: string): Blob;
msClose(): void;
}
declare var Blob: {
prototype: Blob;
new (blobParts?: any[], options?: BlobPropertyBag): Blob;
}
interface NavigatorID {
@@ -4636,26 +4648,6 @@ declare var MSCSSProperties: {
new(): MSCSSProperties;
}
interface HTMLCollection extends MSHTMLCollectionExtensions {
/**
* Sets or retrieves the number of objects in a collection.
*/
length: number;
/**
* Retrieves an object from various collections.
*/
item(nameOrIndex?: any, optionalIndex?: any): Element;
/**
* Retrieves a select object or an object from an options collection.
*/
namedItem(name: string): Element;
// [name: string]: Element;
}
declare var HTMLCollection: {
prototype: HTMLCollection;
new(): HTMLCollection;
}
interface SVGExternalResourcesRequired {
externalResourcesRequired: SVGAnimatedBoolean;
}
@@ -10891,18 +10883,6 @@ declare var FileReader: {
new(): FileReader;
}
interface Blob {
type: string;
size: number;
msDetachStream(): any;
slice(start?: number, end?: number, contentType?: string): Blob;
msClose(): void;
}
declare var Blob: {
prototype: Blob;
new(): Blob;
}
interface ApplicationCache extends EventTarget {
status: number;
ondownloading: (ev: Event) => any;
@@ -11061,6 +11041,14 @@ declare var MSManipulationEvent: {
MS_MANIPULATION_STATE_CANCELLED: number;
}
interface FormData {
append(name: any, value: any, blobName?: string): void;
}
declare var FormData: {
prototype: FormData;
new(): FormData;
}
interface HTMLDataListElement extends HTMLElement {
options: HTMLCollection;
}
@@ -11479,6 +11467,23 @@ interface RandomSource {
getRandomValues(array: ArrayBufferView): ArrayBufferView;
}
interface SourceBuffer extends EventTarget {
updating: boolean;
appendWindowStart: number;
appendWindowEnd: number;
buffered: TimeRanges;
timestampOffset: number;
audioTracks: AudioTrackList;
appendBuffer(data: ArrayBuffer): void;
remove(start: number, end: number): void;
abort(): void;
appendStream(stream: MSStream, maxSize?: number): void;
}
declare var SourceBuffer: {
prototype: SourceBuffer;
new(): SourceBuffer;
}
interface MSInputMethodContext extends EventTarget {
oncandidatewindowshow: (ev: any) => any;
target: HTMLElement;
+22 -17
View File
@@ -79,14 +79,14 @@ interface Int8Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Int8Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -137,14 +137,14 @@ interface Uint8Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Uint8Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -195,14 +195,14 @@ interface Int16Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Int16Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -253,14 +253,14 @@ interface Uint16Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Uint16Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -311,14 +311,14 @@ interface Int32Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Int32Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -369,14 +369,14 @@ interface Uint32Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Uint32Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -427,14 +427,14 @@ interface Float32Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Float32Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -485,14 +485,14 @@ interface Float64Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Float64Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -1453,6 +1453,11 @@ declare var FileReader: {
new(): FileReader;
}
interface BlobPropertyBag {
type?: string;
endings?: string;
}
interface Blob {
type: string;
size: number;
@@ -1462,7 +1467,7 @@ interface Blob {
}
declare var Blob: {
prototype: Blob;
new(): Blob;
new (blobParts?: any[], options?: BlobPropertyBag): Blob;
}
interface MSStream {
+8106 -5742
View File
File diff suppressed because one or more lines are too long
+13620 -22593
View File
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
+5731
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "typescript",
"author": "Microsoft Corp.",
"homepage": "http://typescriptlang.org/",
"version": "1.0.1",
"version": "1.3.0",
"licenses": [
{
"type": "Apache License 2.0",
+40 -39
View File
@@ -33,44 +33,44 @@ function importDefinitelyTypedTest(testCaseName: string, testFiles: string[], re
fs.mkdirSync(testDirectoryPath);
child_process.exec(cmd, {
maxBuffer: 1 * 1024 * 1024,
cwd: testDirectoryPath
}, (error, stdout, stderr) => {
//console.log("importing " + testCaseName + " ...");
//console.log(cmd);
if (error) {
console.log("importing " + testCaseName + " ...");
console.log(cmd);
console.log("==> error " + JSON.stringify(error));
console.log("==> stdout " + String(stdout));
console.log("==> stderr " + String(stderr));
console.log("\r\n");
return;
}
// copy generated file to output location
var outputFilePath = path.join(testDirectoryPath, "iocapture0.json");
var testCasePath = path.join(rwcTestPath, "DefinitelyTyped_" + testCaseName + ".json");
copyFileSync(outputFilePath, testCasePath);
//console.log("output generated at: " + outputFilePath);
if (!fs.existsSync(testCasePath)) {
throw new Error("could not find test case at: " + testCasePath);
}
else {
fs.unlinkSync(outputFilePath);
fs.rmdirSync(testDirectoryPath);
//console.log("testcase generated at: " + testCasePath);
//console.log("Done.");
}
//console.log("\r\n");
})
.on('error', function (error) {
console.log("==> error " + JSON.stringify(error));
console.log("\r\n");
maxBuffer: 1 * 1024 * 1024,
cwd: testDirectoryPath
}, (error, stdout, stderr) => {
console.log("importing " + testCaseName + " ...");
console.log(cmd);
if (error) {
console.log("importing " + testCaseName + " ...");
console.log(cmd);
console.log("==> error " + JSON.stringify(error));
console.log("==> stdout " + String(stdout));
console.log("==> stderr " + String(stderr));
console.log("\r\n");
return;
}
// copy generated file to output location
var outputFilePath = path.join(testDirectoryPath, "iocapture0.json");
var testCasePath = path.join(rwcTestPath, "DefinitelyTyped_" + testCaseName + ".json");
copyFileSync(outputFilePath, testCasePath);
//console.log("output generated at: " + outputFilePath);
if (!fs.existsSync(testCasePath)) {
throw new Error("could not find test case at: " + testCasePath);
}
else {
fs.unlinkSync(outputFilePath);
fs.rmdirSync(testDirectoryPath);
//console.log("testcase generated at: " + testCasePath);
//console.log("Done.");
}
//console.log("\r\n");
})
.on('error', function (error) {
console.log("==> error " + JSON.stringify(error));
console.log("\r\n");
});
}
@@ -79,7 +79,8 @@ function importDefinitelyTypedTests(definitelyTypedRoot: string): void {
if (err) throw err;
subDirectorys
.filter(d => ["_infrastructure", "node_modules", ".git"].indexOf(d) >= 0)
.filter(d => ["_infrastructure", "node_modules", ".git"].indexOf(d) < 0)
.filter(i => i.indexOf("sipml") >=0 )
.filter(i => fs.statSync(path.join(definitelyTypedRoot, i)).isDirectory())
.forEach(d => {
var directoryPath = path.join(definitelyTypedRoot, d);
-124
View File
@@ -1,124 +0,0 @@
declare var require: any, process: any;
declare var __dirname: any;
var fs = require("fs");
var path = require("path");
var child_process = require('child_process');
var tscRoot = path.join(__dirname, "..\\");
var tscPath = path.join(tscRoot, "built", "instrumented", "tsc.js");
var rwcTestPath = path.join(tscRoot, "tests", "cases", "rwc", "dt");
var definitelyTypedRoot = process.argv[2];
function fileExtensionIs(path: string, extension: string): boolean {
var pathLen = path.length;
var extLen = extension.length;
return pathLen > extLen && path.substr(pathLen - extLen, extLen).toLocaleLowerCase() === extension.toLocaleLowerCase();
}
function copyFileSync(source, destination) {
var text = fs.readFileSync(source);
fs.writeFileSync(destination, text);
}
function importDefinitelyTypedTest(testCaseName: string, testFiles: string[], responseFile: string ) {
var cmd = "node " + tscPath + " --module commonjs " + testFiles.join(" ");
if (responseFile) cmd += " @" + responseFile;
var testDirectoryName = testCaseName + "_" + Math.floor((Math.random() * 10000) + 1);
var testDirectoryPath = path.join(process.env["temp"], testDirectoryName);
if (fs.existsSync(testDirectoryPath)) {
throw new Error("Could not create test directory");
}
fs.mkdirSync(testDirectoryPath);
child_process.exec(cmd, {
maxBuffer: 1 * 1024 * 1024,
cwd: testDirectoryPath
}, (error, stdout, stderr) => {
//console.log("importing " + testCaseName + " ...");
//console.log(cmd);
if (error) {
console.log("importing " + testCaseName + " ...");
console.log(cmd);
console.log("==> error " + JSON.stringify(error));
console.log("==> stdout " + String(stdout));
console.log("==> stderr " + String(stderr));
console.log("\r\n");
return;
}
// copy generated file to output location
var outputFilePath = path.join(testDirectoryPath, "iocapture0.json");
var testCasePath = path.join(rwcTestPath, "DefinitelyTyped_" + testCaseName + ".json");
copyFileSync(outputFilePath, testCasePath);
//console.log("output generated at: " + outputFilePath);
if (!fs.existsSync(testCasePath)) {
throw new Error("could not find test case at: " + testCasePath);
}
else {
fs.unlinkSync(outputFilePath);
fs.rmdirSync(testDirectoryPath);
//console.log("testcase generated at: " + testCasePath);
//console.log("Done.");
}
//console.log("\r\n");
})
.on('error', function (error) {
console.log("==> error " + JSON.stringify(error));
console.log("\r\n");
});
}
function importDefinitelyTypedTests(definitelyTypedRoot: string): void {
fs.readdir(definitelyTypedRoot, (err, subDirectorys) => {
if (err) throw err;
subDirectorys
.filter(d => ["_infrastructure", "node_modules", ".git"].indexOf(d) >= 0)
.filter(i => fs.statSync(path.join(definitelyTypedRoot, i)).isDirectory())
.forEach(d => {
var directoryPath = path.join(definitelyTypedRoot, d);
fs.readdir(directoryPath, function (err, files) {
if (err) throw err;
var tsFiles = [];
var testFiles = [];
var paramFile;
files
.map(f => path.join(directoryPath, f))
.forEach(f => {
if (fileExtensionIs(f, ".ts")) tsFiles.push(f);
else if (fileExtensionIs(f, ".tscparams")) paramFile = f;
if (fileExtensionIs(f, "-tests.ts")) testFiles.push(f);
});
if (testFiles.length === 0) {
// no test files but multiple d.ts's, e.g. winjs
var regexp = new RegExp(d + "(([-][0-9])|([\.]d[\.]ts))");
if (tsFiles.length > 1 && tsFiles.every(t => fileExtensionIs(t, ".d.ts") && regexp.test(t))) {
tsFiles.forEach(filename => {
importDefinitelyTypedTest(path.basename(filename, ".d.ts"), [filename], paramFile);
});
}
else {
importDefinitelyTypedTest(d, tsFiles, paramFile);
}
}
else {
testFiles.forEach(filename => {
importDefinitelyTypedTest(path.basename(filename, "-tests.ts"), [filename], paramFile);
});
}
});
})
});
}
importDefinitelyTypedTests(definitelyTypedRoot);
+123
View File
@@ -0,0 +1,123 @@
/// <reference path="../src/harness/external/node.d.ts" />
import fs = require('fs');
import path = require('path');
interface IOLog {
filesRead: {
path: string;
result: { contents: string; };
}[];
arguments: string[];
}
module Commands {
export function dir(obj: IOLog) {
obj.filesRead.filter(f => f.result !== undefined).forEach(f => {
console.log(f.path);
});
}
dir['description'] = ': displays a list of files';
export function find(obj: IOLog, str: string) {
obj.filesRead.filter(f => f.result !== undefined).forEach(f => {
var lines = f.result.contents.split('\n');
var printedHeader = false;
lines.forEach(line => {
if (line.indexOf(str) >= 0) {
if (!printedHeader) {
console.log(' === ' + f.path + ' ===');
printedHeader = true;
}
console.log(line);
}
});
});
}
find['description'] = ' string: finds text in files';
export function grab(obj: IOLog, filename: string) {
obj.filesRead.filter(f => f.result !== undefined).forEach(f => {
if (path.basename(f.path) === filename) {
fs.writeFile(filename, f.result.contents);
}
});
}
grab['description'] = ' filename.ts: writes out the specified file to disk';
export function extract(obj: IOLog, outputFolder: string) {
var directorySeparator = "/";
function directoryExists(path: string): boolean {
return fs.existsSync(path) && fs.statSync(path).isDirectory();
}
function getDirectoryPath(path: string) {
return path.substr(0, Math.max(getRootLength(path), path.lastIndexOf(directorySeparator)));
}
function getRootLength(path: string): number {
if (path.charAt(0) === directorySeparator) {
if (path.charAt(1) !== directorySeparator) return 1;
var p1 = path.indexOf(directorySeparator, 2);
if (p1 < 0) return 2;
var p2 = path.indexOf(directorySeparator, p1 + 1);
if (p2 < 0) return p1 + 1;
return p2 + 1;
}
if (path.charAt(1) === ":") {
if (path.charAt(2) === directorySeparator) return 3;
return 2;
}
return 0;
}
function ensureDirectoriesExist(directoryPath: string) {
if (directoryPath.length > getRootLength(directoryPath) && !directoryExists(directoryPath)) {
var parentDirectory = getDirectoryPath(directoryPath);
ensureDirectoriesExist(parentDirectory);
console.log("creating directory: " + directoryPath);
fs.mkdirSync(directoryPath);
}
}
function transalatePath(outputFolder:string, path: string): string {
return outputFolder + directorySeparator + path.replace(":", "");
}
function fileExists(path: string): boolean {
return fs.existsSync(path);
}
obj.filesRead.forEach(f => {
var filename = transalatePath(outputFolder, f.path);
ensureDirectoriesExist(getDirectoryPath(filename));
console.log("writing filename: " + filename);
fs.writeFile(filename, f.result.contents, (err) => { });
});
console.log("Command: tsc ");
obj.arguments.forEach(a => {
if (getRootLength(a) > 0) {
console.log(transalatePath(outputFolder, a));
}
else {
console.log(a);
}
console.log(" ");
});
}
extract['description'] = ' outputFolder: extract all input files to <outputFolder>';
}
var args = process.argv.slice(2);
if (args.length < 2) {
console.log('Usage: node ior.js path_to_file.json [command]');
console.log('List of commands: ');
Object.keys(Commands).forEach(k => console.log(' ' + k + Commands[k]['description']));
} else {
var cmd: Function = Commands[args[1]];
if (cmd === undefined) {
console.log('Unknown command ' + args[1]);
} else {
fs.readFile(args[0], 'utf-8', (err, data) => {
if (err) throw err;
var json = JSON.parse(data);
cmd.apply(undefined, [json].concat(args.slice(2)));
});
}
}
+4 -2
View File
@@ -3,6 +3,7 @@
interface DiagnosticDetails {
category: string;
code: number;
isEarly?: boolean;
}
interface InputDiagnosticMessageTable {
@@ -63,8 +64,9 @@ function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable, nameMap:
' ' + convertPropertyName(nameMap[name]) +
': { code: ' + diagnosticDetails.code +
', category: DiagnosticCategory.' + diagnosticDetails.category +
', key: "' + name.replace('"', '\\"') +
'" },\r\n';
', key: "' + name.replace('"', '\\"') + '"' +
(diagnosticDetails.isEarly ? ', isEarly: true' : '') +
' },\r\n';
}
result += ' };\r\n}';
+212
View File
@@ -0,0 +1,212 @@
var sys = (function () {
var fileStream = new ActiveXObject("ADODB.Stream");
fileStream.Type = 2;
var binaryStream = new ActiveXObject("ADODB.Stream");
binaryStream.Type = 1;
var args = [];
for (var i = 0; i < WScript.Arguments.length; i++) {
args[i] = WScript.Arguments.Item(i);
}
return {
args: args,
createObject: function (typeName) { return new ActiveXObject(typeName); },
write: function (s) {
WScript.StdOut.Write(s);
},
writeFile: function (fileName, data) {
fileStream.Open();
binaryStream.Open();
try {
fileStream.Charset = "utf-8";
fileStream.WriteText(data);
fileStream.Position = 3;
fileStream.CopyTo(binaryStream);
binaryStream.SaveToFile(fileName, 2);
}
finally {
binaryStream.Close();
fileStream.Close();
}
}
};
})();
function convertDocumentToMarkdown(doc) {
var result = "";
var lastStyle;
var lastInTable;
var tableColumnCount;
var tableCellIndex;
var columnAlignment = [];
function setProperties(target, properties) {
for (var name in properties) {
if (properties.hasOwnProperty(name)) {
var value = properties[name];
if (typeof value === "object") {
setProperties(target[name], value);
}
else {
target[name] = value;
}
}
}
}
function findReplace(findText, findOptions, replaceText, replaceOptions) {
var find = doc.range().find;
find.clearFormatting();
setProperties(find, findOptions);
var replace = find.replacement;
replace.clearFormatting();
setProperties(replace, replaceOptions);
find.execute(findText, false, false, false, false, false, true, 0, true, replaceText, 2);
}
function write(s) {
result += s;
}
function writeTableHeader() {
for (var i = 0; i < tableColumnCount - 1; i++) {
switch (columnAlignment[i]) {
case 1:
write("|:---:");
break;
case 2:
write("|---:");
break;
default:
write("|---");
}
}
write("|\n");
}
function trimEndFormattingMarks(text) {
var i = text.length;
while (i > 0 && text.charCodeAt(i - 1) < 0x20)
i--;
return text.substr(0, i);
}
function writeBlockEnd() {
switch (lastStyle) {
case "Code":
write("```\n\n");
break;
case "List Paragraph":
case "Table":
case "TOC":
write("\n");
break;
}
}
function writeParagraph(p) {
var text = p.range.text;
var style = p.style.nameLocal;
var inTable = p.range.tables.count > 0;
var level = 1;
var sectionBreak = text.indexOf("\x0C") >= 0;
text = trimEndFormattingMarks(text);
if (inTable) {
style = "Table";
}
else if (style.match(/\s\d$/)) {
level = +style.substr(style.length - 1);
style = style.substr(0, style.length - 2);
}
if (lastStyle && style !== lastStyle) {
writeBlockEnd();
}
switch (style) {
case "Heading":
case "Appendix":
var section = p.range.listFormat.listString;
write("####".substr(0, level) + ' <a name="' + section + '"/>' + section + " " + text + "\n\n");
break;
case "Normal":
if (text.length) {
write(text + "\n\n");
}
break;
case "List Paragraph":
write(" ".substr(0, p.range.listFormat.listLevelNumber * 2 - 2) + "* " + text + "\n");
break;
case "Grammar":
write("&emsp;&emsp;" + text.replace(/\s\s\s/g, "&emsp;").replace(/\x0B/g, " \n&emsp;&emsp;&emsp;") + "\n\n");
break;
case "Code":
if (lastStyle !== "Code") {
write("```TypeScript\n");
}
else {
write("\n");
}
write(text.replace(/\x0B/g, " \n") + "\n");
break;
case "Table":
if (!lastInTable) {
tableColumnCount = p.range.tables.item(1).columns.count + 1;
tableCellIndex = 0;
}
if (tableCellIndex < tableColumnCount) {
columnAlignment[tableCellIndex] = p.alignment;
}
write("|" + text);
tableCellIndex++;
if (tableCellIndex % tableColumnCount === 0) {
write("\n");
if (tableCellIndex === tableColumnCount) {
writeTableHeader();
}
}
break;
case "TOC Heading":
write("## " + text + "\n\n");
break;
case "TOC":
var strings = text.split("\t");
write(" ".substr(0, level * 2 - 2) + "* [" + strings[0] + " " + strings[1] + "](#" + strings[0] + ")\n");
break;
}
if (sectionBreak) {
write("<br/>\n\n");
}
lastStyle = style;
lastInTable = inTable;
}
function writeDocument() {
var title = doc.builtInDocumentProperties.item(1) + "";
if (title.length) {
write("# " + title + "\n\n");
}
for (var p = doc.paragraphs.first; p; p = p.next()) {
writeParagraph(p);
}
writeBlockEnd();
}
findReplace("<", {}, "&lt;", {});
findReplace("&lt;", { style: "Code" }, "<", {});
findReplace("&lt;", { style: "Code Fragment" }, "<", {});
findReplace("&lt;", { style: "Terminal" }, "<", {});
findReplace("", { font: { subscript: true } }, "<sub>^&</sub>", { font: { subscript: false } });
findReplace("", { style: "Code Fragment" }, "`^&`", { style: -66 });
findReplace("", { style: "Production" }, "*^&*", { style: -66 });
findReplace("", { style: "Terminal" }, "`^&`", { style: -66 });
findReplace("", { font: { bold: true, italic: true } }, "***^&***", { font: { bold: false, italic: false } });
findReplace("", { font: { italic: true } }, "*^&*", { font: { italic: false } });
doc.fields.toggleShowCodes();
findReplace("^19 REF", {}, "[^&](#^&)", {});
doc.fields.toggleShowCodes();
writeDocument();
result = result.replace(/\x85/g, "\u2026");
result = result.replace(/\x96/g, "\u2013");
result = result.replace(/\x97/g, "\u2014");
return result;
}
function main(args) {
if (args.length !== 2) {
sys.write("Syntax: word2md <inputfile> <outputfile>\n");
return;
}
var app = sys.createObject("Word.Application");
var doc = app.documents.open(args[0]);
sys.writeFile(args[1], convertDocumentToMarkdown(doc));
doc.close(false);
app.quit();
}
main(sys.args);
+371
View File
@@ -0,0 +1,371 @@
// word2md - Word to Markdown conversion tool
//
// word2md converts a Microsoft Word document to Markdown formatted text. The tool uses the
// Word Automation APIs to start an instance of Word and access the contents of the document
// being converted. The tool must be run using the cscript.exe script host and requires Word
// to be installed on the target machine. The name of the document to convert must be specified
// as a command line argument and the resulting Markdown is written to standard output. The
// tool recognizes the specific Word styles used in the TypeScript Language Specification.
module Word {
export interface Collection<T> {
count: number;
item(index: number): T;
}
export interface Font {
bold: boolean;
italic: boolean;
subscript: boolean;
superscript: boolean;
}
export interface Find {
font: Font;
format: boolean;
replacement: Replacement;
style: any;
text: string;
clearFormatting(): void;
execute(
findText: string,
matchCase: boolean,
matchWholeWord: boolean,
matchWildcards: boolean,
matchSoundsLike: boolean,
matchAllWordForms: boolean,
forward: boolean,
wrap: number,
format: boolean,
replaceWith: string,
replace: number): boolean;
}
export interface Replacement {
font: Font;
style: any;
text: string;
clearFormatting(): void;
}
export interface ListFormat {
listLevelNumber: number;
listString: string;
}
export interface Column {
}
export interface Columns extends Collection<Column> {
}
export interface Table {
columns: Columns;
}
export interface Tables extends Collection<Table> {
}
export interface Range {
find: Find;
listFormat: ListFormat;
tables: Tables;
text: string;
words: Ranges;
}
export interface Ranges extends Collection<Range> {
}
export interface Style {
nameLocal: string;
}
export interface Paragraph {
alignment: number;
range: Range;
style: Style;
next(): Paragraph;
}
export interface Paragraphs extends Collection<Paragraph> {
first: Paragraph;
}
export interface Field {
}
export interface Fields extends Collection<Field> {
toggleShowCodes(): void;
}
export interface Document {
fields: Fields;
paragraphs: Paragraphs;
builtInDocumentProperties: Collection<any>;
close(saveChanges: boolean): void;
range(): Range;
}
export interface Documents extends Collection<Document> {
open(filename: string): Document;
}
export interface Application {
documents: Documents;
quit(): void;
}
}
var sys = (function () {
var fileStream = new ActiveXObject("ADODB.Stream");
fileStream.Type = 2 /*text*/;
var binaryStream = new ActiveXObject("ADODB.Stream");
binaryStream.Type = 1 /*binary*/;
var args: string[] = [];
for (var i = 0; i < WScript.Arguments.length; i++) {
args[i] = WScript.Arguments.Item(i);
}
return {
args: args,
createObject: (typeName: string) => new ActiveXObject(typeName),
write(s: string): void {
WScript.StdOut.Write(s);
},
writeFile: (fileName: string, data: string): void => {
fileStream.Open();
binaryStream.Open();
try {
// Write characters in UTF-8 encoding
fileStream.Charset = "utf-8";
fileStream.WriteText(data);
// We don't want the BOM, skip it by setting the starting location to 3 (size of BOM).
fileStream.Position = 3;
fileStream.CopyTo(binaryStream);
binaryStream.SaveToFile(fileName, 2 /*overwrite*/);
}
finally {
binaryStream.Close();
fileStream.Close();
}
}
};
})();
interface FindReplaceOptions {
style?: any;
font?: {
bold?: boolean;
italic?: boolean;
subscript?: boolean;
};
}
function convertDocumentToMarkdown(doc: Word.Document): string {
var result: string = "";
var lastStyle: string;
var lastInTable: boolean;
var tableColumnCount: number;
var tableCellIndex: number;
var columnAlignment: number[] = [];
function setProperties(target: any, properties: any) {
for (var name in properties) {
if (properties.hasOwnProperty(name)) {
var value = properties[name];
if (typeof value === "object") {
setProperties(target[name], value);
}
else {
target[name] = value;
}
}
}
}
function findReplace(findText: string, findOptions: FindReplaceOptions, replaceText: string, replaceOptions: FindReplaceOptions) {
var find = doc.range().find;
find.clearFormatting();
setProperties(find, findOptions);
var replace = find.replacement;
replace.clearFormatting();
setProperties(replace, replaceOptions);
find.execute(findText, false, false, false, false, false, true, 0, true, replaceText, 2);
}
function write(s: string) {
result += s;
}
function writeTableHeader() {
for (var i = 0; i < tableColumnCount - 1; i++) {
switch (columnAlignment[i]) {
case 1:
write("|:---:");
break;
case 2:
write("|---:");
break;
default:
write("|---");
}
}
write("|\n");
}
function trimEndFormattingMarks(text: string) {
var i = text.length;
while (i > 0 && text.charCodeAt(i - 1) < 0x20) i--;
return text.substr(0, i);
}
function writeBlockEnd() {
switch (lastStyle) {
case "Code":
write("```\n\n");
break;
case "List Paragraph":
case "Table":
case "TOC":
write("\n");
break;
}
}
function writeParagraph(p: Word.Paragraph) {
var text = p.range.text;
var style = p.style.nameLocal;
var inTable = p.range.tables.count > 0;
var level = 1;
var sectionBreak = text.indexOf("\x0C") >= 0;
text = trimEndFormattingMarks(text);
if (inTable) {
style = "Table";
}
else if (style.match(/\s\d$/)) {
level = +style.substr(style.length - 1);
style = style.substr(0, style.length - 2);
}
if (lastStyle && style !== lastStyle) {
writeBlockEnd();
}
switch (style) {
case "Heading":
case "Appendix":
var section = p.range.listFormat.listString;
write("####".substr(0, level) + ' <a name="' + section + '"/>' + section + " " + text + "\n\n");
break;
case "Normal":
if (text.length) {
write(text + "\n\n");
}
break;
case "List Paragraph":
write(" ".substr(0, p.range.listFormat.listLevelNumber * 2 - 2) + "* " + text + "\n");
break;
case "Grammar":
write("&emsp;&emsp;" + text.replace(/\s\s\s/g, "&emsp;").replace(/\x0B/g, " \n&emsp;&emsp;&emsp;") + "\n\n");
break;
case "Code":
if (lastStyle !== "Code") {
write("```TypeScript\n");
}
else {
write("\n");
}
write(text.replace(/\x0B/g, " \n") + "\n");
break;
case "Table":
if (!lastInTable) {
tableColumnCount = p.range.tables.item(1).columns.count + 1;
tableCellIndex = 0;
}
if (tableCellIndex < tableColumnCount) {
columnAlignment[tableCellIndex] = p.alignment;
}
write("|" + text);
tableCellIndex++;
if (tableCellIndex % tableColumnCount === 0) {
write("\n");
if (tableCellIndex === tableColumnCount) {
writeTableHeader();
}
}
break;
case "TOC Heading":
write("## " + text + "\n\n");
break;
case "TOC":
var strings = text.split("\t");
write(" ".substr(0, level * 2 - 2) + "* [" + strings[0] + " " + strings[1] + "](#" + strings[0] + ")\n");
break;
}
if (sectionBreak) {
write("<br/>\n\n");
}
lastStyle = style;
lastInTable = inTable;
}
function writeDocument() {
var title = doc.builtInDocumentProperties.item(1) + "";
if (title.length) {
write("# " + title + "\n\n");
}
for (var p = doc.paragraphs.first; p; p = p.next()) {
writeParagraph(p);
}
writeBlockEnd();
}
findReplace("<", {}, "&lt;", {});
findReplace("&lt;", { style: "Code" }, "<", {});
findReplace("&lt;", { style: "Code Fragment" }, "<", {});
findReplace("&lt;", { style: "Terminal" }, "<", {});
findReplace("", { font: { subscript: true } }, "<sub>^&</sub>", { font: { subscript: false } });
findReplace("", { style: "Code Fragment" }, "`^&`", { style: -66 /* default font */ });
findReplace("", { style: "Production" }, "*^&*", { style: -66 /* default font */});
findReplace("", { style: "Terminal" }, "`^&`", { style: -66 /* default font */});
findReplace("", { font: { bold: true, italic: true } }, "***^&***", { font: { bold: false, italic: false } });
findReplace("", { font: { italic: true } }, "*^&*", { font: { italic: false } });
doc.fields.toggleShowCodes();
findReplace("^19 REF", {}, "[^&](#^&)", {});
doc.fields.toggleShowCodes();
writeDocument();
result = result.replace(/\x85/g, "\u2026");
result = result.replace(/\x96/g, "\u2013");
result = result.replace(/\x97/g, "\u2014");
return result;
}
function main(args: string[]) {
if (args.length !== 2) {
sys.write("Syntax: word2md <inputfile> <outputfile>\n");
return;
}
var app: Word.Application = sys.createObject("Word.Application");
var doc = app.documents.open(args[0]);
sys.writeFile(args[1], convertDocumentToMarkdown(doc));
doc.close(false);
app.quit();
}
main(sys.args);
+192 -59
View File
@@ -5,25 +5,51 @@
module ts {
export function isInstantiated(node: Node): boolean {
export const enum ModuleInstanceState {
NonInstantiated = 0,
Instantiated = 1,
ConstEnumOnly = 2
}
export function getModuleInstanceState(node: Node): ModuleInstanceState {
// A module is uninstantiated if it contains only
// 1. interface declarations
if (node.kind === SyntaxKind.InterfaceDeclaration) {
return false;
return ModuleInstanceState.NonInstantiated;
}
// 2. non - exported import declarations
// 2. const enum declarations don't make module instantiated
else if (isConstEnumDeclaration(node)) {
return ModuleInstanceState.ConstEnumOnly;
}
// 3. non - exported import declarations
else if (node.kind === SyntaxKind.ImportDeclaration && !(node.flags & NodeFlags.Export)) {
return false;
return ModuleInstanceState.NonInstantiated;
}
// 3. other uninstantiated module declarations.
else if (node.kind === SyntaxKind.ModuleBlock && !forEachChild(node, isInstantiated)) {
return false;
// 4. other uninstantiated module declarations.
else if (node.kind === SyntaxKind.ModuleBlock) {
var state = ModuleInstanceState.NonInstantiated;
forEachChild(node, n => {
switch (getModuleInstanceState(n)) {
case ModuleInstanceState.NonInstantiated:
// child is non-instantiated - continue searching
return false;
case ModuleInstanceState.ConstEnumOnly:
// child is const enum only - record state and continue searching
state = ModuleInstanceState.ConstEnumOnly;
return false;
case ModuleInstanceState.Instantiated:
// child is instantiated - record state and stop
state = ModuleInstanceState.Instantiated;
return true;
}
});
return state;
}
else if (node.kind === SyntaxKind.ModuleDeclaration && !isInstantiated((<ModuleDeclaration>node).body)) {
return false;
else if (node.kind === SyntaxKind.ModuleDeclaration) {
return getModuleInstanceState((<ModuleDeclaration>node).body);
}
else {
return true;
return ModuleInstanceState.Instantiated;
}
}
@@ -31,13 +57,14 @@ module ts {
var parent: Node;
var container: Declaration;
var blockScopeContainer: Node;
var lastContainer: Declaration;
var symbolCount = 0;
var Symbol = objectAllocator.getSymbolConstructor();
if (!file.locals) {
file.locals = {};
container = file;
container = blockScopeContainer = file;
bind(file);
file.symbolCount = symbolCount;
}
@@ -57,23 +84,30 @@ module ts {
if (symbolKind & SymbolFlags.Value && !symbol.valueDeclaration) symbol.valueDeclaration = node;
}
// TODO(jfreeman): Implement getDeclarationName for property name
function getDeclarationName(node: Declaration): string {
if (node.name) {
if (node.kind === SyntaxKind.ModuleDeclaration && node.name.kind === SyntaxKind.StringLiteral) {
return '"' + node.name.text + '"';
return '"' + (<LiteralExpression>node.name).text + '"';
}
return node.name.text;
return (<Identifier>node.name).text;
}
switch (node.kind) {
case SyntaxKind.Constructor: return "__constructor";
case SyntaxKind.CallSignature: return "__call";
case SyntaxKind.ConstructSignature: return "__new";
case SyntaxKind.IndexSignature: return "__index";
case SyntaxKind.ConstructorType:
case SyntaxKind.Constructor:
return "__constructor";
case SyntaxKind.FunctionType:
case SyntaxKind.CallSignature:
return "__call";
case SyntaxKind.ConstructSignature:
return "__new";
case SyntaxKind.IndexSignature:
return "__index";
}
}
function getDisplayName(node: Declaration): string {
return node.name ? identifierToString(node.name) : getDeclarationName(node);
return node.name ? declarationNameToString(node.name) : getDeclarationName(node);
}
function declareSymbol(symbols: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol {
@@ -84,8 +118,17 @@ module ts {
if (node.name) {
node.name.parent = node;
}
file.semanticErrors.push(createDiagnosticForNode(node.name ? node.name : node,
Diagnostics.Duplicate_identifier_0, getDisplayName(node)));
// Report errors every position with duplicate declaration
// Report errors on previous encountered declarations
var message = symbol.flags & SymbolFlags.BlockScopedVariable
? Diagnostics.Cannot_redeclare_block_scoped_variable_0
: Diagnostics.Duplicate_identifier_0;
forEach(symbol.declarations, declaration => {
file.semanticDiagnostics.push(createDiagnosticForNode(declaration.name, message, getDisplayName(declaration)));
});
file.semanticDiagnostics.push(createDiagnosticForNode(node.name, message, getDisplayName(node)));
symbol = createSymbol(0, name);
}
}
@@ -105,7 +148,7 @@ module ts {
if (node.name) {
node.name.parent = node;
}
file.semanticErrors.push(createDiagnosticForNode(symbol.exports[prototypeSymbol.name].declarations[0],
file.semanticDiagnostics.push(createDiagnosticForNode(symbol.exports[prototypeSymbol.name].declarations[0],
Diagnostics.Duplicate_identifier_0, prototypeSymbol.name));
}
symbol.exports[prototypeSymbol.name] = prototypeSymbol;
@@ -162,12 +205,13 @@ module ts {
// All container nodes are kept on a linked list in declaration order. This list is used by the getLocalNameOfContainer function
// in the type checker to validate that the local name used for a container is unique.
function bindChildren(node: Declaration, symbolKind: SymbolFlags) {
function bindChildren(node: Declaration, symbolKind: SymbolFlags, isBlockScopeContainer: boolean) {
if (symbolKind & SymbolFlags.HasLocals) {
node.locals = {};
}
var saveParent = parent;
var saveContainer = container;
var savedBlockScopeContainer = blockScopeContainer;
parent = node;
if (symbolKind & SymbolFlags.IsContainer) {
container = node;
@@ -179,12 +223,16 @@ module ts {
lastContainer = container;
}
}
if (isBlockScopeContainer) {
blockScopeContainer = node;
}
forEachChild(node, bind);
container = saveContainer;
parent = saveParent;
blockScopeContainer = savedBlockScopeContainer;
}
function bindDeclaration(node: Declaration, symbolKind: SymbolFlags, symbolExcludes: SymbolFlags) {
function bindDeclaration(node: Declaration, symbolKind: SymbolFlags, symbolExcludes: SymbolFlags, isBlockScopeContainer: boolean) {
switch (container.kind) {
case SyntaxKind.ModuleDeclaration:
declareModuleMember(node, symbolKind, symbolExcludes);
@@ -194,6 +242,8 @@ module ts {
declareModuleMember(node, symbolKind, symbolExcludes);
break;
}
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructorType:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.IndexSignature:
@@ -220,121 +270,204 @@ module ts {
declareSymbol(container.symbol.exports, container.symbol, node, symbolKind, symbolExcludes);
break;
}
bindChildren(node, symbolKind);
bindChildren(node, symbolKind, isBlockScopeContainer);
}
function bindConstructorDeclaration(node: ConstructorDeclaration) {
bindDeclaration(node, SymbolFlags.Constructor, 0);
bindDeclaration(node, SymbolFlags.Constructor, 0, /*isBlockScopeContainer*/ true);
forEach(node.parameters, p => {
if (p.flags & (NodeFlags.Public | NodeFlags.Private)) {
bindDeclaration(p, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
if (p.flags & (NodeFlags.Public | NodeFlags.Private | NodeFlags.Protected)) {
bindDeclaration(p, SymbolFlags.Property, SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false);
}
});
}
function bindModuleDeclaration(node: ModuleDeclaration) {
if (node.name.kind === SyntaxKind.StringLiteral) {
bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes);
}
else if (isInstantiated(node)) {
bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes);
bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes, /*isBlockScopeContainer*/ true);
}
else {
bindDeclaration(node, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes);
var state = getModuleInstanceState(node);
if (state === ModuleInstanceState.NonInstantiated) {
bindDeclaration(node, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes, /*isBlockScopeContainer*/ true);
}
else {
bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes, /*isBlockScopeContainer*/ true);
if (state === ModuleInstanceState.ConstEnumOnly) {
// mark value module as module that contains only enums
node.symbol.constEnumOnlyModule = true;
}
else if (node.symbol.constEnumOnlyModule) {
// const only value module was merged with instantiated module - reset flag
node.symbol.constEnumOnlyModule = false;
}
}
}
}
function bindAnonymousDeclaration(node: Node, symbolKind: SymbolFlags, name: string) {
function bindFunctionOrConstructorType(node: SignatureDeclaration) {
// For a given function symbol "<...>(...) => T" we want to generate a symbol identical
// to the one we would get for: { <...>(...): T }
//
// We do that by making an anonymous type literal symbol, and then setting the function
// symbol as its sole member. To the rest of the system, this symbol will be indistinguishable
// from an actual type literal symbol you would have gotten had you used the long form.
var symbolKind = node.kind === SyntaxKind.FunctionType ? SymbolFlags.CallSignature : SymbolFlags.ConstructSignature;
var symbol = createSymbol(symbolKind, getDeclarationName(node));
addDeclarationToSymbol(symbol, node, symbolKind);
bindChildren(node, symbolKind, /*isBlockScopeContainer:*/ false);
var typeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, "__type");
addDeclarationToSymbol(typeLiteralSymbol, node, SymbolFlags.TypeLiteral);
typeLiteralSymbol.members = {};
typeLiteralSymbol.members[node.kind === SyntaxKind.FunctionType ? "__call" : "__new"] = symbol
}
function bindAnonymousDeclaration(node: Node, symbolKind: SymbolFlags, name: string, isBlockScopeContainer: boolean) {
var symbol = createSymbol(symbolKind, name);
addDeclarationToSymbol(symbol, node, symbolKind);
bindChildren(node, symbolKind);
bindChildren(node, symbolKind, isBlockScopeContainer);
}
function bindCatchVariableDeclaration(node: CatchBlock) {
var symbol = createSymbol(SymbolFlags.Variable, node.variable.text || "__missing");
addDeclarationToSymbol(symbol, node, SymbolFlags.Variable);
var symbol = createSymbol(SymbolFlags.FunctionScopedVariable, node.variable.text || "__missing");
addDeclarationToSymbol(symbol, node, SymbolFlags.FunctionScopedVariable);
var saveParent = parent;
parent = node;
var savedBlockScopeContainer = blockScopeContainer;
parent = blockScopeContainer = node;
forEachChild(node, bind);
parent = saveParent;
blockScopeContainer = savedBlockScopeContainer;
}
function bindBlockScopedVariableDeclaration(node: Declaration) {
switch (blockScopeContainer.kind) {
case SyntaxKind.ModuleDeclaration:
declareModuleMember(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes);
break;
case SyntaxKind.SourceFile:
if (isExternalModule(<SourceFile>container)) {
declareModuleMember(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes);
break;
}
default:
if (!blockScopeContainer.locals) {
blockScopeContainer.locals = {};
}
declareSymbol(blockScopeContainer.locals, undefined, node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes);
}
bindChildren(node, SymbolFlags.BlockScopedVariable, /*isBlockScopeContainer*/ false);
}
function bind(node: Node) {
node.parent = parent;
switch (node.kind) {
case SyntaxKind.TypeParameter:
bindDeclaration(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
bindDeclaration(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.Parameter:
bindDeclaration(<Declaration>node, SymbolFlags.Variable, SymbolFlags.ParameterExcludes);
bindDeclaration(<Declaration>node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.VariableDeclaration:
bindDeclaration(<Declaration>node, SymbolFlags.Variable, SymbolFlags.VariableExcludes);
if (node.flags & NodeFlags.BlockScoped) {
bindBlockScopedVariableDeclaration(<Declaration>node);
}
else {
bindDeclaration(<Declaration>node, SymbolFlags.FunctionScopedVariable, SymbolFlags.FunctionScopedVariableExcludes, /*isBlockScopeContainer*/ false);
}
break;
case SyntaxKind.Property:
case SyntaxKind.PropertyAssignment:
bindDeclaration(<Declaration>node, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
case SyntaxKind.ShorthandPropertyAssignment:
bindDeclaration(<Declaration>node, SymbolFlags.Property, SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.EnumMember:
bindDeclaration(<Declaration>node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes);
bindDeclaration(<Declaration>node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.CallSignature:
bindDeclaration(<Declaration>node, SymbolFlags.CallSignature, 0);
break;
case SyntaxKind.Method:
bindDeclaration(<Declaration>node, SymbolFlags.Method, SymbolFlags.MethodExcludes);
bindDeclaration(<Declaration>node, SymbolFlags.CallSignature, 0, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.ConstructSignature:
bindDeclaration(<Declaration>node, SymbolFlags.ConstructSignature, 0);
bindDeclaration(<Declaration>node, SymbolFlags.ConstructSignature, 0, /*isBlockScopeContainer*/ true);
break;
case SyntaxKind.Method:
bindDeclaration(<Declaration>node, SymbolFlags.Method, SymbolFlags.MethodExcludes, /*isBlockScopeContainer*/ true);
break;
case SyntaxKind.IndexSignature:
bindDeclaration(<Declaration>node, SymbolFlags.IndexSignature, 0);
bindDeclaration(<Declaration>node, SymbolFlags.IndexSignature, 0, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.FunctionDeclaration:
bindDeclaration(<Declaration>node, SymbolFlags.Function, SymbolFlags.FunctionExcludes);
bindDeclaration(<Declaration>node, SymbolFlags.Function, SymbolFlags.FunctionExcludes, /*isBlockScopeContainer*/ true);
break;
case SyntaxKind.Constructor:
bindConstructorDeclaration(<ConstructorDeclaration>node);
break;
case SyntaxKind.GetAccessor:
bindDeclaration(<Declaration>node, SymbolFlags.GetAccessor, SymbolFlags.GetAccessorExcludes);
bindDeclaration(<Declaration>node, SymbolFlags.GetAccessor, SymbolFlags.GetAccessorExcludes, /*isBlockScopeContainer*/ true);
break;
case SyntaxKind.SetAccessor:
bindDeclaration(<Declaration>node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes);
bindDeclaration(<Declaration>node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes, /*isBlockScopeContainer*/ true);
break;
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructorType:
bindFunctionOrConstructorType(<SignatureDeclaration>node);
break;
case SyntaxKind.TypeLiteral:
bindAnonymousDeclaration(node, SymbolFlags.TypeLiteral, "__type");
bindAnonymousDeclaration(node, SymbolFlags.TypeLiteral, "__type", /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.ObjectLiteral:
bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, "__object");
bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, "__object", /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
bindAnonymousDeclaration(node, SymbolFlags.Function, "__function");
bindAnonymousDeclaration(node, SymbolFlags.Function, "__function", /*isBlockScopeContainer*/ true);
break;
case SyntaxKind.CatchBlock:
bindCatchVariableDeclaration(<CatchBlock>node);
break;
case SyntaxKind.ClassDeclaration:
bindDeclaration(<Declaration>node, SymbolFlags.Class, SymbolFlags.ClassExcludes);
bindDeclaration(<Declaration>node, SymbolFlags.Class, SymbolFlags.ClassExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.InterfaceDeclaration:
bindDeclaration(<Declaration>node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes);
bindDeclaration(<Declaration>node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.TypeAliasDeclaration:
bindDeclaration(<Declaration>node, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.EnumDeclaration:
bindDeclaration(<Declaration>node, SymbolFlags.Enum, SymbolFlags.EnumExcludes);
if (isConst(node)) {
bindDeclaration(<Declaration>node, SymbolFlags.ConstEnum, SymbolFlags.ConstEnumExcludes, /*isBlockScopeContainer*/ false);
}
else {
bindDeclaration(<Declaration>node, SymbolFlags.RegularEnum, SymbolFlags.RegularEnumExcludes, /*isBlockScopeContainer*/ false);
}
break;
case SyntaxKind.ModuleDeclaration:
bindModuleDeclaration(<ModuleDeclaration>node);
break;
case SyntaxKind.ImportDeclaration:
bindDeclaration(<Declaration>node, SymbolFlags.Import, SymbolFlags.ImportExcludes);
bindDeclaration(<Declaration>node, SymbolFlags.Import, SymbolFlags.ImportExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.SourceFile:
if (isExternalModule(<SourceFile>node)) {
bindAnonymousDeclaration(node, SymbolFlags.ValueModule, '"' + getModuleNameFromFilename((<SourceFile>node).filename) + '"');
bindAnonymousDeclaration(node, SymbolFlags.ValueModule, '"' + removeFileExtension((<SourceFile>node).filename) + '"', /*isBlockScopeContainer*/ true);
break;
}
case SyntaxKind.Block:
case SyntaxKind.TryBlock:
case SyntaxKind.CatchBlock:
case SyntaxKind.FinallyBlock:
case SyntaxKind.ForStatement:
case SyntaxKind.ForInStatement:
case SyntaxKind.SwitchStatement:
bindChildren(node, 0 , true);
break;
default:
var saveParent = parent;
parent = node;
+3530 -1599
View File
File diff suppressed because it is too large Load Diff
+21 -10
View File
@@ -24,7 +24,7 @@ module ts {
type: "boolean",
},
{
name: "emitBOM",
name: "emitBOM",
type: "boolean"
},
{
@@ -54,6 +54,11 @@ module ts {
paramType: Diagnostics.KIND,
error: Diagnostics.Argument_for_module_option_must_be_commonjs_or_amd
},
{
name: "noEmitOnError",
type: "boolean",
description: Diagnostics.Do_not_emit_outputs_if_any_type_checking_errors_were_reported,
},
{
name: "noImplicitAny",
type: "boolean",
@@ -102,10 +107,10 @@ module ts {
{
name: "target",
shortName: "t",
type: { "es3": ScriptTarget.ES3, "es5": ScriptTarget.ES5 },
description: Diagnostics.Specify_ECMAScript_target_version_Colon_ES3_default_or_ES5,
type: { "es3": ScriptTarget.ES3, "es5": ScriptTarget.ES5, "es6": ScriptTarget.ES6 },
description: Diagnostics.Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES6_experimental,
paramType: Diagnostics.VERSION,
error: Diagnostics.Argument_for_target_option_must_be_es3_or_es5
error: Diagnostics.Argument_for_target_option_must_be_es3_es5_or_es6
},
{
name: "version",
@@ -118,6 +123,11 @@ module ts {
shortName: "w",
type: "boolean",
description: Diagnostics.Watch_input_files,
},
{
name: "preserveConstEnums",
type: "boolean",
description: Diagnostics.Do_not_erase_const_enum_declarations_in_generated_code
}
];
@@ -143,9 +153,9 @@ module ts {
parseStrings(commandLine);
return {
options: options,
filenames: filenames,
errors: errors
options,
filenames,
errors
};
function parseStrings(args: string[]) {
@@ -183,9 +193,10 @@ module ts {
break;
// If not a primitive, the possible types are specified in what is effectively a map of options.
default:
var value = (args[i++] || "").toLowerCase();
if (hasProperty(opt.type, value)) {
options[opt.name] = opt.type[value];
var map = <Map<number>>opt.type;
var key = (args[i++] || "").toLowerCase();
if (hasProperty(map, key)) {
options[opt.name] = map[key];
}
else {
errors.push(createCompilerDiagnostic(opt.error));
+146 -41
View File
@@ -1,17 +1,39 @@
/// <reference path="types.ts"/>
module ts {
// Ternary values are defined such that
// x & y is False if either x or y is False.
// x & y is Maybe if either x or y is Maybe, but neither x or y is False.
// x & y is True if both x and y are True.
// x | y is False if both x and y are False.
// x | y is Maybe if either x or y is Maybe, but neither x or y is True.
// x | y is True if either x or y is True.
export const enum Ternary {
False = 0,
Maybe = 1,
True = -1
}
export interface Map<T> {
[index: string]: T;
}
export const enum Comparison {
LessThan = -1,
EqualTo = 0,
GreaterThan = 1
}
export interface StringSet extends Map<any> { }
export function forEach<T, U>(array: T[], callback: (element: T) => U): U {
var result: U;
if (array) {
for (var i = 0, len = array.length; i < len; i++) {
if (result = callback(array[i])) break;
if (result = callback(array[i])) {
break;
}
}
}
return result;
@@ -19,8 +41,7 @@ module ts {
export function contains<T>(array: T[], value: T): boolean {
if (array) {
var len = array.length;
for (var i = 0; i < len; i++) {
for (var i = 0, len = array.length; i < len; i++) {
if (array[i] === value) {
return true;
}
@@ -31,8 +52,7 @@ module ts {
export function indexOf<T>(array: T[], value: T): number {
if (array) {
var len = array.length;
for (var i = 0; i < len; i++) {
for (var i = 0, len = array.length; i < len; i++) {
if (array[i] === value) {
return i;
}
@@ -41,10 +61,21 @@ module ts {
return -1;
}
export function filter<T>(array: T[], f: (x: T) => boolean): T[] {
var result: T[];
export function countWhere<T>(array: T[], predicate: (x: T) => boolean): number {
var count = 0;
if (array) {
result = [];
for (var i = 0, len = array.length; i < len; i++) {
if (predicate(array[i])) {
count++;
}
}
}
return count;
}
export function filter<T>(array: T[], f: (x: T) => boolean): T[] {
if (array) {
var result: T[] = [];
for (var i = 0, len = array.length; i < len; i++) {
var item = array[i];
if (f(item)) {
@@ -56,11 +87,9 @@ module ts {
}
export function map<T, U>(array: T[], f: (x: T) => U): U[] {
var result: U[];
if (array) {
result = [];
var len = array.length;
for (var i = 0; i < len; i++) {
var result: U[] = [];
for (var i = 0, len = array.length; i < len; i++) {
result.push(f(array[i]));
}
}
@@ -70,9 +99,21 @@ module ts {
export function concatenate<T>(array1: T[], array2: T[]): T[] {
if (!array2 || !array2.length) return array1;
if (!array1 || !array1.length) return array2;
return array1.concat(array2);
}
export function deduplicate<T>(array: T[]): T[] {
if (array) {
var result: T[] = [];
for (var i = 0, len = array.length; i < len; i++) {
var item = array[i];
if (!contains(result, item)) result.push(item);
}
}
return result;
}
export function sum(array: any[], prop: string): number {
var result = 0;
for (var i = 0; i < array.length; i++) {
@@ -81,6 +122,17 @@ module ts {
return result;
}
/**
* Returns the last element of an array if non-empty, undefined otherwise.
*/
export function lastOrUndefined<T>(array: T[]): T {
if (array.length === 0) {
return undefined;
}
return array[array.length - 1];
}
export function binarySearch(array: number[], value: number): number {
var low = 0;
var high = array.length - 1;
@@ -189,15 +241,16 @@ module ts {
export var localizedDiagnosticMessages: Map<string> = undefined;
export function getLocaleSpecificMessage(message: string) {
if (ts.localizedDiagnosticMessages) {
message = localizedDiagnosticMessages[message];
}
return message;
return localizedDiagnosticMessages && localizedDiagnosticMessages[message]
? localizedDiagnosticMessages[message]
: message;
}
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage, ...args: any[]): Diagnostic;
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage): Diagnostic {
Debug.assert(start >= 0, "start must be non-negative, is " + start);
Debug.assert(length >= 0, "length must be non-negative, is " + length);
var text = getLocaleSpecificMessage(message.key);
if (arguments.length > 4) {
@@ -205,13 +258,14 @@ module ts {
}
return {
file: file,
start: start,
length: length,
file,
start,
length,
messageText: text,
category: message.category,
code: message.code
code: message.code,
isEarly: message.isEarly
};
}
@@ -230,7 +284,8 @@ module ts {
messageText: text,
category: message.category,
code: message.code
code: message.code,
isEarly: message.isEarly
};
}
@@ -251,7 +306,16 @@ module ts {
};
}
export function concatenateDiagnosticMessageChains(headChain: DiagnosticMessageChain, tailChain: DiagnosticMessageChain): DiagnosticMessageChain {
Debug.assert(!headChain.next);
headChain.next = tailChain;
return headChain;
}
export function flattenDiagnosticChain(file: SourceFile, start: number, length: number, diagnosticChain: DiagnosticMessageChain, newLine: string): Diagnostic {
Debug.assert(start >= 0, "start must be non-negative, is " + start);
Debug.assert(length >= 0, "length must be non-negative, is " + length);
var code = diagnosticChain.code;
var category = diagnosticChain.category;
var messageText = "";
@@ -271,20 +335,20 @@ module ts {
}
return {
file: file,
start: start,
length: length,
code: code,
category: category,
messageText: messageText
file,
start,
length,
code,
category,
messageText
};
}
export function compareValues<T>(a: T, b: T): number {
if (a === b) return 0;
if (a === undefined) return -1;
if (b === undefined) return 1;
return a < b ? -1 : 1;
export function compareValues<T>(a: T, b: T): Comparison {
if (a === b) return Comparison.EqualTo;
if (a === undefined) return Comparison.LessThan;
if (b === undefined) return Comparison.GreaterThan;
return a < b ? Comparison.LessThan : Comparison.GreaterThan;
}
function getDiagnosticFilename(diagnostic: Diagnostic): string {
@@ -309,7 +373,7 @@ module ts {
var previousDiagnostic = diagnostics[0];
for (var i = 1; i < diagnostics.length; i++) {
var currentDiagnostic = diagnostics[i];
var isDupe = compareDiagnostics(currentDiagnostic, previousDiagnostic) === 0;
var isDupe = compareDiagnostics(currentDiagnostic, previousDiagnostic) === Comparison.EqualTo;
if (!isDupe) {
newDiagnostics.push(currentDiagnostic);
previousDiagnostic = currentDiagnostic;
@@ -395,7 +459,11 @@ module ts {
return normalizedPathComponents(path, rootLength);
}
export function getNormalizedPathFromPathCompoments(pathComponents: string[]) {
export function getNormalizedAbsolutePath(filename: string, currentDirectory: string) {
return getNormalizedPathFromPathComponents(getNormalizedPathComponents(filename, currentDirectory));
}
export function getNormalizedPathFromPathComponents(pathComponents: string[]) {
if (pathComponents && pathComponents.length) {
return pathComponents[0] + pathComponents.slice(1).join(directorySeparator);
}
@@ -452,18 +520,18 @@ module ts {
}
}
export function getRelativePathToDirectoryOrUrl(directoryPathOrUrl: string, relativeOrAbsolutePath: string, currentDirectory: string, isAbsolutePathAnUrl: boolean) {
export function getRelativePathToDirectoryOrUrl(directoryPathOrUrl: string, relativeOrAbsolutePath: string, currentDirectory: string, getCanonicalFileName: (fileName: string) => string, isAbsolutePathAnUrl: boolean) {
var pathComponents = getNormalizedPathOrUrlComponents(relativeOrAbsolutePath, currentDirectory);
var directoryComponents = getNormalizedPathOrUrlComponents(directoryPathOrUrl, currentDirectory);
if (directoryComponents.length > 1 && directoryComponents[directoryComponents.length - 1] === "") {
// If the directory path given was of type test/cases/ then we really need components of directry to be only till its name
// If the directory path given was of type test/cases/ then we really need components of directory to be only till its name
// that is ["test", "cases", ""] needs to be actually ["test", "cases"]
directoryComponents.length--;
}
// Find the component that differs
for (var joinStartIndex = 0; joinStartIndex < pathComponents.length && joinStartIndex < directoryComponents.length; joinStartIndex++) {
if (directoryComponents[joinStartIndex] !== pathComponents[joinStartIndex]) {
if (getCanonicalFileName(directoryComponents[joinStartIndex]) !== getCanonicalFileName(pathComponents[joinStartIndex])) {
break;
}
}
@@ -482,7 +550,7 @@ module ts {
}
// Cant find the relative path, get the absolute path
var absolutePath = getNormalizedPathFromPathCompoments(pathComponents);
var absolutePath = getNormalizedPathFromPathComponents(pathComponents);
if (isAbsolutePathAnUrl && isRootedDiskPath(absolutePath)) {
absolutePath = "file:///" + absolutePath;
}
@@ -509,6 +577,43 @@ module ts {
return pathLen > extLen && path.substr(pathLen - extLen, extLen) === extension;
}
var supportedExtensions = [".d.ts", ".ts", ".js"];
export function removeFileExtension(path: string): string {
for (var i = 0; i < supportedExtensions.length; i++) {
var ext = supportedExtensions[i];
if (fileExtensionIs(path, ext)) {
return path.substr(0, path.length - ext.length);
}
}
return path;
}
var escapedCharsRegExp = /[\t\v\f\b\0\r\n\"\\\u2028\u2029\u0085]/g;
var escapedCharsMap: Map<string> = {
"\t": "\\t",
"\v": "\\v",
"\f": "\\f",
"\b": "\\b",
"\0": "\\0",
"\r": "\\r",
"\n": "\\n",
"\"": "\\\"",
"\u2028": "\\u2028", // lineSeparator
"\u2029": "\\u2029", // paragraphSeparator
"\u0085": "\\u0085" // nextLine
};
/** NOTE: This *does not* support the full escape characters, it only supports the subset that can be used in file names
* or string literals. If the information encoded in the map changes, this needs to be revisited. */
export function escapeString(s: string): string {
return escapedCharsRegExp.test(s) ? s.replace(escapedCharsRegExp, c => {
return escapedCharsMap[c] || c;
}) : s;
}
export interface ObjectAllocator {
getNodeConstructor(kind: SyntaxKind): new () => Node;
getSymbolConstructor(): new (flags: SymbolFlags, name: string) => Symbol;
@@ -547,7 +652,7 @@ module ts {
getSignatureConstructor: () => <any>Signature
}
export enum AssertionLevel {
export const enum AssertionLevel {
None = 0,
Normal = 1,
Aggressive = 2,
@@ -561,7 +666,7 @@ module ts {
return currentAssertionLevel >= level;
}
export function assert(expression: any, message?: string, verboseDebugInfo?: () => string): void {
export function assert(expression: boolean, message?: string, verboseDebugInfo?: () => string): void {
if (!expression) {
var verboseDebugString = "";
if (verboseDebugInfo) {
@@ -5,6 +5,7 @@ module ts {
Unterminated_string_literal: { code: 1002, category: DiagnosticCategory.Error, key: "Unterminated string literal." },
Identifier_expected: { code: 1003, category: DiagnosticCategory.Error, key: "Identifier expected." },
_0_expected: { code: 1005, category: DiagnosticCategory.Error, key: "'{0}' expected." },
A_file_cannot_have_a_reference_to_itself: { code: 1006, category: DiagnosticCategory.Error, key: "A file cannot have a reference to itself." },
Trailing_comma_not_allowed: { code: 1009, category: DiagnosticCategory.Error, key: "Trailing comma not allowed." },
Asterisk_Slash_expected: { code: 1010, category: DiagnosticCategory.Error, key: "'*/' expected." },
Unexpected_token: { code: 1012, category: DiagnosticCategory.Error, key: "Unexpected token." },
@@ -84,6 +85,7 @@ module ts {
An_object_literal_cannot_have_property_and_accessor_with_the_same_name: { code: 1119, category: DiagnosticCategory.Error, key: "An object literal cannot have property and accessor with the same name." },
An_export_assignment_cannot_have_modifiers: { code: 1120, category: DiagnosticCategory.Error, key: "An export assignment cannot have modifiers." },
Octal_literals_are_not_allowed_in_strict_mode: { code: 1121, category: DiagnosticCategory.Error, key: "Octal literals are not allowed in strict mode." },
A_tuple_type_element_list_cannot_be_empty: { code: 1122, category: DiagnosticCategory.Error, key: "A tuple type element list cannot be empty." },
Variable_declaration_list_cannot_be_empty: { code: 1123, category: DiagnosticCategory.Error, key: "Variable declaration list cannot be empty." },
Digit_expected: { code: 1124, category: DiagnosticCategory.Error, key: "Digit expected." },
Hexadecimal_digit_expected: { code: 1125, category: DiagnosticCategory.Error, key: "Hexadecimal digit expected." },
@@ -112,6 +114,18 @@ module ts {
Cannot_compile_external_modules_unless_the_module_flag_is_provided: { code: 1148, category: DiagnosticCategory.Error, key: "Cannot compile external modules unless the '--module' flag is provided." },
Filename_0_differs_from_already_included_filename_1_only_in_casing: { code: 1149, category: DiagnosticCategory.Error, key: "Filename '{0}' differs from already included filename '{1}' only in casing" },
new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead: { code: 1150, category: DiagnosticCategory.Error, key: "'new T[]' cannot be used to create an array. Use 'new Array<T>()' instead." },
var_let_or_const_expected: { code: 1152, category: DiagnosticCategory.Error, key: "'var', 'let' or 'const' expected." },
let_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher: { code: 1153, category: DiagnosticCategory.Error, key: "'let' declarations are only available when targeting ECMAScript 6 and higher." },
const_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher: { code: 1154, category: DiagnosticCategory.Error, key: "'const' declarations are only available when targeting ECMAScript 6 and higher." },
const_declarations_must_be_initialized: { code: 1155, category: DiagnosticCategory.Error, key: "'const' declarations must be initialized" },
const_declarations_can_only_be_declared_inside_a_block: { code: 1156, category: DiagnosticCategory.Error, key: "'const' declarations can only be declared inside a block." },
let_declarations_can_only_be_declared_inside_a_block: { code: 1157, category: DiagnosticCategory.Error, key: "'let' declarations can only be declared inside a block." },
Invalid_template_literal_expected: { code: 1158, category: DiagnosticCategory.Error, key: "Invalid template literal; expected '}'" },
Tagged_templates_are_only_available_when_targeting_ECMAScript_6_and_higher: { code: 1159, category: DiagnosticCategory.Error, key: "Tagged templates are only available when targeting ECMAScript 6 and higher." },
Unterminated_template_literal: { code: 1160, category: DiagnosticCategory.Error, key: "Unterminated template literal." },
Unterminated_regular_expression_literal: { code: 1161, category: DiagnosticCategory.Error, key: "Unterminated regular expression literal." },
An_object_member_cannot_be_declared_optional: { code: 1162, category: DiagnosticCategory.Error, key: "An object member cannot be declared optional." },
yield_expression_must_be_contained_within_a_generator_declaration: { code: 1163, category: DiagnosticCategory.Error, key: "'yield' expression must be contained_within a generator declaration." },
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." },
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },
@@ -132,17 +146,16 @@ module ts {
Global_type_0_must_have_1_type_parameter_s: { code: 2317, category: DiagnosticCategory.Error, key: "Global type '{0}' must have {1} type parameter(s)." },
Cannot_find_global_type_0: { code: 2318, category: DiagnosticCategory.Error, key: "Cannot find global type '{0}'." },
Named_properties_0_of_types_1_and_2_are_not_identical: { code: 2319, category: DiagnosticCategory.Error, key: "Named properties '{0}' of types '{1}' and '{2}' are not identical." },
Interface_0_cannot_simultaneously_extend_types_1_and_2_Colon: { code: 2320, category: DiagnosticCategory.Error, key: "Interface '{0}' cannot simultaneously extend types '{1}' and '{2}':" },
Interface_0_cannot_simultaneously_extend_types_1_and_2: { code: 2320, category: DiagnosticCategory.Error, key: "Interface '{0}' cannot simultaneously extend types '{1}' and '{2}'." },
Excessive_stack_depth_comparing_types_0_and_1: { code: 2321, category: DiagnosticCategory.Error, key: "Excessive stack depth comparing types '{0}' and '{1}'." },
Type_0_is_not_assignable_to_type_1_Colon: { code: 2322, category: DiagnosticCategory.Error, key: "Type '{0}' is not assignable to type '{1}':" },
Type_0_is_not_assignable_to_type_1: { code: 2323, category: DiagnosticCategory.Error, key: "Type '{0}' is not assignable to type '{1}'." },
Type_0_is_not_assignable_to_type_1: { code: 2322, category: DiagnosticCategory.Error, key: "Type '{0}' is not assignable to type '{1}'." },
Property_0_is_missing_in_type_1: { code: 2324, category: DiagnosticCategory.Error, key: "Property '{0}' is missing in type '{1}'." },
Private_property_0_cannot_be_reimplemented: { code: 2325, category: DiagnosticCategory.Error, key: "Private property '{0}' cannot be reimplemented." },
Types_of_property_0_are_incompatible_Colon: { code: 2326, category: DiagnosticCategory.Error, key: "Types of property '{0}' are incompatible:" },
Required_property_0_cannot_be_reimplemented_with_optional_property_in_1: { code: 2327, category: DiagnosticCategory.Error, key: "Required property '{0}' cannot be reimplemented with optional property in '{1}'." },
Types_of_parameters_0_and_1_are_incompatible_Colon: { code: 2328, category: DiagnosticCategory.Error, key: "Types of parameters '{0}' and '{1}' are incompatible:" },
Property_0_is_private_in_type_1_but_not_in_type_2: { code: 2325, category: DiagnosticCategory.Error, key: "Property '{0}' is private in type '{1}' but not in type '{2}'." },
Types_of_property_0_are_incompatible: { code: 2326, category: DiagnosticCategory.Error, key: "Types of property '{0}' are incompatible." },
Property_0_is_optional_in_type_1_but_required_in_type_2: { code: 2327, category: DiagnosticCategory.Error, key: "Property '{0}' is optional in type '{1}' but required in type '{2}'." },
Types_of_parameters_0_and_1_are_incompatible: { code: 2328, category: DiagnosticCategory.Error, key: "Types of parameters '{0}' and '{1}' are incompatible." },
Index_signature_is_missing_in_type_0: { code: 2329, category: DiagnosticCategory.Error, key: "Index signature is missing in type '{0}'." },
Index_signatures_are_incompatible_Colon: { code: 2330, category: DiagnosticCategory.Error, key: "Index signatures are incompatible:" },
Index_signatures_are_incompatible: { code: 2330, category: DiagnosticCategory.Error, key: "Index signatures are incompatible." },
this_cannot_be_referenced_in_a_module_body: { code: 2331, category: DiagnosticCategory.Error, key: "'this' cannot be referenced in a module body." },
this_cannot_be_referenced_in_current_location: { code: 2332, category: DiagnosticCategory.Error, key: "'this' cannot be referenced in current location." },
this_cannot_be_referenced_in_constructor_arguments: { code: 2333, category: DiagnosticCategory.Error, key: "'this' cannot be referenced in constructor arguments." },
@@ -152,10 +165,9 @@ module ts {
Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors: { code: 2337, category: DiagnosticCategory.Error, key: "Super calls are not permitted outside constructors or in nested functions inside constructors" },
super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class: { code: 2338, category: DiagnosticCategory.Error, key: "'super' property access is permitted only in a constructor, member function, or member accessor of a derived class" },
Property_0_does_not_exist_on_type_1: { code: 2339, category: DiagnosticCategory.Error, key: "Property '{0}' does not exist on type '{1}'." },
Only_public_methods_of_the_base_class_are_accessible_via_the_super_keyword: { code: 2340, category: DiagnosticCategory.Error, key: "Only public methods of the base class are accessible via the 'super' keyword" },
Property_0_is_inaccessible: { code: 2341, category: DiagnosticCategory.Error, key: "Property '{0}' is inaccessible." },
Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword: { code: 2340, category: DiagnosticCategory.Error, key: "Only public and protected methods of the base class are accessible via the 'super' keyword" },
Property_0_is_private_and_only_accessible_within_class_1: { code: 2341, category: DiagnosticCategory.Error, key: "Property '{0}' is private and only accessible within class '{1}'." },
An_index_expression_argument_must_be_of_type_string_number_or_any: { code: 2342, category: DiagnosticCategory.Error, key: "An index expression argument must be of type 'string', 'number', or 'any'." },
Type_0_does_not_satisfy_the_constraint_1_Colon: { code: 2343, category: DiagnosticCategory.Error, key: "Type '{0}' does not satisfy the constraint '{1}':" },
Type_0_does_not_satisfy_the_constraint_1: { code: 2344, category: DiagnosticCategory.Error, key: "Type '{0}' does not satisfy the constraint '{1}'." },
Argument_of_type_0_is_not_assignable_to_parameter_of_type_1: { code: 2345, category: DiagnosticCategory.Error, key: "Argument of type '{0}' is not assignable to parameter of type '{1}'." },
Supplied_parameters_do_not_match_any_signature_of_call_target: { code: 2346, category: DiagnosticCategory.Error, key: "Supplied parameters do not match any signature of call target." },
@@ -165,7 +177,6 @@ module ts {
Only_a_void_function_can_be_called_with_the_new_keyword: { code: 2350, category: DiagnosticCategory.Error, key: "Only a void function can be called with the 'new' keyword." },
Cannot_use_new_with_an_expression_whose_type_lacks_a_call_or_construct_signature: { code: 2351, category: DiagnosticCategory.Error, key: "Cannot use 'new' with an expression whose type lacks a call or construct signature." },
Neither_type_0_nor_type_1_is_assignable_to_the_other: { code: 2352, category: DiagnosticCategory.Error, key: "Neither type '{0}' nor type '{1}' is assignable to the other." },
Neither_type_0_nor_type_1_is_assignable_to_the_other_Colon: { code: 2353, category: DiagnosticCategory.Error, key: "Neither type '{0}' nor type '{1}' is assignable to the other:" },
No_best_common_type_exists_among_return_expressions: { code: 2354, category: DiagnosticCategory.Error, key: "No best common type exists among return expressions." },
A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value_or_consist_of_a_single_throw_statement: { code: 2355, category: DiagnosticCategory.Error, key: "A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement." },
An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type: { code: 2356, category: DiagnosticCategory.Error, key: "An arithmetic operand must be of type 'any', 'number' or an enum type." },
@@ -178,8 +189,6 @@ module ts {
The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type: { code: 2363, category: DiagnosticCategory.Error, key: "The right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type." },
Invalid_left_hand_side_of_assignment_expression: { code: 2364, category: DiagnosticCategory.Error, key: "Invalid left-hand side of assignment expression." },
Operator_0_cannot_be_applied_to_types_1_and_2: { code: 2365, category: DiagnosticCategory.Error, key: "Operator '{0}' cannot be applied to types '{1}' and '{2}'." },
No_best_common_type_exists_between_0_1_and_2: { code: 2366, category: DiagnosticCategory.Error, key: "No best common type exists between '{0}', '{1}', and '{2}'." },
No_best_common_type_exists_between_0_and_1: { code: 2367, category: DiagnosticCategory.Error, key: "No best common type exists between '{0}' and '{1}'." },
Type_parameter_name_cannot_be_0: { code: 2368, category: DiagnosticCategory.Error, key: "Type parameter name cannot be '{0}'" },
A_parameter_property_is_only_allowed_in_a_constructor_implementation: { code: 2369, category: DiagnosticCategory.Error, key: "A parameter property is only allowed in a constructor implementation." },
A_rest_parameter_must_be_of_an_array_type: { code: 2370, category: DiagnosticCategory.Error, key: "A rest parameter must be of an array type." },
@@ -197,7 +206,7 @@ module ts {
Specialized_overload_signature_is_not_assignable_to_any_non_specialized_signature: { code: 2382, category: DiagnosticCategory.Error, key: "Specialized overload signature is not assignable to any non-specialized signature." },
Overload_signatures_must_all_be_exported_or_not_exported: { code: 2383, category: DiagnosticCategory.Error, key: "Overload signatures must all be exported or not exported." },
Overload_signatures_must_all_be_ambient_or_non_ambient: { code: 2384, category: DiagnosticCategory.Error, key: "Overload signatures must all be ambient or non-ambient." },
Overload_signatures_must_all_be_public_or_private: { code: 2385, category: DiagnosticCategory.Error, key: "Overload signatures must all be public or private." },
Overload_signatures_must_all_be_public_private_or_protected: { code: 2385, category: DiagnosticCategory.Error, key: "Overload signatures must all be public, private or protected." },
Overload_signatures_must_all_be_optional_or_required: { code: 2386, category: DiagnosticCategory.Error, key: "Overload signatures must all be optional or required." },
Function_overload_must_be_static: { code: 2387, category: DiagnosticCategory.Error, key: "Function overload must be static." },
Function_overload_must_not_be_static: { code: 2388, category: DiagnosticCategory.Error, key: "Function overload must not be static." },
@@ -228,12 +237,9 @@ module ts {
Numeric_index_type_0_is_not_assignable_to_string_index_type_1: { code: 2413, category: DiagnosticCategory.Error, key: "Numeric index type '{0}' is not assignable to string index type '{1}'." },
Class_name_cannot_be_0: { code: 2414, category: DiagnosticCategory.Error, key: "Class name cannot be '{0}'" },
Class_0_incorrectly_extends_base_class_1: { code: 2415, category: DiagnosticCategory.Error, key: "Class '{0}' incorrectly extends base class '{1}'." },
Class_0_incorrectly_extends_base_class_1_Colon: { code: 2416, category: DiagnosticCategory.Error, key: "Class '{0}' incorrectly extends base class '{1}':" },
Class_static_side_0_incorrectly_extends_base_class_static_side_1: { code: 2417, category: DiagnosticCategory.Error, key: "Class static side '{0}' incorrectly extends base class static side '{1}'." },
Class_static_side_0_incorrectly_extends_base_class_static_side_1_Colon: { code: 2418, category: DiagnosticCategory.Error, key: "Class static side '{0}' incorrectly extends base class static side '{1}':" },
Type_name_0_in_extends_clause_does_not_reference_constructor_function_for_0: { code: 2419, category: DiagnosticCategory.Error, key: "Type name '{0}' in extends clause does not reference constructor function for '{0}'." },
Class_0_incorrectly_implements_interface_1: { code: 2420, category: DiagnosticCategory.Error, key: "Class '{0}' incorrectly implements interface '{1}'." },
Class_0_incorrectly_implements_interface_1_Colon: { code: 2421, category: DiagnosticCategory.Error, key: "Class '{0}' incorrectly implements interface '{1}':" },
A_class_may_only_implement_another_class_or_interface: { code: 2422, category: DiagnosticCategory.Error, key: "A class may only implement another class or interface." },
Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor: { code: 2423, category: DiagnosticCategory.Error, key: "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member accessor." },
Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_property: { code: 2424, category: DiagnosticCategory.Error, key: "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member property." },
@@ -241,7 +247,6 @@ module ts {
Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function: { code: 2426, category: DiagnosticCategory.Error, key: "Class '{0}' defines instance member accessor '{1}', but extended class '{2}' defines it as instance member function." },
Interface_name_cannot_be_0: { code: 2427, category: DiagnosticCategory.Error, key: "Interface name cannot be '{0}'" },
All_declarations_of_an_interface_must_have_identical_type_parameters: { code: 2428, category: DiagnosticCategory.Error, key: "All declarations of an interface must have identical type parameters." },
Interface_0_incorrectly_extends_interface_1_Colon: { code: 2429, category: DiagnosticCategory.Error, key: "Interface '{0}' incorrectly extends interface '{1}':" },
Interface_0_incorrectly_extends_interface_1: { code: 2430, category: DiagnosticCategory.Error, key: "Interface '{0}' incorrectly extends interface '{1}'." },
Enum_name_cannot_be_0: { code: 2431, category: DiagnosticCategory.Error, key: "Enum name cannot be '{0}'" },
In_an_enum_with_multiple_declarations_only_one_declaration_can_omit_an_initializer_for_its_first_enum_element: { code: 2432, category: DiagnosticCategory.Error, key: "In an enum with multiple declarations, only one declaration can omit an initializer for its first enum element." },
@@ -254,28 +259,33 @@ module ts {
Import_declaration_in_an_ambient_external_module_declaration_cannot_reference_external_module_through_relative_external_module_name: { code: 2439, category: DiagnosticCategory.Error, key: "Import declaration in an ambient external module declaration cannot reference external module through relative external module name." },
Import_declaration_conflicts_with_local_declaration_of_0: { code: 2440, category: DiagnosticCategory.Error, key: "Import declaration conflicts with local declaration of '{0}'" },
Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_an_external_module: { code: 2441, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'. Compiler reserves name '{1}' in top level scope of an external module." },
Types_have_separate_declarations_of_a_private_property_0: { code: 2442, category: DiagnosticCategory.Error, key: "Types have separate declarations of a private property '{0}'." },
Property_0_is_protected_but_type_1_is_not_a_class_derived_from_2: { code: 2443, category: DiagnosticCategory.Error, key: "Property '{0}' is protected but type '{1}' is not a class derived from '{2}'." },
Property_0_is_protected_in_type_1_but_public_in_type_2: { code: 2444, category: DiagnosticCategory.Error, key: "Property '{0}' is protected in type '{1}' but public in type '{2}'." },
Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses: { code: 2445, category: DiagnosticCategory.Error, key: "Property '{0}' is protected and only accessible within class '{1}' and its subclasses." },
Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1: { code: 2446, category: DiagnosticCategory.Error, key: "Property '{0}' is protected and only accessible through an instance of class '{1}'." },
The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead: { code: 2447, category: DiagnosticCategory.Error, key: "The '{0}' operator is not allowed for boolean types. Consider using '{1}' instead." },
Block_scoped_variable_0_used_before_its_declaration: { code: 2448, category: DiagnosticCategory.Error, key: "Block-scoped variable '{0}' used before its declaration.", isEarly: true },
The_operand_of_an_increment_or_decrement_operator_cannot_be_a_constant: { code: 2449, category: DiagnosticCategory.Error, key: "The operand of an increment or decrement operator cannot be a constant.", isEarly: true },
Left_hand_side_of_assignment_expression_cannot_be_a_constant: { code: 2450, category: DiagnosticCategory.Error, key: "Left-hand side of assignment expression cannot be a constant.", isEarly: true },
Cannot_redeclare_block_scoped_variable_0: { code: 2451, category: DiagnosticCategory.Error, key: "Cannot redeclare block-scoped variable '{0}'.", isEarly: true },
An_enum_member_cannot_have_a_numeric_name: { code: 2452, category: DiagnosticCategory.Error, key: "An enum member cannot have a numeric name." },
The_type_argument_for_type_parameter_0_cannot_be_inferred_from_the_usage_Consider_specifying_the_type_arguments_explicitly: { code: 2453, category: DiagnosticCategory.Error, key: "The type argument for type parameter '{0}' cannot be inferred from the usage. Consider specifying the type arguments explicitly." },
Type_argument_candidate_1_is_not_a_valid_type_argument_because_it_is_not_a_supertype_of_candidate_0: { code: 2455, category: DiagnosticCategory.Error, key: "Type argument candidate '{1}' is not a valid type argument because it is not a supertype of candidate '{0}'." },
Type_alias_0_circularly_references_itself: { code: 2456, category: DiagnosticCategory.Error, key: "Type alias '{0}' circularly references itself." },
Type_alias_name_cannot_be_0: { code: 2457, category: DiagnosticCategory.Error, key: "Type alias name cannot be '{0}'" },
An_AMD_module_cannot_have_multiple_name_assignments: { code: 2458, category: DiagnosticCategory.Error, key: "An AMD module cannot have multiple name assignments." },
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
Type_parameter_0_of_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4001, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using name '{1}' from private module '{2}'." },
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },
Type_parameter_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2: { code: 4003, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using name '{1}' from private module '{2}'." },
Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." },
Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2: { code: 4005, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of constructor signature from exported interface has or is using name '{1}' from private module '{2}'." },
Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1: { code: 4006, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of constructor signature from exported interface has or is using private name '{1}'." },
Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2: { code: 4007, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of call signature from exported interface has or is using name '{1}' from private module '{2}'." },
Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1: { code: 4008, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of call signature from exported interface has or is using private name '{1}'." },
Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4009, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of public static method from exported class has or is using name '{1}' from private module '{2}'." },
Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1: { code: 4010, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of public static method from exported class has or is using private name '{1}'." },
Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4011, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of public method from exported class has or is using name '{1}' from private module '{2}'." },
Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1: { code: 4012, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of public method from exported class has or is using private name '{1}'." },
Type_parameter_0_of_method_from_exported_interface_has_or_is_using_name_1_from_private_module_2: { code: 4013, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of method from exported interface has or is using name '{1}' from private module '{2}'." },
Type_parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1: { code: 4014, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of method from exported interface has or is using private name '{1}'." },
Type_parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2: { code: 4015, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported function has or is using name '{1}' from private module '{2}'." },
Type_parameter_0_of_exported_function_has_or_is_using_private_name_1: { code: 4016, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported function has or is using private name '{1}'." },
Implements_clause_of_exported_class_0_has_or_is_using_name_1_from_private_module_2: { code: 4017, category: DiagnosticCategory.Error, key: "Implements clause of exported class '{0}' has or is using name '{1}' from private module '{2}'." },
Extends_clause_of_exported_class_0_has_or_is_using_name_1_from_private_module_2: { code: 4018, category: DiagnosticCategory.Error, key: "Extends clause of exported class '{0}' has or is using name '{1}' from private module '{2}'." },
Implements_clause_of_exported_class_0_has_or_is_using_private_name_1: { code: 4019, category: DiagnosticCategory.Error, key: "Implements clause of exported class '{0}' has or is using private name '{1}'." },
Extends_clause_of_exported_class_0_has_or_is_using_private_name_1: { code: 4020, category: DiagnosticCategory.Error, key: "Extends clause of exported class '{0}' has or is using private name '{1}'." },
Extends_clause_of_exported_interface_0_has_or_is_using_name_1_from_private_module_2: { code: 4021, category: DiagnosticCategory.Error, key: "Extends clause of exported interface '{0}' has or is using name '{1}' from private module '{2}'." },
Extends_clause_of_exported_interface_0_has_or_is_using_private_name_1: { code: 4022, category: DiagnosticCategory.Error, key: "Extends clause of exported interface '{0}' has or is using private name '{1}'." },
Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4023, category: DiagnosticCategory.Error, key: "Exported variable '{0}' has or is using name '{1}' from external module {2} but cannot be named." },
Exported_variable_0_has_or_is_using_name_1_from_private_module_2: { code: 4024, category: DiagnosticCategory.Error, key: "Exported variable '{0}' has or is using name '{1}' from private module '{2}'." },
@@ -333,6 +343,13 @@ module ts {
Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4076, category: DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using name '{1}' from external module {2} but cannot be named." },
Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2: { code: 4077, category: DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using name '{1}' from private module '{2}'." },
Parameter_0_of_exported_function_has_or_is_using_private_name_1: { code: 4078, category: DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using private name '{1}'." },
Exported_type_alias_0_has_or_is_using_private_name_1: { code: 4081, category: DiagnosticCategory.Error, key: "Exported type alias '{0}' has or is using private name '{1}'." },
Enum_declarations_must_all_be_const_or_non_const: { code: 4082, category: DiagnosticCategory.Error, key: "Enum declarations must all be const or non-const." },
In_const_enum_declarations_member_initializer_must_be_constant_expression: { code: 4083, category: DiagnosticCategory.Error, key: "In 'const' enum declarations member initializer must be constant expression.", isEarly: true },
const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment: { code: 4084, category: DiagnosticCategory.Error, key: "'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment." },
Index_expression_arguments_in_const_enums_must_be_of_type_string: { code: 4085, category: DiagnosticCategory.Error, key: "Index expression arguments in 'const' enums must be of type 'string'." },
const_enum_member_initializer_was_evaluated_to_a_non_finite_value: { code: 4086, category: DiagnosticCategory.Error, key: "'const' enum member initializer was evaluated to a non-finite value." },
const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN: { code: 4087, category: DiagnosticCategory.Error, key: "'const' enum member initializer was evaluated to disallowed value 'NaN'." },
The_current_host_does_not_support_the_0_option: { code: 5001, category: DiagnosticCategory.Error, key: "The current host does not support the '{0}' option." },
Cannot_find_the_common_subdirectory_path_for_the_input_files: { code: 5009, category: DiagnosticCategory.Error, key: "Cannot find the common subdirectory path for the input files." },
Cannot_read_file_0_Colon_1: { code: 5012, category: DiagnosticCategory.Error, key: "Cannot read file '{0}': {1}" },
@@ -347,8 +364,10 @@ module ts {
Specifies_the_location_where_debugger_should_locate_TypeScript_files_instead_of_source_locations: { code: 6004, category: DiagnosticCategory.Message, key: "Specifies the location where debugger should locate TypeScript files instead of source locations." },
Watch_input_files: { code: 6005, category: DiagnosticCategory.Message, key: "Watch input files." },
Redirect_output_structure_to_the_directory: { code: 6006, category: DiagnosticCategory.Message, key: "Redirect output structure to the directory." },
Do_not_erase_const_enum_declarations_in_generated_code: { code: 6007, category: DiagnosticCategory.Message, key: "Do not erase const enum declarations in generated code." },
Do_not_emit_outputs_if_any_type_checking_errors_were_reported: { code: 6008, category: DiagnosticCategory.Message, key: "Do not emit outputs if any type checking errors were reported." },
Do_not_emit_comments_to_output: { code: 6009, category: DiagnosticCategory.Message, key: "Do not emit comments to output." },
Specify_ECMAScript_target_version_Colon_ES3_default_or_ES5: { code: 6015, category: DiagnosticCategory.Message, key: "Specify ECMAScript target version: 'ES3' (default), or 'ES5'" },
Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES6_experimental: { code: 6015, category: DiagnosticCategory.Message, key: "Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES6' (experimental)" },
Specify_module_code_generation_Colon_commonjs_or_amd: { code: 6016, category: DiagnosticCategory.Message, key: "Specify module code generation: 'commonjs' or 'amd'" },
Print_this_message: { code: 6017, category: DiagnosticCategory.Message, key: "Print this message." },
Print_the_compiler_s_version: { code: 6019, category: DiagnosticCategory.Message, key: "Print the compiler's version." },
@@ -370,7 +389,7 @@ module ts {
Compiler_option_0_expects_an_argument: { code: 6044, category: DiagnosticCategory.Error, key: "Compiler option '{0}' expects an argument." },
Unterminated_quoted_string_in_response_file_0: { code: 6045, category: DiagnosticCategory.Error, key: "Unterminated quoted string in response file '{0}'." },
Argument_for_module_option_must_be_commonjs_or_amd: { code: 6046, category: DiagnosticCategory.Error, key: "Argument for '--module' option must be 'commonjs' or 'amd'." },
Argument_for_target_option_must_be_es3_or_es5: { code: 6047, category: DiagnosticCategory.Error, key: "Argument for '--target' option must be 'es3' or 'es5'." },
Argument_for_target_option_must_be_es3_es5_or_es6: { code: 6047, category: DiagnosticCategory.Error, key: "Argument for '--target' option must be 'es3', 'es5', or 'es6'." },
Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1: { code: 6048, category: DiagnosticCategory.Error, key: "Locale must be of the form <language> or <language>-<territory>. For example '{0}' or '{1}'." },
Unsupported_locale_0: { code: 6049, category: DiagnosticCategory.Error, key: "Unsupported locale '{0}'." },
Unable_to_open_file_0: { code: 6050, category: DiagnosticCategory.Error, key: "Unable to open file '{0}'." },
@@ -390,6 +409,10 @@ module ts {
Object_literal_s_property_0_implicitly_has_an_1_type: { code: 7018, category: DiagnosticCategory.Error, key: "Object literal's property '{0}' implicitly has an '{1}' type." },
Rest_parameter_0_implicitly_has_an_any_type: { code: 7019, category: DiagnosticCategory.Error, key: "Rest parameter '{0}' implicitly has an 'any[]' type." },
Call_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: { code: 7020, category: DiagnosticCategory.Error, key: "Call signature, which lacks return-type annotation, implicitly has an 'any' return type." },
_0_implicitly_has_type_any_because_it_is_referenced_directly_or_indirectly_in_its_own_type_annotation: { code: 7021, category: DiagnosticCategory.Error, key: "'{0}' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation." },
_0_implicitly_has_type_any_because_it_is_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer: { code: 7022, category: DiagnosticCategory.Error, key: "'{0}' implicitly has type 'any' because it is does not have a type annotation and is referenced directly or indirectly in its own initializer." },
_0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions: { code: 7023, category: DiagnosticCategory.Error, key: "'{0}' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions." },
Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions: { code: 7024, category: DiagnosticCategory.Error, key: "Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions." },
You_cannot_rename_this_element: { code: 8000, category: DiagnosticCategory.Error, key: "You cannot rename this element." },
};
}
+193 -99
View File
@@ -11,6 +11,10 @@
"category": "Error",
"code": 1005
},
"A file cannot have a reference to itself.": {
"category": "Error",
"code": 1006
},
"Trailing comma not allowed.": {
"category": "Error",
"code": 1009
@@ -183,7 +187,7 @@
"category": "Error",
"code": 1066
},
"Unexpected token. A constructor, method, accessor, or property was expected." : {
"Unexpected token. A constructor, method, accessor, or property was expected.": {
"category": "Error",
"code": 1068
},
@@ -327,6 +331,10 @@
"category": "Error",
"code": 1121
},
"A tuple type element list cannot be empty.": {
"category": "Error",
"code": 1122
},
"Variable declaration list cannot be empty.": {
"category": "Error",
"code": 1123
@@ -436,9 +444,57 @@
"code": 1149
},
"'new T[]' cannot be used to create an array. Use 'new Array<T>()' instead.": {
"category": "Error",
"code": 1150
},
"category": "Error",
"code": 1150
},
"'var', 'let' or 'const' expected.": {
"category": "Error",
"code": 1152
},
"'let' declarations are only available when targeting ECMAScript 6 and higher.": {
"category": "Error",
"code": 1153
},
"'const' declarations are only available when targeting ECMAScript 6 and higher.": {
"category": "Error",
"code": 1154
},
"'const' declarations must be initialized": {
"category": "Error",
"code": 1155
},
"'const' declarations can only be declared inside a block.": {
"category": "Error",
"code": 1156
},
"'let' declarations can only be declared inside a block.": {
"category": "Error",
"code": 1157
},
"Invalid template literal; expected '}'": {
"category": "Error",
"code": 1158
},
"Tagged templates are only available when targeting ECMAScript 6 and higher.": {
"category": "Error",
"code": 1159
},
"Unterminated template literal.": {
"category": "Error",
"code": 1160
},
"Unterminated regular expression literal.": {
"category": "Error",
"code": 1161
},
"An object member cannot be declared optional.": {
"category": "Error",
"code": 1162
},
"'yield' expression must be contained_within a generator declaration.": {
"category": "Error",
"code": 1163
},
"Duplicate identifier '{0}'.": {
"category": "Error",
@@ -520,7 +576,7 @@
"category": "Error",
"code": 2319
},
"Interface '{0}' cannot simultaneously extend types '{1}' and '{2}':": {
"Interface '{0}' cannot simultaneously extend types '{1}' and '{2}'.": {
"category": "Error",
"code": 2320
},
@@ -528,31 +584,27 @@
"category": "Error",
"code": 2321
},
"Type '{0}' is not assignable to type '{1}':": {
"category": "Error",
"code": 2322
},
"Type '{0}' is not assignable to type '{1}'.": {
"category": "Error",
"code": 2323
"code": 2322
},
"Property '{0}' is missing in type '{1}'.": {
"category": "Error",
"code": 2324
},
"Private property '{0}' cannot be reimplemented.": {
"Property '{0}' is private in type '{1}' but not in type '{2}'.": {
"category": "Error",
"code": 2325
},
"Types of property '{0}' are incompatible:": {
"Types of property '{0}' are incompatible.": {
"category": "Error",
"code": 2326
},
"Required property '{0}' cannot be reimplemented with optional property in '{1}'.": {
"Property '{0}' is optional in type '{1}' but required in type '{2}'.": {
"category": "Error",
"code": 2327
},
"Types of parameters '{0}' and '{1}' are incompatible:": {
"Types of parameters '{0}' and '{1}' are incompatible.": {
"category": "Error",
"code": 2328
},
@@ -560,7 +612,7 @@
"category": "Error",
"code": 2329
},
"Index signatures are incompatible:": {
"Index signatures are incompatible.": {
"category": "Error",
"code": 2330
},
@@ -600,11 +652,11 @@
"category": "Error",
"code": 2339
},
"Only public methods of the base class are accessible via the 'super' keyword": {
"Only public and protected methods of the base class are accessible via the 'super' keyword": {
"category": "Error",
"code": 2340
},
"Property '{0}' is inaccessible.": {
"Property '{0}' is private and only accessible within class '{1}'.": {
"category": "Error",
"code": 2341
},
@@ -612,10 +664,6 @@
"category": "Error",
"code": 2342
},
"Type '{0}' does not satisfy the constraint '{1}':": {
"category": "Error",
"code": 2343
},
"Type '{0}' does not satisfy the constraint '{1}'.": {
"category": "Error",
"code": 2344
@@ -652,10 +700,6 @@
"category": "Error",
"code": 2352
},
"Neither type '{0}' nor type '{1}' is assignable to the other:": {
"category": "Error",
"code": 2353
},
"No best common type exists among return expressions.": {
"category": "Error",
"code": 2354
@@ -704,14 +748,6 @@
"category": "Error",
"code": 2365
},
"No best common type exists between '{0}', '{1}', and '{2}'.": {
"category": "Error",
"code": 2366
},
"No best common type exists between '{0}' and '{1}'.": {
"category": "Error",
"code": 2367
},
"Type parameter name cannot be '{0}'": {
"category": "Error",
"code": 2368
@@ -780,7 +816,7 @@
"category": "Error",
"code": 2384
},
"Overload signatures must all be public or private.": {
"Overload signatures must all be public, private or protected.": {
"category": "Error",
"code": 2385
},
@@ -904,18 +940,10 @@
"category": "Error",
"code": 2415
},
"Class '{0}' incorrectly extends base class '{1}':": {
"category": "Error",
"code": 2416
},
"Class static side '{0}' incorrectly extends base class static side '{1}'.": {
"category": "Error",
"code": 2417
},
"Class static side '{0}' incorrectly extends base class static side '{1}':": {
"category": "Error",
"code": 2418
},
"Type name '{0}' in extends clause does not reference constructor function for '{0}'.": {
"category": "Error",
"code": 2419
@@ -924,10 +952,6 @@
"category": "Error",
"code": 2420
},
"Class '{0}' incorrectly implements interface '{1}':": {
"category": "Error",
"code": 2421
},
"A class may only implement another class or interface.": {
"category": "Error",
"code": 2422
@@ -956,10 +980,6 @@
"category": "Error",
"code": 2428
},
"Interface '{0}' incorrectly extends interface '{1}':": {
"category": "Error",
"code": 2429
},
"Interface '{0}' incorrectly extends interface '{1}'.": {
"category": "Error",
"code": 2430
@@ -1008,84 +1028,111 @@
"category": "Error",
"code": 2441
},
"Types have separate declarations of a private property '{0}'.": {
"category": "Error",
"code": 2442
},
"Property '{0}' is protected but type '{1}' is not a class derived from '{2}'.": {
"category": "Error",
"code": 2443
},
"Property '{0}' is protected in type '{1}' but public in type '{2}'.": {
"category": "Error",
"code": 2444
},
"Property '{0}' is protected and only accessible within class '{1}' and its subclasses.": {
"category": "Error",
"code": 2445
},
"Property '{0}' is protected and only accessible through an instance of class '{1}'.": {
"category": "Error",
"code": 2446
},
"The '{0}' operator is not allowed for boolean types. Consider using '{1}' instead.": {
"category": "Error",
"code": 2447
},
"Block-scoped variable '{0}' used before its declaration.": {
"category": "Error",
"code": 2448,
"isEarly": true
},
"The operand of an increment or decrement operator cannot be a constant.": {
"category": "Error",
"code": 2449,
"isEarly": true
},
"Left-hand side of assignment expression cannot be a constant.": {
"category": "Error",
"code": 2450,
"isEarly": true
},
"Cannot redeclare block-scoped variable '{0}'.": {
"category": "Error",
"code": 2451,
"isEarly": true
},
"An enum member cannot have a numeric name.": {
"category": "Error",
"code": 2452
},
"The type argument for type parameter '{0}' cannot be inferred from the usage. Consider specifying the type arguments explicitly.": {
"category": "Error",
"code": 2453
},
"Type argument candidate '{1}' is not a valid type argument because it is not a supertype of candidate '{0}'.": {
"category": "Error",
"code": 2455
},
"Type alias '{0}' circularly references itself.": {
"category": "Error",
"code": 2456
},
"Type alias name cannot be '{0}'": {
"category": "Error",
"code": 2457
},
"An AMD module cannot have multiple name assignments.": {
"category": "Error",
"code": 2458
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
"code": 4000
},
"Type parameter '{0}' of exported class has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4001
},
"Type parameter '{0}' of exported class has or is using private name '{1}'.": {
"category": "Error",
"code": 4002
},
"Type parameter '{0}' of exported interface has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4003
},
"Type parameter '{0}' of exported interface has or is using private name '{1}'.": {
"category": "Error",
"code": 4004
},
"Type parameter '{0}' of constructor signature from exported interface has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4005
},
"Type parameter '{0}' of constructor signature from exported interface has or is using private name '{1}'.": {
"category": "Error",
"code": 4006
},
"Type parameter '{0}' of call signature from exported interface has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4007
},
"Type parameter '{0}' of call signature from exported interface has or is using private name '{1}'.": {
"category": "Error",
"code": 4008
},
"Type parameter '{0}' of public static method from exported class has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4009
},
"Type parameter '{0}' of public static method from exported class has or is using private name '{1}'.": {
"category": "Error",
"code": 4010
},
"Type parameter '{0}' of public method from exported class has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4011
},
"Type parameter '{0}' of public method from exported class has or is using private name '{1}'.": {
"category": "Error",
"code": 4012
},
"Type parameter '{0}' of method from exported interface has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4013
},
"Type parameter '{0}' of method from exported interface has or is using private name '{1}'.": {
"category": "Error",
"code": 4014
},
"Type parameter '{0}' of exported function has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4015
},
"Type parameter '{0}' of exported function has or is using private name '{1}'.": {
"category": "Error",
"code": 4016
},
"Implements clause of exported class '{0}' has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4017
},
"Extends clause of exported class '{0}' has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4018
},
"Implements clause of exported class '{0}' has or is using private name '{1}'.": {
"category": "Error",
"code": 4019
@@ -1094,10 +1141,6 @@
"category": "Error",
"code": 4020
},
"Extends clause of exported interface '{0}' has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4021
},
"Extends clause of exported interface '{0}' has or is using private name '{1}'.": {
"category": "Error",
"code": 4022
@@ -1326,8 +1369,35 @@
"category": "Error",
"code": 4078
},
"Exported type alias '{0}' has or is using private name '{1}'.": {
"category": "Error",
"code": 4081
},
"Enum declarations must all be const or non-const.": {
"category": "Error",
"code": 4082
},
"In 'const' enum declarations member initializer must be constant expression.": {
"category": "Error",
"code": 4083,
"isEarly": true
},
"'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment.": {
"category": "Error",
"code": 4084
},
"Index expression arguments in 'const' enums must be of type 'string'.": {
"category": "Error",
"code": 4085
},
"'const' enum member initializer was evaluated to a non-finite value.": {
"category": "Error",
"code": 4086
},
"'const' enum member initializer was evaluated to disallowed value 'NaN'.": {
"category": "Error",
"code": 4087
},
"The current host does not support the '{0}' option.": {
"category": "Error",
"code": 5001
@@ -1384,11 +1454,19 @@
"category": "Message",
"code": 6006
},
"Do not erase const enum declarations in generated code.": {
"category": "Message",
"code": 6007
},
"Do not emit outputs if any type checking errors were reported.": {
"category": "Message",
"code": 6008
},
"Do not emit comments to output.": {
"category": "Message",
"code": 6009
},
"Specify ECMAScript target version: 'ES3' (default), or 'ES5'": {
"Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES6' (experimental)": {
"category": "Message",
"code": 6015
},
@@ -1476,7 +1554,7 @@
"category": "Error",
"code": 6046
},
"Argument for '--target' option must be 'es3' or 'es5'.": {
"Argument for '--target' option must be 'es3', 'es5', or 'es6'.": {
"category": "Error",
"code": 6047
},
@@ -1557,6 +1635,22 @@
"category": "Error",
"code": 7020
},
"'{0}' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation.": {
"category": "Error",
"code": 7021
},
"'{0}' implicitly has type 'any' because it is does not have a type annotation and is referenced directly or indirectly in its own initializer.": {
"category": "Error",
"code": 7022
},
"'{0}' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.": {
"category": "Error",
"code": 7023
},
"Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.": {
"category": "Error",
"code": 7024
},
"You cannot rename this element.": {
"category": "Error",
"code": 8000
+1888 -1298
View File
File diff suppressed because it is too large Load Diff
+2689 -1312
View File
File diff suppressed because it is too large Load Diff
+206 -88
View File
@@ -24,6 +24,7 @@ module ts {
isReservedWord(): boolean;
reScanGreaterToken(): SyntaxKind;
reScanSlashToken(): SyntaxKind;
reScanTemplateToken(): SyntaxKind;
scan(): SyntaxKind;
setText(text: string): void;
setTextPos(textPos: number): void;
@@ -80,6 +81,7 @@ module ts {
"throw": SyntaxKind.ThrowKeyword,
"true": SyntaxKind.TrueKeyword,
"try": SyntaxKind.TryKeyword,
"type": SyntaxKind.TypeKeyword,
"typeof": SyntaxKind.TypeOfKeyword,
"var": SyntaxKind.VarKeyword,
"void": SyntaxKind.VoidKeyword,
@@ -244,7 +246,7 @@ module ts {
return tokenStrings[t];
}
export function getLineStarts(text: string): number[] {
export function computeLineStarts(text: string): number[] {
var result: number[] = new Array();
var pos = 0;
var lineStart = 0;
@@ -292,7 +294,7 @@ module ts {
}
export function positionToLineAndCharacter(text: string, pos: number) {
var lineStarts = getLineStarts(text);
var lineStarts = computeLineStarts(text);
return getLineAndCharacterOfPosition(lineStarts, pos);
}
@@ -371,8 +373,8 @@ module ts {
// between the given position and the next line break are returned. The return value is an array containing a TextRange for each
// comment. Single-line comment ranges include the beginning '//' characters but not the ending line break. Multi-line comment
// ranges include the beginning '/* and ending '*/' characters. The return value is undefined if no comments were found.
function getCommentRanges(text: string, pos: number, trailing: boolean): Comment[] {
var result: Comment[];
function getCommentRanges(text: string, pos: number, trailing: boolean): CommentRange[] {
var result: CommentRange[];
var collecting = trailing || pos === 0;
while (true) {
var ch = text.charCodeAt(pos);
@@ -440,11 +442,11 @@ module ts {
}
}
export function getLeadingComments(text: string, pos: number): Comment[] {
export function getLeadingCommentRanges(text: string, pos: number): CommentRange[] {
return getCommentRanges(text, pos, /*trailing*/ false);
}
export function getTrailingComments(text: string, pos: number): Comment[] {
export function getTrailingCommentRanges(text: string, pos: number): CommentRange[] {
return getCommentRanges(text, pos, /*trailing*/ true);
}
@@ -460,12 +462,12 @@ module ts {
ch > CharacterCodes.maxAsciiCharacter && isUnicodeIdentifierPart(ch, languageVersion);
}
export function createScanner(languageVersion: ScriptTarget, text?: string, onError?: ErrorCallback, onComment?: CommentCallback): Scanner {
export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean, text?: string, onError?: ErrorCallback, onComment?: CommentCallback): Scanner {
var pos: number; // Current position (end position of text of current token)
var len: number; // Length of text
var startPos: number; // Start position of whitespace before current token
var tokenPos: number; // Start position of text of current token
var token: number;
var token: SyntaxKind;
var tokenValue: string;
var precedingLineBreak: boolean;
@@ -518,10 +520,10 @@ module ts {
return +(text.substring(start, pos));
}
function scanHexDigits(count: number, exact?: boolean): number {
function scanHexDigits(count: number, mustMatchCount?: boolean): number {
var digits = 0;
var value = 0;
while (digits < count || !exact) {
while (digits < count || !mustMatchCount) {
var ch = text.charCodeAt(pos);
if (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) {
value = value * 16 + ch - CharacterCodes._0;
@@ -551,7 +553,7 @@ module ts {
while (true) {
if (pos >= len) {
result += text.substring(start, pos);
error(Diagnostics.Unexpected_end_of_text);
error(Diagnostics.Unterminated_string_literal);
break;
}
var ch = text.charCodeAt(pos);
@@ -562,60 +564,7 @@ module ts {
}
if (ch === CharacterCodes.backslash) {
result += text.substring(start, pos);
pos++;
if (pos >= len) {
error(Diagnostics.Unexpected_end_of_text);
break;
}
ch = text.charCodeAt(pos++);
switch (ch) {
case CharacterCodes._0:
result += "\0";
break;
case CharacterCodes.b:
result += "\b";
break;
case CharacterCodes.t:
result += "\t";
break;
case CharacterCodes.n:
result += "\n";
break;
case CharacterCodes.v:
result += "\v";
break;
case CharacterCodes.f:
result += "\f";
break;
case CharacterCodes.r:
result += "\r";
break;
case CharacterCodes.singleQuote:
result += "\'";
break;
case CharacterCodes.doubleQuote:
result += "\"";
break;
case CharacterCodes.x:
case CharacterCodes.u:
var ch = scanHexDigits(ch === CharacterCodes.x ? 2 : 4, true);
if (ch >= 0) {
result += String.fromCharCode(ch);
}
else {
error(Diagnostics.Hexadecimal_digit_expected);
}
break;
case CharacterCodes.carriageReturn:
if (pos < len && text.charCodeAt(pos) === CharacterCodes.lineFeed) pos++;
break;
case CharacterCodes.lineFeed:
case CharacterCodes.lineSeparator:
case CharacterCodes.paragraphSeparator:
break;
default:
result += String.fromCharCode(ch);
}
result += scanEscapeSequence();
start = pos;
continue;
}
@@ -629,13 +578,136 @@ module ts {
return result;
}
/**
* Sets the current 'tokenValue' and returns a NoSubstitutionTemplateLiteral or
* a literal component of a TemplateExpression.
*/
function scanTemplateAndSetTokenValue(): SyntaxKind {
var startedWithBacktick = text.charCodeAt(pos) === CharacterCodes.backtick;
pos++;
var start = pos;
var contents = ""
var resultingToken: SyntaxKind;
while (true) {
if (pos >= len) {
contents += text.substring(start, pos);
error(Diagnostics.Unterminated_template_literal);
resultingToken = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral : SyntaxKind.TemplateTail;
break;
}
var currChar = text.charCodeAt(pos);
// '`'
if (currChar === CharacterCodes.backtick) {
contents += text.substring(start, pos);
pos++;
resultingToken = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral : SyntaxKind.TemplateTail;
break;
}
// '${'
if (currChar === CharacterCodes.$ && pos + 1 < len && text.charCodeAt(pos + 1) === CharacterCodes.openBrace) {
contents += text.substring(start, pos);
pos += 2;
resultingToken = startedWithBacktick ? SyntaxKind.TemplateHead : SyntaxKind.TemplateMiddle;
break;
}
// Escape character
if (currChar === CharacterCodes.backslash) {
contents += text.substring(start, pos);
contents += scanEscapeSequence();
start = pos;
continue;
}
// Speculated ECMAScript 6 Spec 11.8.6.1:
// <CR><LF> and <CR> LineTerminatorSequences are normalized to <LF> for Template Values
// An explicit EscapeSequence is needed to include a <CR> or <CR><LF> sequence.
if (currChar === CharacterCodes.carriageReturn) {
contents += text.substring(start, pos);
if (pos + 1 < len && text.charCodeAt(pos + 1) === CharacterCodes.lineFeed) {
pos++;
}
pos++;
contents += "\n";
start = pos;
continue;
}
pos++;
}
Debug.assert(resultingToken !== undefined);
tokenValue = contents;
return resultingToken;
}
function scanEscapeSequence(): string {
pos++;
if (pos >= len) {
error(Diagnostics.Unexpected_end_of_text);
return "";
}
var ch = text.charCodeAt(pos++);
switch (ch) {
case CharacterCodes._0:
return "\0";
case CharacterCodes.b:
return "\b";
case CharacterCodes.t:
return "\t";
case CharacterCodes.n:
return "\n";
case CharacterCodes.v:
return "\v";
case CharacterCodes.f:
return "\f";
case CharacterCodes.r:
return "\r";
case CharacterCodes.singleQuote:
return "\'";
case CharacterCodes.doubleQuote:
return "\"";
case CharacterCodes.x:
case CharacterCodes.u:
var ch = scanHexDigits(ch === CharacterCodes.x ? 2 : 4, /*mustMatchCount*/ true);
if (ch >= 0) {
return String.fromCharCode(ch);
}
else {
error(Diagnostics.Hexadecimal_digit_expected);
return ""
}
// when encountering a LineContinuation (i.e. a backslash and a line terminator sequence),
// the line terminator is interpreted to be "the empty code unit sequence".
case CharacterCodes.carriageReturn:
if (pos < len && text.charCodeAt(pos) === CharacterCodes.lineFeed) {
pos++;
}
// fall through
case CharacterCodes.lineFeed:
case CharacterCodes.lineSeparator:
case CharacterCodes.paragraphSeparator:
return ""
default:
return String.fromCharCode(ch);
}
}
// Current character is known to be a backslash. Check for Unicode escape of the form '\uXXXX'
// and return code point value if valid Unicode escape is found. Otherwise return -1.
function peekUnicodeEscape(): number {
if (pos + 5 < len && text.charCodeAt(pos + 1) === CharacterCodes.u) {
var start = pos;
pos += 2;
var value = scanHexDigits(4, true);
var value = scanHexDigits(4, /*mustMatchCount*/ true);
pos = start;
return value;
}
@@ -694,12 +766,34 @@ module ts {
case CharacterCodes.lineFeed:
case CharacterCodes.carriageReturn:
precedingLineBreak = true;
if (skipTrivia) {
pos++;
continue;
}
else {
if (ch === CharacterCodes.carriageReturn && pos + 1 < len && text.charCodeAt(pos + 1) === CharacterCodes.lineFeed) {
// consume both CR and LF
pos += 2;
}
else {
pos++;
}
return token = SyntaxKind.NewLineTrivia;
}
case CharacterCodes.tab:
case CharacterCodes.verticalTab:
case CharacterCodes.formFeed:
case CharacterCodes.space:
pos++;
continue;
if (skipTrivia) {
pos++;
continue;
}
else {
while (pos < len && isWhiteSpace(text.charCodeAt(pos))) {
pos++;
}
return token = SyntaxKind.WhitespaceTrivia;
}
case CharacterCodes.exclamation:
if (text.charCodeAt(pos + 1) === CharacterCodes.equals) {
if (text.charCodeAt(pos + 2) === CharacterCodes.equals) {
@@ -712,6 +806,8 @@ module ts {
case CharacterCodes.singleQuote:
tokenValue = scanString();
return token = SyntaxKind.StringLiteral;
case CharacterCodes.backtick:
return token = scanTemplateAndSetTokenValue()
case CharacterCodes.percent:
if (text.charCodeAt(pos + 1) === CharacterCodes.equals) {
return pos += 2, token = SyntaxKind.PercentEqualsToken;
@@ -776,7 +872,13 @@ module ts {
if (onComment) {
onComment(tokenPos, pos);
}
continue;
if (skipTrivia) {
continue;
}
else {
return token = SyntaxKind.SingleLineCommentTrivia;
}
}
// Multi-line comment
if (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) {
@@ -806,7 +908,12 @@ module ts {
onComment(tokenPos, pos);
}
continue;
if (skipTrivia) {
continue;
}
else {
return token = SyntaxKind.MultiLineCommentTrivia;
}
}
if (text.charCodeAt(pos + 1) === CharacterCodes.equals) {
@@ -818,18 +925,18 @@ module ts {
case CharacterCodes._0:
if (pos + 2 < len && (text.charCodeAt(pos + 1) === CharacterCodes.X || text.charCodeAt(pos + 1) === CharacterCodes.x)) {
pos += 2;
var value = scanHexDigits(1, false);
var value = scanHexDigits(1, /*mustMatchCount*/ false);
if (value < 0) {
error(Diagnostics.Hexadecimal_digit_expected);
value = 0;
}
tokenValue = "" + value;
return SyntaxKind.NumericLiteral;
return token = SyntaxKind.NumericLiteral;
}
// Try to parse as an octal
if (pos + 1 < len && isOctalDigit(text.charCodeAt(pos + 1))) {
tokenValue = "" + scanOctalDigits();
return SyntaxKind.NumericLiteral;
return token = SyntaxKind.NumericLiteral;
}
// This fall-through is a deviation from the EcmaScript grammar. The grammar says that a leading zero
// can only be followed by an octal digit, a dot, or the end of the number literal. However, we are being
@@ -959,19 +1066,19 @@ module ts {
var inEscape = false;
var inCharacterClass = false;
while (true) {
// If we've hit EOF without closing off the regex,
// simply return the token we originally parsed.
// If we reach the end of a file, or hit a newline, then this is an unterminated
// regex. Report error and return what we have so far.
if (p >= len) {
return token;
error(Diagnostics.Unterminated_regular_expression_literal)
break;
}
var ch = text.charCodeAt(p);
// Line breaks are not permissible in the middle of a RegExp.
if (isLineBreak(ch)) {
return token;
error(Diagnostics.Unterminated_regular_expression_literal)
break;
}
if (inEscape) {
// Parsing an escape character;
// reset the flag and just advance to the next char.
@@ -980,6 +1087,7 @@ module ts {
else if (ch === CharacterCodes.slash && !inCharacterClass) {
// A slash within a character class is permissible,
// but in general it signals the end of the regexp literal.
p++;
break;
}
else if (ch === CharacterCodes.openBracket) {
@@ -993,8 +1101,8 @@ module ts {
}
p++;
}
p++;
while (isIdentifierPart(text.charCodeAt(p))) {
while (p < len && isIdentifierPart(text.charCodeAt(p))) {
p++;
}
pos = p;
@@ -1004,6 +1112,15 @@ module ts {
return token;
}
/**
* Unconditionally back up and scan a template expression portion.
*/
function reScanTemplateToken(): SyntaxKind {
Debug.assert(token === SyntaxKind.CloseBraceToken, "'reScanTemplateToken' should only be called on a '}'");
pos = tokenPos;
return token = scanTemplateAndSetTokenValue();
}
function tryScan<T>(callback: () => T): T {
var savePos = pos;
var saveStartPos = startPos;
@@ -1050,12 +1167,13 @@ module ts {
hasPrecedingLineBreak: () => precedingLineBreak,
isIdentifier: () => token === SyntaxKind.Identifier || token > SyntaxKind.LastReservedWord,
isReservedWord: () => token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord,
reScanGreaterToken: reScanGreaterToken,
reScanSlashToken: reScanSlashToken,
scan: scan,
setText: setText,
setTextPos: setTextPos,
tryScan: tryScan
reScanGreaterToken,
reScanSlashToken,
reScanTemplateToken,
scan,
setText,
setTextPos,
tryScan,
};
}
}
+6 -7
View File
@@ -1,4 +1,3 @@
/// <reference path="diagnosticInformationMap.generated.ts"/>
interface System {
args: string[];
@@ -68,7 +67,7 @@ var sys: System = (function () {
return fileStream.ReadText();
}
catch (e) {
throw e.number === -2147024809 ? new Error(ts.Diagnostics.Unsupported_file_encoding.key) : e;
throw e;
}
finally {
fileStream.Close();
@@ -100,14 +99,14 @@ var sys: System = (function () {
}
return {
args: args,
args,
newLine: "\r\n",
useCaseSensitiveFileNames: false,
write(s: string): void {
WScript.StdOut.Write(s);
},
readFile: readFile,
writeFile: writeFile,
readFile,
writeFile,
resolvePath(path: string): string {
return fso.GetAbsolutePathName(path);
},
@@ -192,8 +191,8 @@ var sys: System = (function () {
// 1 is a standard descriptor for stdout
_fs.writeSync(1, s);
},
readFile: readFile,
writeFile: writeFile,
readFile,
writeFile,
watchFile: (fileName, callback) => {
// watchFile polls a file every 250ms, picking up file notifications.
_fs.watchFile(fileName, { persistent: true, interval: 250 }, fileChanged);
+53 -26
View File
@@ -9,7 +9,7 @@
/// <reference path="commandLineParser.ts"/>
module ts {
var version = "1.1.0.0";
var version = "1.3.0.0";
/**
* Checks to see if the locale is in the appropriate format,
@@ -142,14 +142,19 @@ module ts {
// otherwise use toLowerCase as a canonical form.
return sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
}
// returned by CScript sys environment
var unsupportedFileEncodingErrorCode = -2147024809;
function getSourceFile(filename: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile {
try {
var text = sys.readFile(filename, options.charset);
}
catch (e) {
if (onError) {
onError(e.message);
onError(e.number === unsupportedFileEncodingErrorCode ?
getDiagnosticText(Diagnostics.Unsupported_file_encoding) :
e.message);
}
text = "";
}
@@ -187,20 +192,26 @@ module ts {
}
return {
getSourceFile: getSourceFile,
getSourceFile,
getDefaultLibFilename: () => combinePaths(getDirectoryPath(normalizePath(sys.getExecutingFilePath())), "lib.d.ts"),
writeFile: writeFile,
writeFile,
getCurrentDirectory: () => currentDirectory || (currentDirectory = sys.getCurrentDirectory()),
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
getCanonicalFileName: getCanonicalFileName,
getCanonicalFileName,
getNewLine: () => sys.newLine
};
}
export function executeCommandLine(args: string[]): void {
var commandLine = parseCommandLine(args);
var compilerOptions = commandLine.options;
if (compilerOptions.locale) {
if (typeof JSON === "undefined") {
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--locale"));
return sys.exit(1);
}
if (commandLine.options.locale) {
validateLocaleAndSetLanguage(commandLine.options.locale, commandLine.errors);
}
@@ -208,32 +219,38 @@ module ts {
// setting up localization, report them and quit.
if (commandLine.errors.length > 0) {
reportDiagnostics(commandLine.errors);
return sys.exit(1);
return sys.exit(EmitReturnStatus.CompilerOptionsErrors);
}
if (commandLine.options.version) {
if (compilerOptions.version) {
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Version_0, version));
return sys.exit(0);
return sys.exit(EmitReturnStatus.Succeeded);
}
if (commandLine.options.help || commandLine.filenames.length === 0) {
if (compilerOptions.help) {
printVersion();
printHelp();
return sys.exit(0);
return sys.exit(EmitReturnStatus.Succeeded);
}
var defaultCompilerHost = createCompilerHost(commandLine.options);
if (commandLine.filenames.length === 0) {
printVersion();
printHelp();
return sys.exit(EmitReturnStatus.CompilerOptionsErrors);
}
var defaultCompilerHost = createCompilerHost(compilerOptions);
if (commandLine.options.watch) {
if (compilerOptions.watch) {
if (!sys.watchFile) {
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"));
return sys.exit(1);
return sys.exit(EmitReturnStatus.CompilerOptionsErrors);
}
watchProgram(commandLine, defaultCompilerHost);
}
else {
var result = compile(commandLine, defaultCompilerHost).errors.length > 0 ? 1 : 0;
var result = compile(commandLine, defaultCompilerHost).exitStatus
return sys.exit(result);
}
}
@@ -328,23 +345,34 @@ module ts {
function compile(commandLine: ParsedCommandLine, compilerHost: CompilerHost) {
var parseStart = new Date().getTime();
var program = createProgram(commandLine.filenames, commandLine.options, compilerHost);
var compilerOptions = commandLine.options;
var program = createProgram(commandLine.filenames, compilerOptions, compilerHost);
var bindStart = new Date().getTime();
var errors = program.getDiagnostics();
var errors: Diagnostic[] = program.getDiagnostics();
var exitStatus: EmitReturnStatus;
if (errors.length) {
var checkStart = bindStart;
var emitStart = bindStart;
var reportStart = bindStart;
exitStatus = EmitReturnStatus.AllOutputGenerationSkipped;
}
else {
var checker = program.getTypeChecker(/*fullTypeCheckMode*/ true);
var checkStart = new Date().getTime();
var semanticErrors = checker.getDiagnostics();
var emitStart = new Date().getTime();
var emitErrors = checker.emitFiles().errors;
var reportStart = new Date().getTime();
errors = concatenate(semanticErrors, emitErrors);
errors = checker.getDiagnostics();
if (checker.isEmitBlocked()) {
exitStatus = EmitReturnStatus.AllOutputGenerationSkipped;
}
else {
var emitStart = new Date().getTime();
var emitOutput = checker.emitFiles();
var emitErrors = emitOutput.diagnostics;
exitStatus = emitOutput.emitResultStatus;
var reportStart = new Date().getTime();
errors = concatenate(errors, emitErrors);
}
}
reportDiagnostics(errors);
@@ -366,8 +394,7 @@ module ts {
reportTimeStatistic("Total time", reportStart - parseStart);
}
return { program: program, errors: errors };
return { program, exitStatus };
}
function printVersion() {
@@ -392,7 +419,7 @@ module ts {
// Build up the list of examples.
var padding = makePadding(marginLength);
output += getDiagnosticText(Diagnostics.Examples_Colon_0, makePadding(marginLength - examplesLength) + "tsc hello.ts") + sys.newLine;
output += padding + "tsc --out foo.js foo.ts" + sys.newLine;
output += padding + "tsc --out file.js file.ts" + sys.newLine;
output += padding + "tsc @args.txt" + sys.newLine;
output += sys.newLine;
+449 -186
View File
File diff suppressed because it is too large Load Diff
+27 -64
View File
@@ -3,7 +3,7 @@
/// <reference path='typeWriter.ts' />
/// <reference path='syntacticCleaner.ts' />
enum CompilerTestType {
const enum CompilerTestType {
Conformance,
Regressions,
Test262
@@ -61,9 +61,11 @@ class CompilerBaselineRunner extends RunnerBase {
var otherFiles: { unitName: string; content: string }[];
var harnessCompiler: Harness.Compiler.HarnessCompiler;
var declToBeCompiled: { unitName: string; content: string }[] = [];
var declOtherFiles: { unitName: string; content: string }[] = [];
var declResult: Harness.Compiler.CompilerResult;
var declFileCompilationResult: {
declInputFiles: { unitName: string; content: string }[];
declOtherFiles: { unitName: string; content: string }[];
declResult: Harness.Compiler.CompilerResult;
};
var createNewInstance = false;
@@ -147,19 +149,14 @@ class CompilerBaselineRunner extends RunnerBase {
toBeCompiled = undefined;
otherFiles = undefined;
harnessCompiler = undefined;
declToBeCompiled = undefined;
declOtherFiles = undefined;
declResult = undefined;
declFileCompilationResult = undefined;
});
function getByteOrderMarkText(file: Harness.Compiler.GeneratedFile): string {
return file.writeByteOrderMark ? "\u00EF\u00BB\u00BF" : "";
}
function getErrorBaseline(toBeCompiled: { unitName: string; content: string }[],
otherFiles: { unitName: string; content: string }[],
result: Harness.Compiler.CompilerResult
) {
function getErrorBaseline(toBeCompiled: { unitName: string; content: string }[], otherFiles: { unitName: string; content: string }[], result: Harness.Compiler.CompilerResult) {
return Harness.Compiler.getErrorBaseline(toBeCompiled.concat(otherFiles), result.errors);
}
@@ -168,7 +165,7 @@ class CompilerBaselineRunner extends RunnerBase {
if (this.errors) {
Harness.Baseline.runBaseline('Correct errors for ' + fileName, justName.replace(/\.ts$/, '.errors.txt'), (): string => {
if (result.errors.length === 0) return null;
return getErrorBaseline(toBeCompiled, otherFiles, result);
});
}
@@ -176,61 +173,23 @@ class CompilerBaselineRunner extends RunnerBase {
// Source maps?
it('Correct sourcemap content for ' + fileName, () => {
if (result.sourceMapRecord) {
if (options.sourceMap) {
Harness.Baseline.runBaseline('Correct sourcemap content for ' + fileName, justName.replace(/\.ts$/, '.sourcemap.txt'), () => {
return result.sourceMapRecord;
var record = result.getSourceMapRecord();
if (options.noEmitOnError && result.errors.length !== 0 && record === undefined) {
// Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required.
return null;
}
return record;
});
}
});
// Compile .d.ts files
it('Correct compiler generated.d.ts for ' + fileName, () => {
if (options.declaration && result.errors.length === 0 && result.declFilesCode.length !== result.files.length) {
throw new Error('There were no errors and declFiles generated did not match number of js files generated');
}
// if the .d.ts is non-empty, confirm it compiles correctly as well
if (options.declaration && result.errors.length === 0 && result.declFilesCode.length > 0) {
function addDtsFile(file: { unitName: string; content: string }, dtsFiles: { unitName: string; content: string }[]) {
if (Harness.Compiler.isDTS(file.unitName)) {
dtsFiles.push(file);
}
else {
var declFile = findResultCodeFile(file.unitName);
// Look if there is --out file corresponding to this ts file
if (!declFile && options.out) {
declFile = findResultCodeFile(options.out);
if (!declFile || findUnit(declFile.fileName, declToBeCompiled) ||
findUnit(declFile.fileName, declOtherFiles)) {
return;
}
}
if (declFile) {
dtsFiles.push({ unitName: declFile.fileName, content: declFile.code });
return;
}
}
function findResultCodeFile(fileName: string) {
return ts.forEach(result.declFilesCode,
declFile => declFile.fileName === (fileName.substr(0, fileName.length - ".ts".length) + ".d.ts")
? declFile : undefined);
}
function findUnit(fileName: string, units: { unitName: string; content: string }[]) {
return ts.forEach(units, unit => unit.unitName === fileName ? unit : undefined);
}
}
ts.forEach(toBeCompiled, file => addDtsFile(file, declToBeCompiled));
ts.forEach(otherFiles, file => addDtsFile(file, declOtherFiles));
harnessCompiler.compileFiles(declToBeCompiled, declOtherFiles, function (compileResult) {
declResult = compileResult;
}, function (settings) {
harnessCompiler.setCompilerSettings(tcSettings);
});
}
declFileCompilationResult = harnessCompiler.compileDeclarationFiles(toBeCompiled, otherFiles, result, function (settings) {
harnessCompiler.setCompilerSettings(tcSettings);
}, options);
});
@@ -270,10 +229,10 @@ class CompilerBaselineRunner extends RunnerBase {
}
}
if (declResult && declResult.errors.length) {
if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) {
jsCode += '\r\n\r\n//// [DtsFileErrors]\r\n';
jsCode += '\r\n\r\n';
jsCode += getErrorBaseline(declToBeCompiled, declOtherFiles, declResult);
jsCode += getErrorBaseline(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles, declFileCompilationResult.declResult);
}
if (jsCode.length > 0) {
@@ -292,6 +251,12 @@ class CompilerBaselineRunner extends RunnerBase {
}
Harness.Baseline.runBaseline('Correct Sourcemap output for ' + fileName, justName.replace(/\.ts/, '.js.map'), () => {
if (options.noEmitOnError && result.errors.length !== 0 && result.sourceMaps.length === 0) {
// We need to return null here or the runBaseLine will actually create a empty file.
// Baselining isn't required here because there is no output.
return null;
}
var sourceMapCode = '';
for (var i = 0; i < result.sourceMaps.length; i++) {
sourceMapCode += '//// [' + Harness.Path.getFileName(result.sourceMaps[i].fileName) + ']\r\n';
@@ -331,12 +296,10 @@ class CompilerBaselineRunner extends RunnerBase {
typeLines.push('=== ' + file.unitName + ' ===\r\n');
for (var i = 0; i < codeLines.length; i++) {
var currentCodeLine = codeLines[i];
var lastLine = typeLines[typeLines.length];
typeLines.push(currentCodeLine + '\r\n');
if (typeMap[file.unitName]) {
var typeInfo = typeMap[file.unitName][i];
if (typeInfo) {
var leadingSpaces = '';
typeInfo.forEach(ty => {
typeLines.push('>' + ty + '\r\n');
});
-225
View File
@@ -1,225 +0,0 @@
if (!String.prototype.trim) {
String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g, '');
};
}
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement, fromIndex) {
"use strict";
if (this == null) {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
if (len === 0) {
return -1;
}
var n = 0;
if (arguments.length > 0) {
n = Number(arguments[1]);
if (n != n) {
n = 0;
} else if (n != 0 && n != Infinity && n != -Infinity) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
}
if (n >= len) {
return -1;
}
var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
for (; k < len; k++) {
if (k in t && t[k] === searchElement) {
return k;
}
}
return -1;
};
}
if (!Array.prototype.filter) {
Array.prototype.filter = function (fun, thisp) {
"use strict";
if (this == null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun != "function")
throw new TypeError();
var res = [];
for (var i = 0; i < len; i++) {
if (i in t) {
var val = t[i];
if (fun.call(thisp, val, i, t))
res.push(val);
}
}
return res;
};
}
if (!Array.prototype.map) {
Array.prototype.map = function (callback, thisArg) {
var T = undefined, A, k;
if (this == null) {
throw new TypeError(" this is null or not defined");
}
// 1. Let O be the result of calling ToObject passing the |this| value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
var len = O.length >>> 0;
if ({}.toString.call(callback) != "[object Function]") {
throw new TypeError(callback + " is not a function");
}
if (thisArg) {
T = thisArg;
}
// 6. Let A be a new array created as if by the expression new Array(len) where Array is
// the standard built-in constructor with that name and len is the value of len.
A = new Array(len);
// 7. Let k be 0
k = 0;
while (k < len) {
var kValue, mappedValue;
if (k in O) {
// i. Let kValue be the result of calling the Get internal method of O with argument Pk.
kValue = O[k];
// ii. Let mappedValue be the result of calling the Call internal method of callback
// with T as the this value and argument list containing kValue, k, and O.
mappedValue = callback.call(T, kValue, k, O);
// iii. Call the DefineOwnProperty internal method of A with arguments
// Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true},
// and false.
// In browsers that support Object.defineProperty, use the following:
// Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });
// For best browser support, use the following:
A[k] = mappedValue;
}
// d. Increase k by 1.
k++;
}
// 9. return A
return A;
};
}
if (!Array.prototype.reduce) {
Array.prototype.reduce = function reduce(accumulator) {
if (this === null || this === undefined)
throw new TypeError("Object is null or undefined");
var i = 0, l = this.length >> 0, curr;
if (typeof accumulator !== "function")
throw new TypeError("First argument is not callable");
if (arguments.length < 2) {
if (l === 0)
throw new TypeError("Array length is 0 and no second argument");
curr = this[0];
i = 1;
} else
curr = arguments[1];
while (i < l) {
if (i in this)
curr = accumulator.call(undefined, curr, this[i], i, this);
++i;
}
return curr;
};
}
if (!Array.prototype.forEach) {
Array.prototype.forEach = function (callback, thisArg) {
var T, k;
if (this == null) {
throw new TypeError(" this is null or not defined");
}
// 1. Let O be the result of calling ToObject passing the |this| value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
var len = O.length >>> 0;
if ({}.toString.call(callback) != "[object Function]") {
throw new TypeError(callback + " is not a function");
}
if (thisArg) {
T = thisArg;
} else {
T = undefined;
}
// 6. Let k be 0
k = 0;
while (k < len) {
var kValue;
if (k in O) {
// i. Let kValue be the result of calling the Get internal method of O with argument Pk.
kValue = O[k];
// ii. Call the Call internal method of callback with T as the this value and
// argument list containing kValue, k, and O.
callback.call(T, kValue, k, O);
}
// d. Increase k by 1.
k++;
}
// 8. return undefined
};
}
if (!Date.now) {
Date.now = function () {
return (new Date()).getTime();
};
}
if (!Array.prototype.some) {
Array.prototype.some = function (fun/*, thisp */ ) {
"use strict";
if (this == null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun != "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++) {
var idx = i.toString();
if (idx in t && fun.call(thisp, t[i], i, t))
return true;
}
return false;
};
}
-354
View File
@@ -1,354 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/*----------------- ThirdPartyNotices -------------------------------------------------------
This file is based on or incorporates material from the projects listed below
(collectively "Third Party Code"). Microsoft is not the original author of the
Third Party Code. The original copyright notice and the license, under which
Microsoft received such Third Party Code, are set forth below. Such license and
notices are provided for informational purposes only. Microsoft licenses the Third
Party Code to you under the terms of the Apache 2.0 License.
--
Array filter Compatibility Method,
Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter
Array forEach Compatibility Method,
Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach
Array indexOf Compatibility Method,
Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf
Array map Compatibility Method,
Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map
Array Reduce Compatibility Method,
Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/Reduce
Array some Compatibility Method,
Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/some
String Trim Compatibility Method,
Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/Trim
Date now Compatibility Method,
Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/now
Copyright (c) 2007 - 2012 Mozilla Developer Network and individual contributors
Licensed by Microsoft under the Apache License, Version 2.0 (the "License"); you
may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR
CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions and
limitations under the License.
--
Original License provided for Informational Purposes Only
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------- End of ThirdPartyNotices --------------------------------------------------- */
// Compatibility with non ES5 compliant engines
if (!String.prototype.trim) {
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, '');
};
}
// Compatibility with non ES5 compliant engines
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement: any, fromIndex?: any) {
"use strict";
if (this == null) {
throw new TypeError();
}
var t = Object(this);
var len: any = t.length >>> 0;
if (len === 0) {
return -1;
}
var n: any = 0;
if (arguments.length > 0) {
n = Number(arguments[1]);
if (n != n) { // shortcut for verifying if it's NaN
n = 0;
}
else if (n != 0 && n != Infinity && n != -Infinity) {
n = (n > 0 || <any>-1) * Math.floor(Math.abs(n));
}
}
if (n >= len) {
return -1;
}
var k: any = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
for (; k < len; k++) {
if (k in t && t[k] === searchElement) {
return k;
}
}
return -1;
}
}
if (!Array.prototype.filter)
{
Array.prototype.filter = function(fun: any, thisp?: any)
{
"use strict";
if (this == null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun != "function")
throw new TypeError();
var res: any[] = [];
for (var i = 0; i < len; i++)
{
if (<any>i in t)
{
var val = t[i]; // in case fun mutates this
if (fun.call(thisp, val, i, t))
res.push(val);
}
}
return res;
};
}
// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: http://es5.github.com/#x15.4.4.19
if (!Array.prototype.map) {
Array.prototype.map = function(callback: any, thisArg?: any) {
var T: any = undefined, A: any, k: any;
if (this == null) {
throw new TypeError(" this is null or not defined");
}
// 1. Let O be the result of calling ToObject passing the |this| value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
var len = O.length >>> 0;
// 4. If IsCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
if ({}.toString.call(callback) != "[object Function]") {
throw new TypeError(callback + " is not a function");
}
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (thisArg) {
T = thisArg;
}
// 6. Let A be a new array created as if by the expression new Array(len) where Array is
// the standard built-in constructor with that name and len is the value of len.
A = new Array(len);
// 7. Let k be 0
k = 0;
// 8. Repeat, while k < len
while(k < len) {
var kValue: any, mappedValue: any;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
if (k in O) {
// i. Let kValue be the result of calling the Get internal method of O with argument Pk.
kValue = O[ k ];
// ii. Let mappedValue be the result of calling the Call internal method of callback
// with T as the this value and argument list containing kValue, k, and O.
mappedValue = callback.call(T, kValue, k, O);
// iii. Call the DefineOwnProperty internal method of A with arguments
// Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true},
// and false.
// In browsers that support Object.defineProperty, use the following:
// Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });
// For best browser support, use the following:
A[ k ] = mappedValue;
}
// d. Increase k by 1.
k++;
}
// 9. return A
return A;
};
}
if (!Array.prototype.reduce) {
Array.prototype.reduce = function reduce(accumulator: any){
if (this===null || this===undefined) throw new TypeError("Object is null or undefined");
var i = 0, l = this.length >> 0, curr: any;
if(typeof accumulator !== "function") // ES5 : "If IsCallable(callbackfn) is false, throw a TypeError exception."
throw new TypeError("First argument is not callable");
if(arguments.length < 2) {
if (l === 0) throw new TypeError("Array length is 0 and no second argument");
curr = this[0];
i = 1; // start accumulating at the second element
}
else
curr = arguments[1];
while (i < l) {
if(<any>i in this) curr = accumulator.call(undefined, curr, this[i], i, this);
++i;
}
return curr;
};
}
// Compatibility with non ES5 compliant engines
// Production steps of ECMA-262, Edition 5, 15.4.4.18
// Reference: http://es5.github.com/#x15.4.4.18
if (!Array.prototype.forEach) {
Array.prototype.forEach = function(callback: any, thisArg?: any) {
var T: any, k: any;
if (this == null) {
throw new TypeError(" this is null or not defined");
}
// 1. Let O be the result of calling ToObject passing the |this| value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
var len = O.length >>> 0; // Hack to convert O.length to a UInt32
// 4. If IsCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
if ({ }.toString.call(callback) != "[object Function]") {
throw new TypeError(callback + " is not a function");
}
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (thisArg) {
T = thisArg;
}
else {
T = undefined; // added to stop definite assignment error
}
// 6. Let k be 0
k = 0;
// 7. Repeat, while k < len
while (k < len) {
var kValue: any;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
if (k in O) {
// i. Let kValue be the result of calling the Get internal method of O with argument Pk.
kValue = O[k];
// ii. Call the Call internal method of callback with T as the this value and
// argument list containing kValue, k, and O.
callback.call(T, kValue, k, O);
}
// d. Increase k by 1.
k++;
}
// 8. return undefined
};
}
// Compatibility with non ES5 compliant engines
if (!Date.now) {
Date.now = function() {
return (new Date()).getTime();
};
}
// Compatibility with non ES5 compliant engines
// Production steps of ECMA-262, Edition 5.1, 15.4.4.17
if (!Array.prototype.some)
{
Array.prototype.some = function(fun: any /*, thisp */)
{
"use strict";
if (this == null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun != "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
var idx = i.toString(); // REVIEW: this line is not from the Mozilla page, necessary to avoid our compile time checks against non-string/any types in an in expression
if (idx in t && fun.call(thisp, t[i], i, t))
return true;
}
return false;
};
}
-486
View File
@@ -1,486 +0,0 @@
/*
json2.js
2013-05-26
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or '&nbsp;'),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});
This is a reference implementation. You are free to copy, modify, or
redistribute.
*/
/*jslint evil: true, regexp: true */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
if (typeof JSON !== 'object') {
JSON = {};
}
(function () {
'use strict';
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function () {
return isFinite(this.valueOf())
? this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z'
: null;
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function () {
return this.valueOf();
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string'
? c
: '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' : '"' + string + '"';
}
function str(key, holder) {
// Produce a string from holder[key].
var i, // The loop counter.
k, // The member key.
v, // The member value.
length,
mind = gap,
partial,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if (!value) {
return 'null';
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0
? '[]'
: gap
? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
: '[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
if (typeof rep[i] === 'string') {
k = rep[i];
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0
? '{}'
: gap
? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
: '{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function'
? walk({'': j}, '')
: j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError('JSON.parse');
};
}
}());
-486
View File
@@ -1,486 +0,0 @@
/*
json2.js
2013-05-26
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or '&nbsp;'),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});
This is a reference implementation. You are free to copy, modify, or
redistribute.
*/
/*jslint evil: true, regexp: true */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
if (typeof JSON !== 'object') {
JSON = <any>{};
}
(function () {
'use strict';
function f(n: any) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function () {
return isFinite(this.valueOf())
? this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z'
: null;
};
(<any>String.prototype).toJSON =
(<any>Number.prototype).toJSON =
(<any>Boolean.prototype).toJSON = function () {
return this.valueOf();
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap: any,
indent: any,
meta = <any>{ // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep: any;
function quote(string: string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string'
? c
: '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' : '"' + string + '"';
}
function str(key: any, holder: any) {
// Produce a string from holder[key].
var i: any, // The loop counter.
k: any, // The member key.
v: any, // The member value.
length: number,
mind = gap,
partial: any,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if (!value) {
return 'null';
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0
? '[]'
: gap
? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
: '[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
if (typeof rep[i] === 'string') {
k = rep[i];
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0
? '{}'
: gap
? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
: '{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
JSON.stringify = <any>function (value: any, replacer: any, space: any) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i: any;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j: any;
function walk(holder: any, key: any) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k: any, v: any, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function'
? walk({'': j}, '')
: j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError('JSON.parse');
};
}
}());
+591 -299
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -20,7 +20,7 @@ class FourslashRunner extends RunnerBase {
});
this.tests.forEach((fn: string) => {
fn = Harness.Path.switchToForwardSlashes(fn);
fn = ts.normalizeSlashes(fn);
var justName = fn.replace(/^.*[\\\/]/, '');
// Convert to relative path
+176 -58
View File
@@ -15,6 +15,7 @@
/// <reference path='..\services\services.ts' />
/// <reference path='..\services\shims.ts' />
/// <reference path='..\compiler\core.ts' />
/// <reference path='..\compiler\sys.ts' />
/// <reference path='external\mocha.d.ts'/>
/// <reference path='external\chai.d.ts'/>
@@ -30,7 +31,7 @@ module Utils {
var global = <any>Function("return this").call(null);
// Setup some globals based on the current environment
export enum ExecutionEnvironment {
export const enum ExecutionEnvironment {
Node,
Browser,
CScript
@@ -117,15 +118,11 @@ module Harness.Path {
}
export function filePath(fullPath: string) {
fullPath = switchToForwardSlashes(fullPath);
fullPath = ts.normalizeSlashes(fullPath);
var components = fullPath.split("/");
var path: string[] = components.slice(0, components.length - 1);
return path.join("/") + "/";
}
export function switchToForwardSlashes(path: string) {
return path.replace(/\\/g, "/").replace(/\/\//g, '/');
}
}
module Harness {
@@ -139,6 +136,7 @@ module Harness {
deleteFile(filename: string): void;
listFiles(path: string, filter: RegExp, options?: { recursive?: boolean }): string[];
log(text: string): void;
getMemoryUsage? (): number;
}
module IOImpl {
@@ -275,6 +273,13 @@ module Harness {
return filesInFolder(path);
}
export var getMemoryUsage: typeof IO.getMemoryUsage = () => {
if (global.gc) {
global.gc();
}
return process.memoryUsage().heapUsed;
}
}
export module Network {
@@ -532,32 +537,61 @@ module Harness {
}
export var defaultLibFileName = 'lib.d.ts';
export var defaultLibSourceFile = ts.createSourceFile(defaultLibFileName, IO.readFile(libFolder + 'lib.core.d.ts'), /*languageVersion*/ ts.ScriptTarget.ES5, /*version:*/ "0");
export var defaultLibSourceFile = ts.createSourceFile(defaultLibFileName, IO.readFile(libFolder + 'lib.core.d.ts'), /*languageVersion*/ ts.ScriptTarget.Latest, /*version:*/ "0");
// Cache these between executions so we don't have to re-parse them for every test
export var fourslashFilename = 'fourslash.ts';
export var fourslashSourceFile: ts.SourceFile;
export function getCanonicalFileName(fileName: string): string {
return sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
}
export function createCompilerHost(filemap: { [filename: string]: ts.SourceFile; }, writeFile: (fn: string, contents: string, writeByteOrderMark:boolean) => void): ts.CompilerHost {
export function createCompilerHost(inputFiles: { unitName: string; content: string; }[],
writeFile: (fn: string, contents: string, writeByteOrderMark: boolean) => void,
scriptTarget: ts.ScriptTarget,
useCaseSensitiveFileNames: boolean): ts.CompilerHost {
// Local get canonical file name function, that depends on passed in parameter for useCaseSensitiveFileNames
function getCanonicalFileName(fileName: string): string {
return useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
}
var filemap: { [filename: string]: ts.SourceFile; } = {};
// Register input files
function register(file: { unitName: string; content: string; }) {
if (file.content !== undefined) {
var filename = ts.normalizeSlashes(file.unitName);
filemap[getCanonicalFileName(filename)] = ts.createSourceFile(filename, file.content, scriptTarget, /*version:*/ "0");
}
};
inputFiles.forEach(register);
return {
getCurrentDirectory: sys.getCurrentDirectory,
getCancellationToken: (): any => undefined,
getSourceFile: (fn, languageVersion) => {
if (Object.prototype.hasOwnProperty.call(filemap, getCanonicalFileName(fn))) {
return filemap[getCanonicalFileName(fn)];
} else {
}
else if (fn === fourslashFilename) {
var tsFn = 'tests/cases/fourslash/' + fourslashFilename;
fourslashSourceFile = fourslashSourceFile || ts.createSourceFile(tsFn, Harness.IO.readFile(tsFn), scriptTarget, /*version*/ "0", /*isOpen*/ false);
return fourslashSourceFile;
}
else {
var lib = defaultLibFileName;
if (fn === defaultLibFileName) {
return defaultLibSourceFile;
}
// Don't throw here -- the compiler might be looking for a test that actually doesn't exist as part of the TC
return null;
return undefined;
}
},
getDefaultLibFilename: () => defaultLibFileName,
writeFile: writeFile,
getCanonicalFileName: getCanonicalFileName,
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
writeFile,
getCanonicalFileName,
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
getNewLine: ()=> sys.newLine
};
}
@@ -614,7 +648,7 @@ module Harness {
}
public compileFiles(inputFiles: { unitName: string; content: string }[],
otherFiles: { unitName: string; content?: string }[],
otherFiles: { unitName: string; content: string }[],
onComplete: (result: CompilerResult, checker: ts.TypeChecker) => void,
settingsCallback?: (settings: ts.CompilerOptions) => void,
options?: ts.CompilerOptions) {
@@ -622,14 +656,16 @@ module Harness {
options = options || { noResolve: false };
options.target = options.target || ts.ScriptTarget.ES3;
options.module = options.module || ts.ModuleKind.None;
options.noErrorTruncation = true;
if (settingsCallback) {
settingsCallback(null);
}
var useCaseSensitiveFileNames = sys.useCaseSensitiveFileNames;
this.settings.forEach(setting => {
switch (setting.flag.toLowerCase()) {
// "filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outDir", "noimplicitany", "noresolve"
// "filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outdir", "noimplicitany", "noresolve"
case "module":
case "modulegentarget":
if (typeof setting.value === 'string') {
@@ -654,6 +690,8 @@ module Harness {
options.target = ts.ScriptTarget.ES3;
} else if (setting.value.toLowerCase() === 'es5') {
options.target = ts.ScriptTarget.ES5;
} else if (setting.value.toLowerCase() === 'es6') {
options.target = ts.ScriptTarget.ES6;
} else {
throw new Error('Unknown compile target ' + setting.value);
}
@@ -662,6 +700,10 @@ module Harness {
}
break;
case 'noemitonerror':
options.noEmitOnError = !!setting.value;
break;
case 'noresolve':
options.noResolve = !!setting.value;
break;
@@ -705,15 +747,17 @@ module Harness {
options.removeComments = setting.value === 'false';
break;
case 'usecasesensitivefilenames':
useCaseSensitiveFileNames = setting.value === 'true';
break;
case 'mapsourcefiles':
case 'maproot':
case 'generatedeclarationfiles':
case 'usecasesensitivefileresolution':
case 'gatherDiagnostics':
case 'codepage':
case 'createFileLog':
case 'filename':
case 'propagateenumconstants':
case 'removecomments':
case 'watch':
case 'allowautomaticsemicoloninsertion':
@@ -725,6 +769,12 @@ module Harness {
options.emitBOM = !!setting.value;
break;
case 'errortruncation':
options.noErrorTruncation = setting.value === 'false';
break;
case 'preserveconstenums':
options.preserveConstEnums = setting.value === 'true';
break;
default:
throw new Error('Unsupported compiler setting ' + setting.flag);
}
@@ -733,7 +783,7 @@ module Harness {
var filemap: { [name: string]: ts.SourceFile; } = {};
var register = (file: { unitName: string; content: string; }) => {
if (file.content !== undefined) {
var filename = Path.switchToForwardSlashes(file.unitName);
var filename = ts.normalizeSlashes(file.unitName);
filemap[getCanonicalFileName(filename)] = ts.createSourceFile(filename, file.content, options.target, /*version:*/ "0");
}
};
@@ -743,35 +793,104 @@ module Harness {
var fileOutputs: GeneratedFile[] = [];
var programFiles = inputFiles.map(file => file.unitName);
var program = ts.createProgram(programFiles, options, createCompilerHost(filemap, (fn, contents, writeByteOrderMark) => fileOutputs.push({ fileName: fn, code: contents, writeByteOrderMark: writeByteOrderMark })));
var hadParseErrors = program.getDiagnostics().length > 0;
var program = ts.createProgram(programFiles, options, createCompilerHost(inputFiles.concat(otherFiles),
(fn, contents, writeByteOrderMark) => fileOutputs.push({ fileName: fn, code: contents, writeByteOrderMark: writeByteOrderMark }),
options.target,
useCaseSensitiveFileNames));
var checker = program.getTypeChecker(/*fullTypeCheckMode*/ true);
checker.checkProgram();
var isEmitBlocked = checker.isEmitBlocked();
// only emit if there weren't parse errors
var emitResult: ts.EmitResult;
if (!hadParseErrors) {
if (!isEmitBlocked) {
emitResult = checker.emitFiles();
}
var errors: HarnessDiagnostic[] = [];
program.getDiagnostics().concat(checker.getDiagnostics()).concat(emitResult ? emitResult.errors : []).forEach(err => {
program.getDiagnostics().concat(checker.getDiagnostics()).concat(emitResult ? emitResult.diagnostics : []).forEach(err => {
// TODO: new compiler formats errors after this point to add . and newlines so we'll just do it manually for now
errors.push(getMinimalDiagnostic(err));
});
this.lastErrors = errors;
var result = new CompilerResult(fileOutputs, errors, []);
// Covert the source Map data into the baseline
result.updateSourceMapRecord(program, emitResult ? emitResult.sourceMaps : undefined);
var result = new CompilerResult(fileOutputs, errors, program, sys.getCurrentDirectory(), emitResult ? emitResult.sourceMaps : undefined);
onComplete(result, checker);
// reset what newline means in case the last test changed it
sys.newLine = '\r\n';
return options;
}
public compileDeclarationFiles(inputFiles: { unitName: string; content: string; }[],
otherFiles: { unitName: string; content: string; }[],
result: CompilerResult,
settingsCallback?: (settings: ts.CompilerOptions) => void,
options?: ts.CompilerOptions) {
if (options.declaration && result.errors.length === 0 && result.declFilesCode.length !== result.files.length) {
throw new Error('There were no errors and declFiles generated did not match number of js files generated');
}
// if the .d.ts is non-empty, confirm it compiles correctly as well
if (options.declaration && result.errors.length === 0 && result.declFilesCode.length > 0) {
var declInputFiles: { unitName: string; content: string }[] = [];
var declOtherFiles: { unitName: string; content: string }[] = [];
var declResult: Harness.Compiler.CompilerResult;
ts.forEach(inputFiles, file => addDtsFile(file, declInputFiles));
ts.forEach(otherFiles, file => addDtsFile(file, declOtherFiles));
this.compileFiles(declInputFiles, declOtherFiles, function (compileResult) {
declResult = compileResult;
}, settingsCallback, options);
return { declInputFiles, declOtherFiles, declResult };
}
function addDtsFile(file: { unitName: string; content: string }, dtsFiles: { unitName: string; content: string }[]) {
if (isDTS(file.unitName)) {
dtsFiles.push(file);
}
else if (isTS(file.unitName)) {
var declFile = findResultCodeFile(file.unitName);
if (!findUnit(declFile.fileName, declInputFiles) && !findUnit(declFile.fileName, declOtherFiles)) {
dtsFiles.push({ unitName: declFile.fileName, content: declFile.code });
}
}
function findResultCodeFile(fileName: string) {
var dTsFileName = ts.forEach(result.program.getSourceFiles(), sourceFile => {
if (sourceFile.filename === fileName) {
// Is this file going to be emitted separately
var sourceFileName: string;
if (ts.isExternalModule(sourceFile) || !options.out) {
if (options.outDir) {
var sourceFilePath = ts.getNormalizedAbsolutePath(sourceFile.filename, result.currentDirectoryForProgram);
sourceFilePath = sourceFilePath.replace(result.program.getCommonSourceDirectory(), "");
sourceFileName = ts.combinePaths(options.outDir, sourceFilePath);
}
else {
sourceFileName = sourceFile.filename;
}
}
else {
// Goes to single --out file
sourceFileName = options.out;
}
return ts.removeFileExtension(sourceFileName) + ".d.ts";
}
});
return ts.forEach(result.declFilesCode, declFile => declFile.fileName === dTsFileName ? declFile : undefined);
}
function findUnit(fileName: string, units: { unitName: string; content: string; }[]) {
return ts.forEach(units, unit => unit.unitName === fileName ? unit : undefined);
}
}
}
}
export function getMinimalDiagnostic(err: ts.Diagnostic): HarnessDiagnostic {
@@ -802,9 +921,7 @@ module Harness {
return errorOutput;
}
export function getErrorBaseline(inputFiles: { unitName: string; content: string }[],
diagnostics: HarnessDiagnostic[]
) {
export function getErrorBaseline(inputFiles: { unitName: string; content: string }[], diagnostics: HarnessDiagnostic[]) {
var outputLines: string[] = [];
// Count up all the errors we find so we don't miss any
@@ -815,13 +932,13 @@ module Harness {
.split('\n')
.map(s => s.length > 0 && s.charAt(s.length - 1) === '\r' ? s.substr(0, s.length - 1) : s)
.filter(s => s.length > 0)
.map(s => '!!! ' + s);
.map(s => '!!! ' + error.category + " TS" + error.code + ": " + s);
errLines.forEach(e => outputLines.push(e));
totalErrorsReported++;
}
// Report glovbal errors:
// Report global errors
var globalErrors = diagnostics.filter(err => !err.filename);
globalErrors.forEach(err => outputErrorText(err));
@@ -843,7 +960,7 @@ module Harness {
// Note: IE JS engine incorrectly handles consecutive delimiters here when using RegExp split, so
// we have to string-based splitting instead and try to figure out the delimiting chars
var lineStarts = ts.getLineStarts(inputFile.content);
var lineStarts = ts.computeLineStarts(inputFile.content);
var lines = inputFile.content.split('\n');
lines.forEach((line, lineIndex) => {
if (line.length > 0 && line.charAt(line.length - 1) === '\r') {
@@ -888,10 +1005,15 @@ module Harness {
assert.equal(markedErrorCount, fileErrors.length, 'count of errors in ' + inputFile.unitName);
});
// Verify we didn't miss any errors in total
assert.equal(totalErrorsReported, diagnostics.length, 'total number of errors');
var numLibraryDiagnostics = ts.countWhere(diagnostics, diagnostic => {
return diagnostic.filename && isLibraryFile(diagnostic.filename);
});
return outputLines.join('\r\n');
// Verify we didn't miss any errors in total
assert.equal(totalErrorsReported + numLibraryDiagnostics, diagnostics.length, 'total number of errors');
return minimalDiagnosticsToString(diagnostics) +
sys.newLine + sys.newLine + outputLines.join('\r\n');
}
/* TODO: Delete?
@@ -908,11 +1030,7 @@ module Harness {
}
*/
/** Recreate the harness compiler instance to its default settings */
export function recreate(options?: { useMinimalDefaultLib: boolean; noImplicitAny: boolean; }) {
}
/** The harness' compiler instance used when tests are actually run. Reseting or changing settings of this compiler instance must be done within a testcase (i.e., describe/it) */
/** The harness' compiler instance used when tests are actually run. Reseting or changing settings of this compiler instance must be done within a test case (i.e., describe/it) */
var harnessCompiler: HarnessCompiler;
/** Returns the singleton harness compiler instance for generating and running tests.
@@ -951,6 +1069,10 @@ module Harness {
return str.substr(str.length - end.length) === end;
}
export function isTS(fileName: string) {
return stringEndsWith(fileName, '.ts');
}
export function isDTS(fileName: string) {
return stringEndsWith(fileName, '.d.ts');
}
@@ -969,11 +1091,10 @@ module Harness {
public errors: HarnessDiagnostic[] = [];
public declFilesCode: GeneratedFile[] = [];
public sourceMaps: GeneratedFile[] = [];
public sourceMapRecord: string;
/** @param fileResults an array of strings for the fileName and an ITextWriter with its code */
constructor(fileResults: GeneratedFile[], errors: HarnessDiagnostic[], sourceMapRecordLines: string[]) {
var lines: string[] = [];
constructor(fileResults: GeneratedFile[], errors: HarnessDiagnostic[], public program: ts.Program,
public currentDirectoryForProgram: string, private sourceMapData: ts.SourceMapData[]) {
fileResults.forEach(emittedFile => {
if (isDTS(emittedFile.fileName)) {
@@ -990,12 +1111,11 @@ module Harness {
});
this.errors = errors;
this.sourceMapRecord = sourceMapRecordLines.join('\r\n');
}
public updateSourceMapRecord(program: ts.Program, sourceMapData: ts.SourceMapData[]) {
if (sourceMapData) {
this.sourceMapRecord = Harness.SourceMapRecoder.getSourceMapRecord(sourceMapData, program, this.files);
public getSourceMapRecord() {
if (this.sourceMapData) {
return Harness.SourceMapRecoder.getSourceMapRecord(this.sourceMapData, this.program, this.files);
}
}
@@ -1011,7 +1131,7 @@ module Harness {
}
export module TestCaseParser {
/** all the necesarry information to set the right compiler settings */
/** all the necessary information to set the right compiler settings */
export interface CompilerSetting {
flag: string;
value: string;
@@ -1030,7 +1150,7 @@ module Harness {
var optionRegex = /^[\/]{2}\s*@(\w+)\s*:\s*(\S*)/gm; // multiple matches on multiple lines
// List of allowed metadata names
var fileMetadataNames = ["filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outDir", "noimplicitany", "noresolve", "newline", "newlines", "emitbom"];
var fileMetadataNames = ["filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outdir", "noemitonerror","noimplicitany", "noresolve", "newline", "newlines", "emitbom", "errortruncation", "usecasesensitivefilenames", "preserveconstenums"];
function extractCompilerSettings(content: string): CompilerSetting[] {
@@ -1049,7 +1169,7 @@ module Harness {
var settings = extractCompilerSettings(code);
// List of all the subfiles we've parsed out
var files: TestUnitData[] = [];
var testUnitData: TestUnitData[] = [];
var lines = Utils.splitContentByNewlines(code);
@@ -1085,7 +1205,7 @@ module Harness {
originalFilePath: fileName,
references: refs
};
files.push(newTestFile);
testUnitData.push(newTestFile);
// Reset local data
currentFileContent = null;
@@ -1110,7 +1230,7 @@ module Harness {
}
// normalize the fileName for the single file case
currentFileName = files.length > 0 ? currentFileName : Path.getFileName(fileName);
currentFileName = testUnitData.length > 0 ? currentFileName : Path.getFileName(fileName);
// EOF, push whatever remains
var newTestFile2 = {
@@ -1120,15 +1240,14 @@ module Harness {
originalFilePath: fileName,
references: refs
};
files.push(newTestFile2);
testUnitData.push(newTestFile2);
return { settings: settings, testUnitData: files };
return { settings, testUnitData };
}
}
/** Support class for baseline files */
export module Baseline {
var firstRun = true;
export interface BaselineOptions {
LineEndingSensitive?: boolean;
@@ -1169,8 +1288,7 @@ module Harness {
IO.createDirectory(dirName);
fileCache[dirName] = true;
}
var parentDir = IO.directoryName(actualFilename); // .../tests/baselines/local
var parentParentDir = IO.directoryName(IO.directoryName(actualFilename)) // .../tests/baselines
// Create folders if needed
createDirectoryStructure(Harness.IO.directoryName(actualFilename));
@@ -1220,7 +1338,7 @@ module Harness {
actual = actual.replace(/\r\n?/g, '\n');
}
return { expected: expected, actual: actual };
return { expected, actual };
}
function writeComparison(expected: string, actual: string, relativeFilename: string, actualFilename: string, descriptionForDescribe: string) {
+45 -24
View File
@@ -4,8 +4,8 @@
module Harness.LanguageService {
export class ScriptInfo {
public version: number = 1;
public editRanges: { length: number; textChangeRange: TypeScript.TextChangeRange; }[] = [];
public lineMap: TypeScript.LineMap = null;
public editRanges: { length: number; textChangeRange: ts.TextChangeRange; }[] = [];
public lineMap: number[] = null;
constructor(public fileName: string, public content: string, public isOpen = true) {
this.setContent(content);
@@ -13,7 +13,7 @@ module Harness.LanguageService {
private setContent(content: string): void {
this.content = content;
this.lineMap = TypeScript.LineMap1.fromString(content);
this.lineMap = ts.computeLineStarts(content);
}
public updateContent(content: string): void {
@@ -32,30 +32,30 @@ module Harness.LanguageService {
// Store edit range + new length of script
this.editRanges.push({
length: this.content.length,
textChangeRange: new TypeScript.TextChangeRange(
TypeScript.TextSpan.fromBounds(minChar, limChar), newText.length)
textChangeRange: new ts.TextChangeRange(
ts.TextSpan.fromBounds(minChar, limChar), newText.length)
});
// Update version #
this.version++;
}
public getTextChangeRangeBetweenVersions(startVersion: number, endVersion: number): TypeScript.TextChangeRange {
public getTextChangeRangeBetweenVersions(startVersion: number, endVersion: number): ts.TextChangeRange {
if (startVersion === endVersion) {
// No edits!
return TypeScript.TextChangeRange.unchanged;
return ts.TextChangeRange.unchanged;
}
var initialEditRangeIndex = this.editRanges.length - (this.version - startVersion);
var lastEditRangeIndex = this.editRanges.length - (this.version - endVersion);
var entries = this.editRanges.slice(initialEditRangeIndex, lastEditRangeIndex);
return TypeScript.TextChangeRange.collapseChangesAcrossMultipleVersions(entries.map(e => e.textChangeRange));
return ts.TextChangeRange.collapseChangesAcrossMultipleVersions(entries.map(e => e.textChangeRange));
}
}
class ScriptSnapshotShim implements ts.ScriptSnapshotShim {
private lineMap: TypeScript.LineMap = null;
private lineMap: number[] = null;
private textSnapshot: string;
private version: number;
@@ -74,10 +74,10 @@ module Harness.LanguageService {
public getLineStartPositions(): string {
if (this.lineMap === null) {
this.lineMap = TypeScript.LineMap1.fromString(this.textSnapshot);
this.lineMap = ts.computeLineStarts(this.textSnapshot);
}
return JSON.stringify(this.lineMap.lineStarts());
return JSON.stringify(this.lineMap);
}
public getChangeRange(oldScript: ts.ScriptSnapshotShim): string {
@@ -108,7 +108,7 @@ module Harness.LanguageService {
public acquireDocument(
fileName: string,
compilationSettings: ts.CompilerOptions,
scriptSnapshot: TypeScript.IScriptSnapshot,
scriptSnapshot: ts.IScriptSnapshot,
version: string,
isOpen: boolean): ts.SourceFile {
return ts.createSourceFile(fileName, scriptSnapshot.getText(0, scriptSnapshot.getLength()), compilationSettings.target, version, isOpen);
@@ -118,10 +118,10 @@ module Harness.LanguageService {
document: ts.SourceFile,
fileName: string,
compilationSettings: ts.CompilerOptions,
scriptSnapshot: TypeScript.IScriptSnapshot,
scriptSnapshot: ts.IScriptSnapshot,
version: string,
isOpen: boolean,
textChangeRange: TypeScript.TextChangeRange
textChangeRange: ts.TextChangeRange
): ts.SourceFile {
return document.update(scriptSnapshot, version, isOpen, textChangeRange);
}
@@ -134,6 +134,7 @@ module Harness.LanguageService {
private ls: ts.LanguageServiceShim = null;
private fileNameToScript: ts.Map<ScriptInfo> = {};
private settings: ts.CompilationSettings = {};
constructor(private cancellationToken: ts.CancellationToken = CancellationToken.None) {
}
@@ -199,13 +200,21 @@ module Harness.LanguageService {
/// Returns json for Tools.CompilationSettings
public getCompilationSettings(): string {
return JSON.stringify({}); // i.e. default settings
return JSON.stringify(this.settings);
}
public getCancellationToken(): ts.CancellationToken {
return this.cancellationToken;
}
public getCurrentDirectory(): string {
return "";
}
public getDefaultLibFilename(): string {
return "";
}
public getScriptFileNames(): string {
var fileNames: string[] = [];
ts.forEachKey(this.fileNameToScript, (fileName) => { fileNames.push(fileName); });
@@ -236,19 +245,31 @@ module Harness.LanguageService {
return this.ls;
}
public setCompilationSettings(settings: ts.CompilationSettings) {
for (var key in settings) {
if (settings.hasOwnProperty(key)) {
this.settings[key] = settings[key];
}
}
}
/** Return a new instance of the classifier service shim */
public getClassifier(): ts.ClassifierShim {
return new TypeScript.Services.TypeScriptServicesFactory().createClassifierShim(this);
}
public getCoreService(): ts.CoreServicesShim {
return new TypeScript.Services.TypeScriptServicesFactory().createCoreServicesShim(this);
}
/** Parse file given its source text */
public parseSourceText(fileName: string, sourceText: TypeScript.IScriptSnapshot): TypeScript.SourceUnitSyntax {
return TypeScript.Parser.parse(fileName, TypeScript.SimpleText.fromScriptSnapshot(sourceText), ts.ScriptTarget.ES5, TypeScript.isDTSFile(fileName)).sourceUnit();
public parseSourceText(fileName: string, sourceText: ts.IScriptSnapshot): ts.SourceFile {
return ts.createSourceFile(fileName, sourceText.getText(0, sourceText.getLength()), ts.ScriptTarget.Latest, "1", true);
}
/** Parse a file on disk given its fileName */
public parseFile(fileName: string) {
var sourceText = TypeScript.ScriptSnapshot.fromString(Harness.IO.readFile(fileName));
var sourceText = ts.ScriptSnapshot.fromString(Harness.IO.readFile(fileName));
return this.parseSourceText(fileName, sourceText);
}
@@ -262,22 +283,22 @@ module Harness.LanguageService {
assert.isTrue(line >= 1);
assert.isTrue(col >= 1);
return script.lineMap.getPosition(line - 1, col - 1);
return ts.getPositionFromLineAndCharacter(script.lineMap, line, col);
}
/**
* @param line 0 based index
* @param col 0 based index
*/
public positionToZeroBasedLineCol(fileName: string, position: number): TypeScript.ILineAndCharacter {
public positionToZeroBasedLineCol(fileName: string, position: number): ts.LineAndCharacter {
var script: ScriptInfo = this.fileNameToScript[fileName];
assert.isNotNull(script);
var result = script.lineMap.getLineAndCharacterFromPosition(position);
var result = ts.getLineAndCharacterOfPosition(script.lineMap, position);
assert.isTrue(result.line() >= 0);
assert.isTrue(result.character() >= 0);
return { line: result.line(), character: result.character() };
assert.isTrue(result.line >= 1);
assert.isTrue(result.character >= 1);
return { line: result.line - 1, character: result.character - 1 };
}
/** Verify that applying edits to sourceFileName result in the content of the file baselineFileName */
+3 -3
View File
@@ -175,10 +175,10 @@ module Playback {
}
function findResultByPath<T>(wrapper: { resolvePath(s: string): string }, logArray: { path: string; result?: T }[], expectedPath: string, defaultValue?: T): T {
var normalizedName = Harness.Path.switchToForwardSlashes(expectedPath).toLowerCase();
var normalizedName = ts.normalizeSlashes(expectedPath).toLowerCase();
// Try to find the result through normal filename
for (var i = 0; i < logArray.length; i++) {
if (Harness.Path.switchToForwardSlashes(logArray[i].path).toLowerCase() === normalizedName) {
if (ts.normalizeSlashes(logArray[i].path).toLowerCase() === normalizedName) {
return logArray[i].result;
}
}
@@ -203,7 +203,7 @@ module Playback {
function pathsAreEquivalent(left: string, right: string, wrapper: { resolvePath(s: string): string }) {
var key = left + '-~~-' + right;
function areSame(a: string, b: string) {
return Harness.Path.switchToForwardSlashes(a).toLowerCase() === Harness.Path.switchToForwardSlashes(b).toLowerCase();
return ts.normalizeSlashes(a).toLowerCase() === ts.normalizeSlashes(b).toLowerCase();
}
function check() {
if (Harness.Path.getFileName(left).toLowerCase() === Harness.Path.getFileName(right).toLowerCase()) {
+64 -29
View File
@@ -4,7 +4,7 @@
// Test case is json of below type in tests/cases/project/
interface ProjectRunnerTestCase {
scenario: string;
projectRoot: string; // project where it lives - this also is the current dictory when compiling
projectRoot: string; // project where it lives - this also is the current directory when compiling
inputFiles: string[]; // list of input files to be given to program
out?: string; // --out
outDir?: string; // --outDir
@@ -17,12 +17,13 @@ interface ProjectRunnerTestCase {
baselineCheck?: boolean; // Verify the baselines of output files, if this is false, we will write to output to the disk but there is no verification of baselines
runTest?: boolean; // Run the resulting test
bug?: string; // If there is any bug associated with this test case
noResolve?: boolean;
}
interface ProjectRunnerTestCaseResolutionInfo extends ProjectRunnerTestCase {
// Apart from actual test case the results of the resolution
resolvedInputFiles: string[]; // List of files that were asked to read by compiler
emittedFiles: string[]; // List of files that wre emitted by the compiler
emittedFiles: string[]; // List of files that were emitted by the compiler
}
interface BatchCompileProjectTestCaseEmittedFile extends Harness.Compiler.GeneratedFile {
@@ -69,7 +70,7 @@ class ProjectRunner extends RunnerBase {
testCase = <ProjectRunnerTestCase>JSON.parse(testFileText);
}
catch (e) {
assert(false, "Testcase: " + testCaseFileName + " doesnt not contain valid json format: " + e.message);
assert(false, "Testcase: " + testCaseFileName + " does not contain valid json format: " + e.message);
}
var testCaseJustName = testCaseFileName.replace(/^.*[\\\/]/, '').replace(/\.json/, "");
@@ -87,7 +88,7 @@ class ProjectRunner extends RunnerBase {
}
// When test case output goes to tests/baselines/local/projectOutput/testCaseName/moduleKind/
// We have these two separate locations because when compairing baselines the baseline verifier will delete the existing file
// We have these two separate locations because when comparing baselines the baseline verifier will delete the existing file
// so even if it was created by compiler in that location, the file will be deleted by verified before we can read it
// so lets keep these two locations separate
function getProjectOutputFolder(filename: string, moduleKind: ts.ModuleKind) {
@@ -132,7 +133,7 @@ class ProjectRunner extends RunnerBase {
var checker = program.getTypeChecker(/*fullTypeCheck*/ true);
errors = checker.getDiagnostics();
var emitResult = checker.emitFiles();
errors = ts.concatenate(errors, emitResult.errors);
errors = ts.concatenate(errors, emitResult.diagnostics);
sourceMapData = emitResult.sourceMaps;
// Clean up source map data that will be used in baselining
@@ -148,10 +149,10 @@ class ProjectRunner extends RunnerBase {
}
return {
moduleKind: moduleKind,
program: program,
errors: errors,
sourceMapData: sourceMapData
moduleKind,
program,
errors,
sourceMapData
};
function createCompilerOptions(): ts.CompilerOptions {
@@ -162,7 +163,8 @@ class ProjectRunner extends RunnerBase {
outDir: testCase.outDir,
mapRoot: testCase.resolveMapRoot && testCase.mapRoot ? sys.resolvePath(testCase.mapRoot) : testCase.mapRoot,
sourceRoot: testCase.resolveSourceRoot && testCase.sourceRoot ? sys.resolvePath(testCase.sourceRoot) : testCase.sourceRoot,
module: moduleKind
module: moduleKind,
noResolve: testCase.noResolve
};
}
@@ -183,10 +185,10 @@ class ProjectRunner extends RunnerBase {
function createCompilerHost(): ts.CompilerHost {
return {
getSourceFile: getSourceFile,
getSourceFile,
getDefaultLibFilename: () => "lib.d.ts",
writeFile: writeFile,
getCurrentDirectory: getCurrentDirectory,
writeFile,
getCurrentDirectory,
getCanonicalFileName: Harness.Compiler.getCanonicalFileName,
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
getNewLine: () => sys.newLine
@@ -201,12 +203,12 @@ class ProjectRunner extends RunnerBase {
var projectCompilerResult = compileProjectFiles(moduleKind, () => testCase.inputFiles, getSourceFileText, writeFile);
return {
moduleKind: moduleKind,
moduleKind,
program: projectCompilerResult.program,
sourceMapData: projectCompilerResult.sourceMapData,
outputFiles: outputFiles,
outputFiles,
errors: projectCompilerResult.errors,
nonSubfolderDiskFiles: nonSubfolderDiskFiles,
nonSubfolderDiskFiles,
};
function getSourceFileText(filename: string): string {
@@ -226,9 +228,10 @@ class ProjectRunner extends RunnerBase {
? filename
: ts.normalizeSlashes(testCase.projectRoot) + "/" + ts.normalizeSlashes(filename);
var diskRelativeName = ts.getRelativePathToDirectoryOrUrl(testCase.projectRoot, diskFileName, getCurrentDirectory(), false);
var diskRelativeName = ts.getRelativePathToDirectoryOrUrl(testCase.projectRoot, diskFileName,
getCurrentDirectory(), Harness.Compiler.getCanonicalFileName, /*isAbsolutePathAnUrl*/ false);
if (ts.isRootedDiskPath(diskRelativeName) || diskRelativeName.substr(0, 3) === "../") {
// If the generated output file recides in the parent folder or is rooted path,
// If the generated output file resides in the parent folder or is rooted path,
// we need to instead create files that can live in the project reference folder
// but make sure extension of these files matches with the filename the compiler asked to write
diskRelativeName = "diskFile" + nonSubfolderDiskFiles++ +
@@ -271,16 +274,40 @@ class ProjectRunner extends RunnerBase {
}
function compileCompileDTsFiles(compilerResult: BatchCompileProjectTestCaseResult) {
var inputDtsSourceFiles = ts.map(ts.filter(compilerResult.program.getSourceFiles(),
sourceFile => Harness.Compiler.isDTS(sourceFile.filename)),
sourceFile => {
return { emittedFileName: sourceFile.filename, code: sourceFile.text };
});
var allInputFiles: { emittedFileName: string; code: string; }[] = [];
var compilerOptions = compilerResult.program.getCompilerOptions();
var compilerHost = compilerResult.program.getCompilerHost();
ts.forEach(compilerResult.program.getSourceFiles(), sourceFile => {
if (Harness.Compiler.isDTS(sourceFile.filename)) {
allInputFiles.unshift({ emittedFileName: sourceFile.filename, code: sourceFile.text });
}
else if (ts.shouldEmitToOwnFile(sourceFile, compilerResult.program.getCompilerOptions())) {
if (compilerOptions.outDir) {
var sourceFilePath = ts.getNormalizedAbsolutePath(sourceFile.filename, compilerHost.getCurrentDirectory());
sourceFilePath = sourceFilePath.replace(compilerResult.program.getCommonSourceDirectory(), "");
var emitOutputFilePathWithoutExtension = ts.removeFileExtension(ts.combinePaths(compilerOptions.outDir, sourceFilePath));
}
else {
var emitOutputFilePathWithoutExtension = ts.removeFileExtension(sourceFile.filename);
}
var outputDtsFileName = emitOutputFilePathWithoutExtension + ".d.ts";
allInputFiles.unshift(findOutpuDtsFile(outputDtsFileName));
}
else {
var outputDtsFileName = ts.removeFileExtension(compilerOptions.out) + ".d.ts";
var outputDtsFile = findOutpuDtsFile(outputDtsFileName);
if (!ts.contains(allInputFiles, outputDtsFile)) {
allInputFiles.unshift(outputDtsFile);
}
}
});
var ouputDtsFiles = ts.filter(compilerResult.outputFiles, ouputFile => Harness.Compiler.isDTS(ouputFile.emittedFileName));
var allInputFiles = inputDtsSourceFiles.concat(ouputDtsFiles);
return compileProjectFiles(compilerResult.moduleKind,getInputFiles, getSourceFileText, writeFile);
function findOutpuDtsFile(fileName: string) {
return ts.forEach(compilerResult.outputFiles, outputFile => outputFile.emittedFileName === fileName ? outputFile : undefined);
}
function getInputFiles() {
return ts.map(allInputFiles, outputFile => outputFile.emittedFileName);
}
@@ -299,13 +326,11 @@ class ProjectRunner extends RunnerBase {
return { unitName: sourceFile.filename, content: sourceFile.text };
});
var diagnostics = ts.map(compilerResult.errors, error => Harness.Compiler.getMinimalDiagnostic(error));
var errors = Harness.Compiler.minimalDiagnosticsToString(diagnostics);
errors += sys.newLine + sys.newLine + Harness.Compiler.getErrorBaseline(inputFiles, diagnostics);
return errors;
return Harness.Compiler.getErrorBaseline(inputFiles, diagnostics);
}
describe('Compiling project for ' + testCase.scenario +': testcase ' + testCaseFileName, () => {
describe('Compiling project for ' + testCase.scenario + ': testcase ' + testCaseFileName, () => {
function verifyCompilerResults(compilerResult: BatchCompileProjectTestCaseResult) {
function getCompilerResolutionInfo() {
var resolutionInfo: ProjectRunnerTestCaseResolutionInfo = {
@@ -420,6 +445,16 @@ class ProjectRunner extends RunnerBase {
// })
//});
}
after(() => {
// Mocha holds onto the closure environment of the describe callback even after the test is done.
// Therefore we have to clean out large objects after the test is done.
nodeCompilerResult = undefined;
amdCompilerResult = undefined;
testCase = undefined;
testFileText = undefined;
testCaseJustName = undefined;
});
});
}
}
-7
View File
@@ -18,7 +18,6 @@
// ///<reference path='fourslashRunner.ts' />
/// <reference path='projectsRunner.ts' />
/// <reference path='rwcRunner.ts' />
/// <reference path='unittestrunner.ts' />
function runTests(runners: RunnerBase[]) {
if (reverse) {
@@ -67,9 +66,6 @@ if (testConfigFile !== '') {
case 'fourslash-generated':
runners.push(new GeneratedFourslashRunner());
break;
case 'unittests':
runners.push(new UnitTestRunner());
break;
case 'rwc':
runners.push(new RWCRunner());
break;
@@ -93,9 +89,6 @@ if (runners.length === 0) {
// language services
runners.push(new FourslashRunner());
//runners.push(new GeneratedFourslashRunner());
// unittests
runners.push(new UnitTestRunner());
}
sys.newLine = '\r\n';
+139 -114
View File
@@ -23,7 +23,7 @@ module RWC {
function collateOutputs(outputFiles: Harness.Compiler.GeneratedFile[], clean?: (s: string) => string) {
// Collect, test, and sort the filenames
function cleanName(fn: string) {
var lastSlash = Harness.Path.switchToForwardSlashes(fn).lastIndexOf('/');
var lastSlash = ts.normalizeSlashes(fn).lastIndexOf('/');
return fn.substr(lastSlash + 1).toLowerCase();
}
outputFiles.sort((a, b) => cleanName(a.fileName).localeCompare(cleanName(b.fileName)));
@@ -46,146 +46,171 @@ module RWC {
}
export function runRWCTest(jsonPath: string) {
var harnessCompiler = Harness.Compiler.getCompiler();
var opts: ts.ParsedCommandLine;
describe("Testing a RWC project: " + jsonPath, () => {
var inputFiles: { unitName: string; content: string; }[] = [];
var otherFiles: { unitName: string; content: string; }[] = [];
var compilerResult: Harness.Compiler.CompilerResult;
var compilerOptions: ts.CompilerOptions;
var baselineOpts: Harness.Baseline.BaselineOptions = { Subfolder: 'rwc' };
var baseName = /(.*)\/(.*).json/.exec(ts.normalizeSlashes(jsonPath))[2];
// Compile .d.ts files
var declFileCompilationResult: {
declInputFiles: { unitName: string; content: string }[];
declOtherFiles: { unitName: string; content: string }[];
declResult: Harness.Compiler.CompilerResult;
};
var ioLog: IOLog = JSON.parse(Harness.IO.readFile(jsonPath));
var errors = '';
it('has parsable options', () => {
runWithIOLog(ioLog, () => {
opts = ts.parseCommandLine(ioLog.arguments);
assert.equal(opts.errors.length, 0);
});
});
var inputFiles: { unitName: string; content: string; }[] = [];
var otherFiles: { unitName: string; content: string; }[] = [];
var compilerResult: Harness.Compiler.CompilerResult;
it('can compile', () => {
runWithIOLog(ioLog, () => {
harnessCompiler.reset();
// Load the files
ts.forEach(opts.filenames, fileName => {
inputFiles.push(getHarnessCompilerInputUnit(fileName));
});
if (!opts.options.noLib) {
// Find the lib.d.ts file in the input file and add it to the input files list
var libFile = ts.forEach(ioLog.filesRead, fileRead=> Harness.isLibraryFile(fileRead.path) ? fileRead.path : undefined);
if (libFile) {
inputFiles.push(getHarnessCompilerInputUnit(libFile));
}
}
ts.forEach(ioLog.filesRead, fileRead => {
var resolvedPath = Harness.Path.switchToForwardSlashes(sys.resolvePath(fileRead.path));
var inInputList = ts.forEach(inputFiles, inputFile=> inputFile.unitName === resolvedPath);
if (!inInputList) {
// Add the file to other files
otherFiles.push(getHarnessCompilerInputUnit(fileRead.path));
}
});
// do not use lib since we already read it in above
opts.options.noLib = true;
// Emit the results
harnessCompiler.compileFiles(inputFiles, otherFiles, compileResult => {
compilerResult = compileResult;
}, /*settingsCallback*/ undefined, opts.options);
after(() => {
// Mocha holds onto the closure environment of the describe callback even after the test is done.
// Therefore we have to clean out large objects after the test is done.
inputFiles = undefined;
otherFiles = undefined;
compilerResult = undefined;
compilerOptions = undefined;
baselineOpts = undefined;
baseName = undefined;
declFileCompilationResult = undefined;
});
function getHarnessCompilerInputUnit(fileName: string) {
var resolvedPath = Harness.Path.switchToForwardSlashes(sys.resolvePath(fileName));
try {
var content = sys.readFile(resolvedPath);
it('can compile', () => {
var harnessCompiler = Harness.Compiler.getCompiler();
var opts: ts.ParsedCommandLine;
var ioLog: IOLog = JSON.parse(Harness.IO.readFile(jsonPath));
runWithIOLog(ioLog, () => {
opts = ts.parseCommandLine(ioLog.arguments);
assert.equal(opts.errors.length, 0);
});
runWithIOLog(ioLog, () => {
harnessCompiler.reset();
// Load the files
ts.forEach(opts.filenames, fileName => {
inputFiles.push(getHarnessCompilerInputUnit(fileName));
});
if (!opts.options.noLib) {
// Find the lib.d.ts file in the input file and add it to the input files list
var libFile = ts.forEach(ioLog.filesRead, fileRead=> Harness.isLibraryFile(fileRead.path) ? fileRead.path : undefined);
if (libFile) {
inputFiles.push(getHarnessCompilerInputUnit(libFile));
}
}
ts.forEach(ioLog.filesRead, fileRead => {
var resolvedPath = ts.normalizeSlashes(sys.resolvePath(fileRead.path));
var inInputList = ts.forEach(inputFiles, inputFile=> inputFile.unitName === resolvedPath);
if (!inInputList) {
// Add the file to other files
otherFiles.push(getHarnessCompilerInputUnit(fileRead.path));
}
});
// do not use lib since we already read it in above
opts.options.noLib = true;
// Emit the results
compilerOptions = harnessCompiler.compileFiles(inputFiles, otherFiles, compileResult => {
compilerResult = compileResult;
}, /*settingsCallback*/ undefined, opts.options);
});
function getHarnessCompilerInputUnit(fileName: string) {
var unitName = ts.normalizeSlashes(sys.resolvePath(fileName));
try {
var content = sys.readFile(unitName);
}
catch (e) {
// Leave content undefined.
}
return { unitName, content };
}
catch (e) {
// Leave content undefined.
}
return { unitName: resolvedPath, content: content };
}
});
});
// Baselines
var baselineOpts: Harness.Baseline.BaselineOptions = { Subfolder: 'rwc' };
var baseName = /(.*)\/(.*).json/.exec(Harness.Path.switchToForwardSlashes(jsonPath))[2];
// Baselines
it('Correct compiler generated.d.ts', () => {
declFileCompilationResult = Harness.Compiler.getCompiler().compileDeclarationFiles(inputFiles, otherFiles, compilerResult, /*settingscallback*/ undefined, compilerOptions);
});
it('has the expected emitted code', () => {
Harness.Baseline.runBaseline('has the expected emitted code', baseName + '.output.js', () => {
return collateOutputs(compilerResult.files, s => SyntacticCleaner.clean(s));
}, false, baselineOpts);
});
it('has the expected declaration file content', () => {
Harness.Baseline.runBaseline('has the expected declaration file content', baseName + '.d.ts', () => {
if (compilerResult.errors.length || !compilerResult.declFilesCode.length) {
return null;
}
return collateOutputs(compilerResult.declFilesCode);
}, false, baselineOpts);
});
it('has the expected source maps', () => {
Harness.Baseline.runBaseline('has the expected source maps', baseName + '.map', () => {
if (!compilerResult.sourceMaps.length) {
return null;
}
return collateOutputs(compilerResult.sourceMaps);
}, false, baselineOpts);
});
it('has correct source map record', () => {
if (compilerResult.sourceMapRecord) {
Harness.Baseline.runBaseline('has correct source map record', baseName + '.sourcemap.txt', () => {
return compilerResult.sourceMapRecord;
it('has the expected emitted code', () => {
Harness.Baseline.runBaseline('has the expected emitted code', baseName + '.output.js', () => {
return collateOutputs(compilerResult.files, s => SyntacticCleaner.clean(s));
}, false, baselineOpts);
}
});
});
it('has the expected errors', () => {
Harness.Baseline.runBaseline('has the expected errors', baseName + '.errors.txt', () => {
if (compilerResult.errors.length === 0) {
return null;
it('has the expected declaration file content', () => {
Harness.Baseline.runBaseline('has the expected declaration file content', baseName + '.d.ts', () => {
if (compilerResult.errors.length || !compilerResult.declFilesCode.length) {
return null;
}
return collateOutputs(compilerResult.declFilesCode);
}, false, baselineOpts);
});
it('has the expected source maps', () => {
Harness.Baseline.runBaseline('has the expected source maps', baseName + '.map', () => {
if (!compilerResult.sourceMaps.length) {
return null;
}
return collateOutputs(compilerResult.sourceMaps);
}, false, baselineOpts);
});
//it('has correct source map record', () => {
// if (compilerOptions.sourceMap) {
// Harness.Baseline.runBaseline('has correct source map record', baseName + '.sourcemap.txt', () => {
// return compilerResult.getSourceMapRecord();
// }, false, baselineOpts);
// }
//});
it('has the expected errors', () => {
Harness.Baseline.runBaseline('has the expected errors', baseName + '.errors.txt', () => {
if (compilerResult.errors.length === 0) {
return null;
}
return Harness.Compiler.getErrorBaseline(inputFiles.concat(otherFiles), compilerResult.errors);
}, false, baselineOpts);
});
it('has no errors in generated declaration files', () => {
if (compilerOptions.declaration && !compilerResult.errors.length) {
Harness.Baseline.runBaseline('has no errors in generated declaration files', baseName + '.dts.errors.txt', () => {
if (declFileCompilationResult.declResult.errors.length === 0) {
return null;
}
return Harness.Compiler.minimalDiagnosticsToString(declFileCompilationResult.declResult.errors) +
sys.newLine + sys.newLine +
Harness.Compiler.getErrorBaseline(declFileCompilationResult.declInputFiles.concat(declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
}, false, baselineOpts);
}
});
return Harness.Compiler.minimalDiagnosticsToString(compilerResult.errors) +
sys.newLine + sys.newLine +
Harness.Compiler.getErrorBaseline(inputFiles.concat(otherFiles), compilerResult.errors);
}, false, baselineOpts);
// TODO: Type baselines (need to refactor out from compilerRunner)
});
// TODO: Type baselines (need to refactor out from compilerRunner)
}
}
class RWCRunner extends RunnerBase {
private runnerPath = "tests/runners/rwc";
private sourcePath = "tests/cases/rwc/";
private harnessCompiler: Harness.Compiler.HarnessCompiler;
private static sourcePath = "tests/cases/rwc/";
/** Setup the runner's tests so that they are ready to be executed by the harness
* The first test should be a describe/it block that sets up the harness's compiler instance appropriately
*/
public initializeTests(): void {
// Recreate the compiler with the default lib
Harness.Compiler.recreate({ useMinimalDefaultLib: false, noImplicitAny: false });
this.harnessCompiler = Harness.Compiler.getCompiler();
// Read in and evaluate the test list
var testList = Harness.IO.listFiles(this.sourcePath, /.+\.json$/);
var testList = Harness.IO.listFiles(RWCRunner.sourcePath, /.+\.json$/);
for (var i = 0; i < testList.length; i++) {
this.runTest(testList[i]);
}
}
private runTest(jsonFilename: string) {
describe("Testing a RWC project: " + jsonFilename, () => {
RWC.runRWCTest(jsonFilename);
});
RWC.runRWCTest(jsonFilename);
}
}
+3 -3
View File
@@ -223,7 +223,7 @@ module Harness.SourceMapRecoder {
sourceMapNames = sourceMapData.sourceMapNames;
jsFile = currentJsFile;
jsLineMap = ts.getLineStarts(jsFile.code);
jsLineMap = ts.computeLineStarts(jsFile.code);
spansOnSingleLine = [];
prevWrittenSourcePos = 0;
@@ -294,7 +294,7 @@ module Harness.SourceMapRecoder {
sourceMapRecoder.WriteLine("sourceFile:" + sourceMapSources[spansOnSingleLine[0].sourceMapSpan.sourceIndex]);
sourceMapRecoder.WriteLine("-------------------------------------------------------------------");
tsLineMap = ts.getLineStarts(newSourceFileCode);
tsLineMap = ts.computeLineStarts(newSourceFileCode);
tsCode = newSourceFileCode;
prevWrittenSourcePos = 0;
}
@@ -390,7 +390,7 @@ module Harness.SourceMapRecoder {
}
}
var tsCodeLineMap = ts.getLineStarts(sourceText);
var tsCodeLineMap = ts.computeLineStarts(sourceText);
for (var i = 0; i < tsCodeLineMap.length; i++) {
writeSourceMapIndent(prevEmittedCol, i == 0 ? markerIds[index] : " >");
sourceMapRecoder.Write(getTextOfLine(i, tsCodeLineMap, sourceText));
+7 -7
View File
@@ -1,7 +1,7 @@
interface TypeWriterResult {
line: number;
column: number;
syntaxKind: string;
syntaxKind: number;
sourceText: string;
type: string;
}
@@ -67,8 +67,8 @@ class TypeWriterWalker {
case ts.SyntaxKind.ContinueStatement:
case ts.SyntaxKind.BreakStatement:
return (<ts.BreakOrContinueStatement>parent).label === identifier;
case ts.SyntaxKind.LabelledStatement:
return (<ts.LabelledStatement>parent).label === identifier;
case ts.SyntaxKind.LabeledStatement:
return (<ts.LabeledStatement>parent).label === identifier;
}
return false;
}
@@ -76,7 +76,7 @@ class TypeWriterWalker {
private log(node: ts.Node, type: ts.Type): void {
var actualPos = ts.skipTrivia(this.currentSourceFile.text, node.pos);
var lineAndCharacter = this.currentSourceFile.getLineAndCharacterFromPosition(actualPos);
var sourceText = ts.getSourceTextOfNodeFromSourceText(this.currentSourceFile.text, node);
var sourceText = ts.getTextOfNodeFromSourceText(this.currentSourceFile.text, node);
// If we got an unknown type, we temporarily want to fall back to just pretending the name
// (source text) of the node is the type. This is to align with the old typeWriter to make
@@ -84,15 +84,15 @@ class TypeWriterWalker {
this.results.push({
line: lineAndCharacter.line - 1,
column: lineAndCharacter.character,
syntaxKind: ts.SyntaxKind[node.kind],
syntaxKind: node.kind,
sourceText: sourceText,
type: this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.None)
type: this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.WriteOwnNameForAnyLike)
});
}
private getTypeOfNode(node: ts.Node): ts.Type {
var type = this.checker.getTypeOfNode(node);
ts.Debug.assert(type, "type doesn't exist");
ts.Debug.assert(type !== undefined, "type doesn't exist");
return type;
}
}
-73
View File
@@ -1,73 +0,0 @@
///<reference path="harness.ts" />
///<reference path="runnerbase.ts" />
class UnitTestRunner extends RunnerBase {
constructor() {
super();
}
public initializeTests() {
this.tests = this.enumerateFiles('tests/cases/unittests/services');
var outfile = new Harness.Compiler.WriterAggregator()
var outerr = new Harness.Compiler.WriterAggregator();
// note this is running immediately to generate tests to be run later inside describe/it
// need a fresh instance so that the previous runner's last test is not hanging around
var harnessCompiler = Harness.Compiler.getCompiler({ useExistingInstance: false });
var toBeAdded = this.tests.map(test => {
return { unitName: test, content: Harness.IO.readFile(test) }
});
harnessCompiler.addInputFiles(toBeAdded);
harnessCompiler.setCompilerOptions({ noResolve: true });
var stdout = new Harness.Compiler.EmitterIOHost();
var emitDiagnostics = harnessCompiler.emitAll(stdout);
var results = stdout.toArray();
var lines: string[] = [];
results.forEach(v => lines = lines.concat(v.file.lines));
var code = lines.join("\n")
var nodeContext: any = undefined;
if (Utils.getExecutionEnvironment() === Utils.ExecutionEnvironment.Node) {
nodeContext = {
require: require,
process: process,
describe: describe,
it: it,
assert: assert,
beforeEach: beforeEach,
afterEach: afterEach,
before: before,
after: after,
Harness: Harness,
IO: Harness.IO,
ts: ts,
TypeScript: TypeScript
// FourSlash: FourSlash
};
}
describe("Setup compiler for compiler unittests", () => {
// ensures a clean compiler instance when tests are eventually executed following this describe block
harnessCompiler = Harness.Compiler.getCompiler({
useExistingInstance: false,
optionsForFreshInstance: { useMinimalDefaultLib: true, noImplicitAny: false }
});
});
// this generated code is a series of top level describe/it blocks that will run in between the setup and cleanup blocks in this file
Utils.evalFile(code, "generated_test_code.js", nodeContext);
describe("Cleanup after unittests", () => {
var harnessCompiler = Harness.Compiler.getCompiler({
useExistingInstance: false,
optionsForFreshInstance: { useMinimalDefaultLib: true, noImplicitAny: false }
});
});
// note this runs immediately (ie before this same code in the describe block above)
// to make sure the next runner doesn't include the previous one's stuff
harnessCompiler = Harness.Compiler.getCompiler({ useExistingInstance: false });
}
}
+4
View File
@@ -484,6 +484,10 @@ declare var Number: {
POSITIVE_INFINITY: number;
}
interface TemplateStringsArray extends Array<string> {
raw: string[];
}
interface Math {
/** The mathematical constant e. This is Euler's number, the base of natural logarithms. */
E: number;
+17 -12
View File
@@ -1886,6 +1886,23 @@ declare var HTMLCollection: {
new(): HTMLCollection;
}
interface BlobPropertyBag {
type?: string;
endings?: string;
}
interface Blob {
type: string;
size: number;
msDetachStream(): any;
slice(start?: number, end?: number, contentType?: string): Blob;
msClose(): void;
}
declare var Blob: {
prototype: Blob;
new (blobParts?: any[], options?: BlobPropertyBag): Blob;
}
interface NavigatorID {
appVersion: string;
appName: string;
@@ -10027,18 +10044,6 @@ declare var FileReader: {
new(): FileReader;
}
interface Blob {
type: string;
size: number;
msDetachStream(): any;
slice(start?: number, end?: number, contentType?: string): Blob;
msClose(): void;
}
declare var Blob: {
prototype: Blob;
new(): Blob;
}
interface ApplicationCache extends EventTarget {
status: number;
ondownloading: (ev: Event) => any;
+16 -16
View File
@@ -63,14 +63,14 @@ interface Int8Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Int8Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -121,14 +121,14 @@ interface Uint8Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Uint8Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -179,14 +179,14 @@ interface Int16Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Int16Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -237,14 +237,14 @@ interface Uint16Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Uint16Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -295,14 +295,14 @@ interface Int32Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Int32Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -353,14 +353,14 @@ interface Uint32Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Uint32Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -411,14 +411,14 @@ interface Float32Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Float32Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
@@ -469,14 +469,14 @@ interface Float64Array extends ArrayBufferView {
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: Float64Array, offset?: number): void;
/**
* Sets a value or an array of values.
* @param A typed or untyped array of values to set.
* @param array A typed or untyped array of values to set.
* @param offset The index in the current array at which the values are to be written.
*/
set(array: number[], offset?: number): void;
+6 -1
View File
@@ -614,6 +614,11 @@ declare var FileReader: {
new(): FileReader;
}
interface BlobPropertyBag {
type?: string;
endings?: string;
}
interface Blob {
type: string;
size: number;
@@ -623,7 +628,7 @@ interface Blob {
}
declare var Blob: {
prototype: Blob;
new(): Blob;
new (blobParts?: any[], options?: BlobPropertyBag): Blob;
}
interface MSStream {
-73
View File
@@ -1,73 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='references.ts' />
module TypeScript.Services {
export class BraceMatcher {
// Given a script name and position in the script, return a pair of text range if the
// position corresponds to a "brace matchin" characters (e.g. "{" or "(", etc.)
// If the position is not on any range, return an empty set.
public static getMatchSpans(syntaxTree: TypeScript.SyntaxTree, position: number): TypeScript.TextSpan[] {
var result: TypeScript.TextSpan[] = [];
var token = findToken(syntaxTree.sourceUnit(), position);
if (start(token) === position) {
var matchKind = BraceMatcher.getMatchingTokenKind(token);
if (matchKind !== null) {
var parentElement = token.parent;
for (var i = 0, n = childCount(parentElement); i < n; i++) {
var current = childAt(parentElement, i);
if (current !== null && fullWidth(current) > 0) {
if (current.kind() === matchKind) {
var range1 = new TypeScript.TextSpan(start(token), width(token));
var range2 = new TypeScript.TextSpan(start(current), width(current));
if (range1.start() < range2.start()) {
result.push(range1, range2);
}
else {
result.push(range2, range1);
}
break;
}
}
}
}
}
return result;
}
private static getMatchingTokenKind(token: TypeScript.ISyntaxToken): TypeScript.SyntaxKind {
switch (token.kind()) {
case TypeScript.SyntaxKind.OpenBraceToken: return TypeScript.SyntaxKind.CloseBraceToken
case TypeScript.SyntaxKind.OpenParenToken: return TypeScript.SyntaxKind.CloseParenToken;
case TypeScript.SyntaxKind.OpenBracketToken: return TypeScript.SyntaxKind.CloseBracketToken;
case TypeScript.SyntaxKind.LessThanToken: return TypeScript.SyntaxKind.GreaterThanToken;
case TypeScript.SyntaxKind.CloseBraceToken: return TypeScript.SyntaxKind.OpenBraceToken
case TypeScript.SyntaxKind.CloseParenToken: return TypeScript.SyntaxKind.OpenParenToken;
case TypeScript.SyntaxKind.CloseBracketToken: return TypeScript.SyntaxKind.OpenBracketToken;
case TypeScript.SyntaxKind.GreaterThanToken: return TypeScript.SyntaxKind.LessThanToken;
}
return null;
}
}
}
+456 -1040
View File
File diff suppressed because it is too large Load Diff
-53
View File
@@ -1,53 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='references.ts' />
module TypeScript {
export class Comment {
constructor(private _trivia: ISyntaxTrivia,
public endsLine: boolean,
public _start: number,
public _end: number) {
}
public start(): number {
return this._start;
}
public end(): number {
return this._end;
}
public fullText(): string {
return this._trivia.fullText();
}
public kind(): SyntaxKind {
return this._trivia.kind();
}
public structuralEquals(ast: Comment, includingPosition: boolean): boolean {
if (includingPosition) {
if (this.start() !== ast.start() || this.end() !== ast.end()) {
return false;
}
}
return this._trivia.fullText() === ast._trivia.fullText() &&
this.endsLine === ast.endsLine;
}
}
}
-759
View File
@@ -1,759 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='references.ts' />
module TypeScript.ASTHelpers {
var sentinelEmptyArray: any[] = [];
//export function scriptIsElided(sourceUnit: SourceUnitSyntax): boolean {
// return isDTSFile(sourceUnit.syntaxTree.fileName()) || moduleMembersAreElided(sourceUnit.moduleElements);
//}
//export function moduleIsElided(declaration: ModuleDeclarationSyntax): boolean {
// return hasModifier(declaration.modifiers, PullElementFlags.Ambient) || moduleMembersAreElided(declaration.moduleElements);
//}
//function moduleMembersAreElided(members: IModuleElementSyntax[]): boolean {
// for (var i = 0, n = members.length; i < n; i++) {
// var member = members[i];
// // We should emit *this* module if it contains any non-interface types.
// // Caveat: if we have contain a module, then we should be emitted *if we want to
// // emit that inner module as well.
// if (member.kind() === SyntaxKind.ModuleDeclaration) {
// if (!moduleIsElided(<ModuleDeclarationSyntax>member)) {
// return false;
// }
// }
// else if (member.kind() !== SyntaxKind.InterfaceDeclaration) {
// return false;
// }
// }
// return true;
//}
//export function enumIsElided(declaration: EnumDeclarationSyntax): boolean {
// if (hasModifier(declaration.modifiers, PullElementFlags.Ambient)) {
// return true;
// }
// return false;
//}
export function isValidAstNode(ast: ISyntaxElement): boolean {
return ast && !isShared(ast) && start(ast) !== -1 && end(ast) !== -1;
}
export function isValidSpan(ast: ISpan): boolean {
if (!ast)
return false;
if (ast.start() === -1 || ast.end() === -1)
return false;
return true;
}
///
/// Return the ISyntaxElement containing "position"
///
export function getAstAtPosition(script: ISyntaxElement, pos: number, useTrailingTriviaAsLimChar: boolean = true, forceInclusive: boolean = false): ISyntaxElement {
var top: ISyntaxElement = null;
var pre = function (cur: ISyntaxElement, walker: IAstWalker) {
if (!isShared(cur) && isValidAstNode(cur)) {
var isInvalid1 = cur.kind() === SyntaxKind.ExpressionStatement && width(cur) === 0;
if (isInvalid1) {
walker.options.goChildren = false;
}
else {
// Add "cur" to the stack if it contains our position
// For "identifier" nodes, we need a special case: A position equal to "limChar" is
// valid, since the position corresponds to a caret position (in between characters)
// For example:
// bar
// 0123
// If "position === 3", the caret is at the "right" of the "r" character, which should be considered valid
var inclusive =
forceInclusive ||
cur.kind() === SyntaxKind.IdentifierName ||
cur.kind() === SyntaxKind.MemberAccessExpression ||
cur.kind() === SyntaxKind.QualifiedName ||
//cur.kind() === SyntaxKind.TypeRef ||
cur.kind() === SyntaxKind.VariableDeclaration ||
cur.kind() === SyntaxKind.VariableDeclarator ||
cur.kind() === SyntaxKind.InvocationExpression ||
pos === end(script) + lastToken(script).trailingTriviaWidth(); // Special "EOF" case
var minChar = start(cur);
var limChar = end(cur) + (useTrailingTriviaAsLimChar ? trailingTriviaWidth(cur) : 0) + (inclusive ? 1 : 0);
if (pos >= minChar && pos < limChar) {
// Ignore empty lists
if ((cur.kind() !== SyntaxKind.List && cur.kind() !== SyntaxKind.SeparatedList) || end(cur) > start(cur)) {
// TODO: Since ISyntaxElement is sometimes not correct wrt to position, only add "cur" if it's better
// than top of the stack.
if (top === null) {
top = cur;
}
else if (start(cur) >= start(top) &&
(end(cur) + (useTrailingTriviaAsLimChar ? trailingTriviaWidth(cur) : 0)) <= (end(top) + (useTrailingTriviaAsLimChar ? trailingTriviaWidth(top) : 0))) {
// this new node appears to be better than the one we're
// storing. Make this the new node.
// However, If the current top is a missing identifier, we
// don't want to replace it with another missing identifier.
// We want to return the first missing identifier found in a
// depth first walk of the tree.
if (width(top) !== 0 || width(cur) !== 0) {
top = cur;
}
}
}
}
// Don't go further down the tree if pos is outside of [minChar, limChar]
walker.options.goChildren = (minChar <= pos && pos <= limChar);
}
}
};
getAstWalkerFactory().walk(script, pre);
return top;
}
export function getExtendsHeritageClause(clauses: HeritageClauseSyntax[]): HeritageClauseSyntax {
return getHeritageClause(clauses, SyntaxKind.ExtendsHeritageClause);
}
export function getImplementsHeritageClause(clauses: HeritageClauseSyntax[]): HeritageClauseSyntax {
return getHeritageClause(clauses, SyntaxKind.ImplementsHeritageClause);
}
function getHeritageClause(clauses: HeritageClauseSyntax[], kind: SyntaxKind): HeritageClauseSyntax {
if (clauses) {
for (var i = 0, n = clauses.length; i < n; i++) {
var child = clauses[i];
if (child.typeNames.length > 0 && child.kind() === kind) {
return child;
}
}
}
return null;
}
export function isCallExpression(ast: ISyntaxElement): boolean {
return (ast && ast.kind() === SyntaxKind.InvocationExpression) ||
(ast && ast.kind() === SyntaxKind.ObjectCreationExpression);
}
export function isCallExpressionTarget(ast: ISyntaxElement): boolean {
return !!getCallExpressionTarget(ast);
}
export function getCallExpressionTarget(ast: ISyntaxElement): ISyntaxElement {
if (!ast) {
return null;
}
var current = ast;
while (current && current.parent) {
if (current.parent.kind() === SyntaxKind.MemberAccessExpression &&
(<MemberAccessExpressionSyntax>current.parent).name === current) {
current = current.parent;
continue;
}
break;
}
if (current && current.parent) {
if (current.parent.kind() === SyntaxKind.InvocationExpression || current.parent.kind() === SyntaxKind.ObjectCreationExpression) {
return current === (<InvocationExpressionSyntax>current.parent).expression ? current : null;
}
}
return null;
}
function isNameOfSomeDeclaration(ast: ISyntaxElement) {
if (ast === null || ast.parent === null) {
return false;
}
if (ast.kind() !== SyntaxKind.IdentifierName) {
return false;
}
switch (ast.parent.kind()) {
case SyntaxKind.ClassDeclaration:
return (<ClassDeclarationSyntax>ast.parent).identifier === ast;
case SyntaxKind.InterfaceDeclaration:
return (<InterfaceDeclarationSyntax>ast.parent).identifier === ast;
case SyntaxKind.EnumDeclaration:
return (<EnumDeclarationSyntax>ast.parent).identifier === ast;
case SyntaxKind.ModuleDeclaration:
return (<ModuleDeclarationSyntax>ast.parent).name === ast || (<ModuleDeclarationSyntax>ast.parent).stringLiteral === ast;
case SyntaxKind.VariableDeclarator:
return (<VariableDeclaratorSyntax>ast.parent).propertyName === ast;
case SyntaxKind.FunctionDeclaration:
return (<FunctionDeclarationSyntax>ast.parent).identifier === ast;
case SyntaxKind.MemberFunctionDeclaration:
return (<MemberFunctionDeclarationSyntax>ast.parent).propertyName === ast;
case SyntaxKind.Parameter:
return (<ParameterSyntax>ast.parent).identifier === ast;
case SyntaxKind.TypeParameter:
return (<TypeParameterSyntax>ast.parent).identifier === ast;
case SyntaxKind.SimplePropertyAssignment:
return (<SimplePropertyAssignmentSyntax>ast.parent).propertyName === ast;
case SyntaxKind.FunctionPropertyAssignment:
return (<FunctionPropertyAssignmentSyntax>ast.parent).propertyName === ast;
case SyntaxKind.EnumElement:
return (<EnumElementSyntax>ast.parent).propertyName === ast;
case SyntaxKind.ImportDeclaration:
return (<ImportDeclarationSyntax>ast.parent).identifier === ast;
case SyntaxKind.MethodSignature:
return (<MethodSignatureSyntax>ast.parent).propertyName === ast;
case SyntaxKind.PropertySignature:
return (<MethodSignatureSyntax>ast.parent).propertyName === ast;
}
return false;
}
export function isDeclarationASTOrDeclarationNameAST(ast: ISyntaxElement) {
return isNameOfSomeDeclaration(ast) || ASTHelpers.isDeclarationAST(ast);
}
export function getEnclosingParameterForInitializer(ast: ISyntaxElement): ParameterSyntax {
var current = ast;
while (current) {
switch (current.kind()) {
case SyntaxKind.EqualsValueClause:
if (current.parent && current.parent.kind() === SyntaxKind.Parameter) {
return <ParameterSyntax>current.parent;
}
break;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.ModuleDeclaration:
// exit early
return null;
}
current = current.parent;
}
return null;
}
export function getEnclosingMemberDeclaration(ast: ISyntaxElement): ISyntaxElement {
var current = ast;
while (current) {
switch (current.kind()) {
case SyntaxKind.MemberVariableDeclaration:
case SyntaxKind.MethodSignature:
case SyntaxKind.MemberFunctionDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
return current;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.ModuleDeclaration:
// exit early
return null;
}
current = current.parent;
}
return null;
}
export function isNameOfFunction(ast: ISyntaxElement) {
return ast
&& ast.parent
&& ast.kind() === SyntaxKind.IdentifierName
&& ast.parent.kind() === SyntaxKind.FunctionDeclaration
&& (<FunctionDeclarationSyntax>ast.parent).identifier === ast;
}
export function isNameOfMemberFunction(ast: ISyntaxElement) {
return ast
&& ast.parent
&& ast.kind() === SyntaxKind.IdentifierName
&& ast.parent.kind() === SyntaxKind.MemberFunctionDeclaration
&& (<MemberFunctionDeclarationSyntax>ast.parent).propertyName === ast;
}
export function isNameOfMemberAccessExpression(ast: ISyntaxElement) {
if (ast &&
ast.parent &&
ast.parent.kind() === SyntaxKind.MemberAccessExpression &&
(<MemberAccessExpressionSyntax>ast.parent).name === ast) {
return true;
}
return false;
}
export function isRightSideOfQualifiedName(ast: ISyntaxElement) {
if (ast &&
ast.parent &&
ast.parent.kind() === SyntaxKind.QualifiedName &&
(<QualifiedNameSyntax>ast.parent).right === ast) {
return true;
}
return false;
}
export function parentIsModuleDeclaration(ast: ISyntaxElement) {
return ast.parent && ast.parent.kind() === SyntaxKind.ModuleDeclaration;
}
export function isDeclarationAST(ast: ISyntaxElement): boolean {
switch (ast.kind()) {
case SyntaxKind.VariableDeclarator:
return getVariableStatement(<VariableDeclaratorSyntax>ast) !== null;
case SyntaxKind.ImportDeclaration:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.Parameter:
case SyntaxKind.SimpleArrowFunctionExpression:
case SyntaxKind.ParenthesizedArrowFunctionExpression:
case SyntaxKind.IndexSignature:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ArrayType:
case SyntaxKind.ObjectType:
case SyntaxKind.TypeParameter:
case SyntaxKind.ConstructorDeclaration:
case SyntaxKind.MemberFunctionDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.MemberVariableDeclaration:
case SyntaxKind.IndexMemberDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.EnumElement:
case SyntaxKind.SimplePropertyAssignment:
case SyntaxKind.FunctionPropertyAssignment:
case SyntaxKind.FunctionExpression:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.MethodSignature:
case SyntaxKind.PropertySignature:
return true;
default:
return false;
}
}
export function preComments(element: ISyntaxElement, text: ISimpleText): Comment[]{
if (element) {
switch (element.kind()) {
case SyntaxKind.VariableStatement:
case SyntaxKind.ExpressionStatement:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ImportDeclaration:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.IfStatement:
case SyntaxKind.SimplePropertyAssignment:
case SyntaxKind.MemberFunctionDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.ReturnStatement:
case SyntaxKind.ConstructorDeclaration:
case SyntaxKind.MemberVariableDeclaration:
case SyntaxKind.EnumElement:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.IndexSignature:
case SyntaxKind.PropertySignature:
case SyntaxKind.MethodSignature:
case SyntaxKind.FunctionPropertyAssignment:
case SyntaxKind.Parameter:
return convertNodeLeadingComments(element, text);
}
}
return null;
}
export function postComments(element: ISyntaxElement, text: ISimpleText): Comment[] {
if (element) {
switch (element.kind()) {
case SyntaxKind.ExpressionStatement:
return convertNodeTrailingComments(element, text, /*allowWithNewLine:*/ true);
case SyntaxKind.VariableStatement:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ImportDeclaration:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.IfStatement:
case SyntaxKind.SimplePropertyAssignment:
case SyntaxKind.MemberFunctionDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.ReturnStatement:
case SyntaxKind.ConstructorDeclaration:
case SyntaxKind.MemberVariableDeclaration:
case SyntaxKind.EnumElement:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.IndexSignature:
case SyntaxKind.PropertySignature:
case SyntaxKind.MethodSignature:
case SyntaxKind.FunctionPropertyAssignment:
case SyntaxKind.Parameter:
return convertNodeTrailingComments(element, text);
}
}
return null;
}
function convertNodeTrailingComments(node: ISyntaxElement, text: ISimpleText, allowWithNewLine = false): Comment[]{
// Bail out quickly before doing any expensive math computation.
var _lastToken = lastToken(node);
if (_lastToken === null || !_lastToken.hasTrailingTrivia()) {
return null;
}
if (!allowWithNewLine && SyntaxUtilities.isLastTokenOnLine(_lastToken, text)) {
return null;
}
return convertComments(_lastToken.trailingTrivia(text), fullStart(node) + fullWidth(node) - _lastToken.trailingTriviaWidth(text));
}
function convertNodeLeadingComments(element: ISyntaxElement, text: ISimpleText): Comment[]{
if (element) {
return convertTokenLeadingComments(firstToken(element), text);
}
return null;
}
export function convertTokenLeadingComments(token: ISyntaxToken, text: ISimpleText): Comment[]{
if (token === null) {
return null;
}
return token.hasLeadingTrivia()
? convertComments(token.leadingTrivia(text), token.fullStart())
: null;
}
export function convertTokenTrailingComments(token: ISyntaxToken, text: ISimpleText): Comment[] {
if (token === null) {
return null;
}
return token.hasTrailingTrivia()
? convertComments(token.trailingTrivia(text), fullEnd(token) - token.trailingTriviaWidth(text))
: null;
}
function convertComments(triviaList: ISyntaxTriviaList, commentStartPosition: number): Comment[]{
var result: Comment[] = null;
for (var i = 0, n = triviaList.count(); i < n; i++) {
var trivia = triviaList.syntaxTriviaAt(i);
if (trivia.isComment()) {
var hasTrailingNewLine = ((i + 1) < n) && triviaList.syntaxTriviaAt(i + 1).isNewLine();
result = result || [];
result.push(convertComment(trivia, commentStartPosition, hasTrailingNewLine));
}
commentStartPosition += trivia.fullWidth();
}
return result;
}
function convertComment(trivia: ISyntaxTrivia, commentStartPosition: number, hasTrailingNewLine: boolean): Comment {
var comment = new Comment(trivia, hasTrailingNewLine, commentStartPosition, commentStartPosition + trivia.fullWidth());
return comment;
}
export function docComments(ast: ISyntaxElement, text: ISimpleText): Comment[] {
if (isDeclarationAST(ast)) {
var comments: Comment[] = null;
if (ast.kind() === SyntaxKind.VariableDeclarator) {
// Get the doc comments for a variable off of the variable statement. That's what
// they'll be attached to in the tree.
comments = TypeScript.ASTHelpers.preComments(getVariableStatement(<VariableDeclaratorSyntax>ast), text);
}
else if (ast.kind() === SyntaxKind.Parameter) {
// First check if the parameter was written like so:
// (
// /** blah */ a,
// /** blah */ b);
comments = TypeScript.ASTHelpers.preComments(ast, text);
if (!comments) {
// Now check if it was written like so:
// (/** blah */ a, /** blah */ b);
// In this case, the comment will belong to the preceding token.
var previousToken = findToken(syntaxTree(ast).sourceUnit(), firstToken(ast).fullStart() - 1);
if (previousToken && (previousToken.kind() === SyntaxKind.OpenParenToken || previousToken.kind() === SyntaxKind.CommaToken)) {
comments = convertTokenTrailingComments(previousToken, text);
}
}
}
else {
comments = TypeScript.ASTHelpers.preComments(ast, text);
}
if (comments && comments.length > 0) {
return comments.filter(c => isDocComment(c));
}
}
return sentinelEmptyArray;
}
export function isDocComment(comment: Comment) {
if (comment.kind() === SyntaxKind.MultiLineCommentTrivia) {
var fullText = comment.fullText();
return fullText.charAt(2) === "*" && fullText.charAt(3) !== "/";
}
return false;
}
export function getParameterList(ast: ISyntaxElement): ParameterListSyntax {
if (ast) {
switch (ast.kind()) {
case SyntaxKind.ConstructorDeclaration:
return getParameterList((<ConstructorDeclarationSyntax>ast).callSignature);
case SyntaxKind.FunctionDeclaration:
return getParameterList((<FunctionDeclarationSyntax>ast).callSignature);
case SyntaxKind.ParenthesizedArrowFunctionExpression:
return getParameterList((<ParenthesizedArrowFunctionExpressionSyntax>ast).callSignature);
case SyntaxKind.ConstructSignature:
return getParameterList((<ConstructSignatureSyntax>ast).callSignature);
case SyntaxKind.MemberFunctionDeclaration:
return getParameterList((<MemberFunctionDeclarationSyntax>ast).callSignature);
case SyntaxKind.FunctionPropertyAssignment:
return getParameterList((<FunctionPropertyAssignmentSyntax>ast).callSignature);
case SyntaxKind.FunctionExpression:
return getParameterList((<FunctionExpressionSyntax>ast).callSignature);
case SyntaxKind.MethodSignature:
return getParameterList((<MethodSignatureSyntax>ast).callSignature);
case SyntaxKind.ConstructorType:
return (<ConstructorTypeSyntax>ast).parameterList;
case SyntaxKind.FunctionType:
return (<FunctionTypeSyntax>ast).parameterList;
case SyntaxKind.CallSignature:
return (<CallSignatureSyntax>ast).parameterList;
case SyntaxKind.GetAccessor:
return getParameterList((<GetAccessorSyntax>ast).callSignature);
case SyntaxKind.SetAccessor:
return getParameterList((<SetAccessorSyntax>ast).callSignature);
}
}
return null;
}
export function getType(ast: ISyntaxElement): ITypeSyntax {
if (ast) {
switch (ast.kind()) {
case SyntaxKind.FunctionDeclaration:
return getType((<FunctionDeclarationSyntax>ast).callSignature);
case SyntaxKind.ParenthesizedArrowFunctionExpression:
return getType((<ParenthesizedArrowFunctionExpressionSyntax>ast).callSignature);
case SyntaxKind.ConstructSignature:
return getType((<ConstructSignatureSyntax>ast).callSignature);
case SyntaxKind.MemberFunctionDeclaration:
return getType((<MemberFunctionDeclarationSyntax>ast).callSignature);
case SyntaxKind.FunctionPropertyAssignment:
return getType((<FunctionPropertyAssignmentSyntax>ast).callSignature);
case SyntaxKind.FunctionExpression:
return getType((<FunctionExpressionSyntax>ast).callSignature);
case SyntaxKind.MethodSignature:
return getType((<MethodSignatureSyntax>ast).callSignature);
case SyntaxKind.CallSignature:
return getType((<CallSignatureSyntax>ast).typeAnnotation);
case SyntaxKind.IndexSignature:
return getType((<IndexSignatureSyntax>ast).typeAnnotation);
case SyntaxKind.PropertySignature:
return getType((<PropertySignatureSyntax>ast).typeAnnotation);
case SyntaxKind.GetAccessor:
return getType((<GetAccessorSyntax>ast).callSignature);
case SyntaxKind.Parameter:
return getType((<ParameterSyntax>ast).typeAnnotation);
case SyntaxKind.MemberVariableDeclaration:
return getType((<MemberVariableDeclarationSyntax>ast).variableDeclarator);
case SyntaxKind.VariableDeclarator:
return getType((<VariableDeclaratorSyntax>ast).typeAnnotation);
case SyntaxKind.CatchClause:
return getType((<CatchClauseSyntax>ast).typeAnnotation);
case SyntaxKind.ConstructorType:
return (<ConstructorTypeSyntax>ast).type;
case SyntaxKind.FunctionType:
return (<FunctionTypeSyntax>ast).type;
case SyntaxKind.TypeAnnotation:
return (<TypeAnnotationSyntax>ast).type;
}
}
return null;
}
function getVariableStatement(variableDeclarator: VariableDeclaratorSyntax): VariableStatementSyntax {
if (variableDeclarator && variableDeclarator.parent && variableDeclarator.parent.parent && variableDeclarator.parent.parent.parent &&
variableDeclarator.parent.kind() === SyntaxKind.SeparatedList &&
variableDeclarator.parent.parent.kind() === SyntaxKind.VariableDeclaration &&
variableDeclarator.parent.parent.parent.kind() === SyntaxKind.VariableStatement) {
return <VariableStatementSyntax>variableDeclarator.parent.parent.parent;
}
return null;
}
export function getVariableDeclaratorModifiers(variableDeclarator: VariableDeclaratorSyntax): ISyntaxToken[] {
var variableStatement = getVariableStatement(variableDeclarator);
return variableStatement ? variableStatement.modifiers : Syntax.emptyList<ISyntaxToken>();
}
export function isIntegerLiteralAST(expression: ISyntaxElement): boolean {
if (expression) {
switch (expression.kind()) {
case SyntaxKind.PlusExpression:
case SyntaxKind.NegateExpression:
// Note: if there is a + or - sign, we can only allow a normal integer following
// (and not a hex integer). i.e. -0xA is a legal expression, but it is not a
// *literal*.
expression = (<PrefixUnaryExpressionSyntax>expression).operand;
return expression.kind() === SyntaxKind.NumericLiteral && IntegerUtilities.isInteger((<ISyntaxToken>expression).text());
case SyntaxKind.NumericLiteral:
// If it doesn't have a + or -, then either an integer literal or a hex literal
// is acceptable.
var text = (<ISyntaxToken>expression).text();
return IntegerUtilities.isInteger(text) || IntegerUtilities.isHexInteger(text);
}
}
return false;
}
export function getEnclosingModuleDeclaration(ast: ISyntaxElement): ModuleDeclarationSyntax {
while (ast) {
if (ast.kind() === SyntaxKind.ModuleDeclaration) {
return <ModuleDeclarationSyntax>ast;
}
ast = ast.parent;
}
return null;
}
function isEntireNameOfModuleDeclaration(nameAST: ISyntaxElement) {
return parentIsModuleDeclaration(nameAST) && (<ModuleDeclarationSyntax>nameAST.parent).name === nameAST;
}
export function getModuleDeclarationFromNameAST(ast: ISyntaxElement): ModuleDeclarationSyntax {
if (ast) {
switch (ast.kind()) {
case SyntaxKind.StringLiteral:
if (parentIsModuleDeclaration(ast) && (<ModuleDeclarationSyntax>ast.parent).stringLiteral === ast) {
return <ModuleDeclarationSyntax>ast.parent;
}
return null;
case SyntaxKind.IdentifierName:
case SyntaxKind.QualifiedName:
if (isEntireNameOfModuleDeclaration(ast)) {
return <ModuleDeclarationSyntax>ast.parent;
}
break;
default:
return null;
}
// Only qualified names can be name of module declaration if they didnt satisfy above conditions
for (ast = ast.parent; ast && ast.kind() === SyntaxKind.QualifiedName; ast = ast.parent) {
if (isEntireNameOfModuleDeclaration(ast)) {
return <ModuleDeclarationSyntax>ast.parent;
}
}
}
return null;
}
export function isLastNameOfModule(ast: ModuleDeclarationSyntax, astName: ISyntaxElement): boolean {
if (ast) {
if (ast.stringLiteral) {
return astName === ast.stringLiteral;
}
else if (ast.name.kind() === SyntaxKind.QualifiedName) {
return astName === (<QualifiedNameSyntax>ast.name).right;
}
else {
return astName === ast.name;
}
}
return false;
}
export function getNameOfIdentifierOrQualifiedName(name: ISyntaxElement): string {
if (name.kind() === SyntaxKind.IdentifierName) {
return (<ISyntaxToken>name).text();
}
else {
Debug.assert(name.kind() == SyntaxKind.QualifiedName);
var dotExpr = <QualifiedNameSyntax>name;
return getNameOfIdentifierOrQualifiedName(dotExpr.left) + "." + getNameOfIdentifierOrQualifiedName(dotExpr.right);
}
}
export function getModuleNames(name: ISyntaxElement, result?: ISyntaxToken[]): ISyntaxToken[] {
result = result || [];
if (name.kind() === SyntaxKind.QualifiedName) {
getModuleNames((<QualifiedNameSyntax>name).left, result);
result.push((<QualifiedNameSyntax>name).right);
}
else {
result.push(<ISyntaxToken>name);
}
return result;
}
}
-716
View File
@@ -1,716 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='references.ts' />
module TypeScript {
function walkListChildren(preAst: ISyntaxNodeOrToken[], walker: AstWalker): void {
for (var i = 0, n = preAst.length; i < n; i++) {
walker.walk(preAst[i]);
}
}
function walkThrowStatementChildren(preAst: ThrowStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
}
function walkPrefixUnaryExpressionChildren(preAst: PrefixUnaryExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.operand);
}
function walkPostfixUnaryExpressionChildren(preAst: PostfixUnaryExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.operand);
}
function walkDeleteExpressionChildren(preAst: DeleteExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
}
function walkTypeArgumentListChildren(preAst: TypeArgumentListSyntax, walker: AstWalker): void {
walker.walk(preAst.typeArguments);
}
function walkTypeOfExpressionChildren(preAst: TypeOfExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
}
function walkVoidExpressionChildren(preAst: VoidExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
}
function walkArgumentListChildren(preAst: ArgumentListSyntax, walker: AstWalker): void {
walker.walk(preAst.typeArgumentList);
walker.walk(preAst.arguments);
}
function walkArrayLiteralExpressionChildren(preAst: ArrayLiteralExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expressions);
}
function walkSimplePropertyAssignmentChildren(preAst: SimplePropertyAssignmentSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.expression);
}
function walkFunctionPropertyAssignmentChildren(preAst: FunctionPropertyAssignmentSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.callSignature);
walker.walk(preAst.block);
}
function walkGetAccessorChildren(preAst: GetAccessorSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.callSignature);
walker.walk(preAst.block);
}
function walkSeparatedListChildren(preAst: ISyntaxNodeOrToken[], walker: AstWalker): void {
for (var i = 0, n = preAst.length; i < n; i++) {
walker.walk(preAst[i]);
}
}
function walkSetAccessorChildren(preAst: SetAccessorSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.callSignature);
walker.walk(preAst.block);
}
function walkObjectLiteralExpressionChildren(preAst: ObjectLiteralExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyAssignments);
}
function walkCastExpressionChildren(preAst: CastExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.type);
walker.walk(preAst.expression);
}
function walkParenthesizedExpressionChildren(preAst: ParenthesizedExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
}
function walkElementAccessExpressionChildren(preAst: ElementAccessExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
walker.walk(preAst.argumentExpression);
}
function walkMemberAccessExpressionChildren(preAst: MemberAccessExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
walker.walk(preAst.name);
}
function walkQualifiedNameChildren(preAst: QualifiedNameSyntax, walker: AstWalker): void {
walker.walk(preAst.left);
walker.walk(preAst.right);
}
function walkBinaryExpressionChildren(preAst: BinaryExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.left);
walker.walk(preAst.right);
}
function walkEqualsValueClauseChildren(preAst: EqualsValueClauseSyntax, walker: AstWalker): void {
walker.walk(preAst.value);
}
function walkTypeParameterChildren(preAst: TypeParameterSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.constraint);
}
function walkTypeParameterListChildren(preAst: TypeParameterListSyntax, walker: AstWalker): void {
walker.walk(preAst.typeParameters);
}
function walkGenericTypeChildren(preAst: GenericTypeSyntax, walker: AstWalker): void {
walker.walk(preAst.name);
walker.walk(preAst.typeArgumentList);
}
function walkTypeAnnotationChildren(preAst: TypeAnnotationSyntax, walker: AstWalker): void {
walker.walk(preAst.type);
}
function walkTypeQueryChildren(preAst: TypeQuerySyntax, walker: AstWalker): void {
walker.walk(preAst.name);
}
function walkInvocationExpressionChildren(preAst: InvocationExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
walker.walk(preAst.argumentList);
}
function walkObjectCreationExpressionChildren(preAst: ObjectCreationExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
walker.walk(preAst.argumentList);
}
function walkTrinaryExpressionChildren(preAst: ConditionalExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.condition);
walker.walk(preAst.whenTrue);
walker.walk(preAst.whenFalse);
}
function walkFunctionExpressionChildren(preAst: FunctionExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.callSignature);
walker.walk(preAst.block);
}
function walkFunctionTypeChildren(preAst: FunctionTypeSyntax, walker: AstWalker): void {
walker.walk(preAst.typeParameterList);
walker.walk(preAst.parameterList);
walker.walk(preAst.type);
}
function walkParenthesizedArrowFunctionExpressionChildren(preAst: ParenthesizedArrowFunctionExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.callSignature);
walker.walk(preAst.block);
walker.walk(preAst.expression);
}
function walkSimpleArrowFunctionExpressionChildren(preAst: SimpleArrowFunctionExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.parameter);
walker.walk(preAst.block);
walker.walk(preAst.expression);
}
function walkMemberFunctionDeclarationChildren(preAst: MemberFunctionDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.callSignature);
walker.walk(preAst.block);
}
function walkFuncDeclChildren(preAst: FunctionDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.callSignature);
walker.walk(preAst.block);
}
function walkIndexMemberDeclarationChildren(preAst: IndexMemberDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.indexSignature);
}
function walkIndexSignatureChildren(preAst: IndexSignatureSyntax, walker: AstWalker): void {
walker.walk(preAst.parameters);
walker.walk(preAst.typeAnnotation);
}
function walkCallSignatureChildren(preAst: CallSignatureSyntax, walker: AstWalker): void {
walker.walk(preAst.typeParameterList);
walker.walk(preAst.parameterList);
walker.walk(preAst.typeAnnotation);
}
function walkConstraintChildren(preAst: ConstraintSyntax, walker: AstWalker): void {
walker.walk(preAst.typeOrExpression);
}
function walkConstructorDeclarationChildren(preAst: ConstructorDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.callSignature);
walker.walk(preAst.block);
}
function walkConstructorTypeChildren(preAst: FunctionTypeSyntax, walker: AstWalker): void {
walker.walk(preAst.typeParameterList);
walker.walk(preAst.parameterList);
walker.walk(preAst.type);
}
function walkConstructSignatureChildren(preAst: ConstructSignatureSyntax, walker: AstWalker): void {
walker.walk(preAst.callSignature);
}
function walkParameterChildren(preAst: ParameterSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.typeAnnotation);
walker.walk(preAst.equalsValueClause);
}
function walkParameterListChildren(preAst: ParameterListSyntax, walker: AstWalker): void {
walker.walk(preAst.parameters);
}
function walkPropertySignatureChildren(preAst: PropertySignatureSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.typeAnnotation);
}
function walkVariableDeclaratorChildren(preAst: VariableDeclaratorSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.typeAnnotation);
walker.walk(preAst.equalsValueClause);
}
function walkMemberVariableDeclarationChildren(preAst: MemberVariableDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.variableDeclarator);
}
function walkMethodSignatureChildren(preAst: MethodSignatureSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.callSignature);
}
function walkReturnStatementChildren(preAst: ReturnStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
}
function walkForStatementChildren(preAst: ForStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.variableDeclaration);
walker.walk(preAst.initializer);
walker.walk(preAst.condition);
walker.walk(preAst.incrementor);
walker.walk(preAst.statement);
}
function walkForInStatementChildren(preAst: ForInStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.variableDeclaration);
walker.walk(preAst.left);
walker.walk(preAst.expression);
walker.walk(preAst.statement);
}
function walkIfStatementChildren(preAst: IfStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.condition);
walker.walk(preAst.statement);
walker.walk(preAst.elseClause);
}
function walkElseClauseChildren(preAst: ElseClauseSyntax, walker: AstWalker): void {
walker.walk(preAst.statement);
}
function walkWhileStatementChildren(preAst: WhileStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.condition);
walker.walk(preAst.statement);
}
function walkDoStatementChildren(preAst: DoStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.condition);
walker.walk(preAst.statement);
}
function walkBlockChildren(preAst: BlockSyntax, walker: AstWalker): void {
walker.walk(preAst.statements);
}
function walkVariableDeclarationChildren(preAst: VariableDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.variableDeclarators);
}
function walkCaseSwitchClauseChildren(preAst: CaseSwitchClauseSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
walker.walk(preAst.statements);
}
function walkDefaultSwitchClauseChildren(preAst: DefaultSwitchClauseSyntax, walker: AstWalker): void {
walker.walk(preAst.statements);
}
function walkSwitchStatementChildren(preAst: SwitchStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
walker.walk(preAst.switchClauses);
}
function walkTryStatementChildren(preAst: TryStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.block);
walker.walk(preAst.catchClause);
walker.walk(preAst.finallyClause);
}
function walkCatchClauseChildren(preAst: CatchClauseSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.typeAnnotation);
walker.walk(preAst.block);
}
function walkExternalModuleReferenceChildren(preAst: ExternalModuleReferenceSyntax, walker: AstWalker): void {
walker.walk(preAst.stringLiteral);
}
function walkFinallyClauseChildren(preAst: FinallyClauseSyntax, walker: AstWalker): void {
walker.walk(preAst.block);
}
function walkClassDeclChildren(preAst: ClassDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.typeParameterList);
walker.walk(preAst.heritageClauses);
walker.walk(preAst.classElements);
}
function walkScriptChildren(preAst: SourceUnitSyntax, walker: AstWalker): void {
walker.walk(preAst.moduleElements);
}
function walkHeritageClauseChildren(preAst: HeritageClauseSyntax, walker: AstWalker): void {
walker.walk(preAst.typeNames);
}
function walkInterfaceDeclerationChildren(preAst: InterfaceDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.typeParameterList);
walker.walk(preAst.heritageClauses);
walker.walk(preAst.body);
}
function walkObjectTypeChildren(preAst: ObjectTypeSyntax, walker: AstWalker): void {
walker.walk(preAst.typeMembers);
}
function walkArrayTypeChildren(preAst: ArrayTypeSyntax, walker: AstWalker): void {
walker.walk(preAst.type);
}
function walkModuleDeclarationChildren(preAst: ModuleDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.name);
walker.walk(preAst.stringLiteral);
walker.walk(preAst.moduleElements);
}
function walkModuleNameModuleReferenceChildren(preAst: ModuleNameModuleReferenceSyntax, walker: AstWalker): void {
walker.walk(preAst.moduleName);
}
function walkEnumDeclarationChildren(preAst: EnumDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.enumElements);
}
function walkEnumElementChildren(preAst: EnumElementSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.equalsValueClause);
}
function walkImportDeclarationChildren(preAst: ImportDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.moduleReference);
}
function walkExportAssignmentChildren(preAst: ExportAssignmentSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
}
function walkWithStatementChildren(preAst: WithStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.condition);
walker.walk(preAst.statement);
}
function walkExpressionStatementChildren(preAst: ExpressionStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
}
function walkLabeledStatementChildren(preAst: LabeledStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.statement);
}
function walkVariableStatementChildren(preAst: VariableStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.variableDeclaration);
}
var childrenWalkers: IAstWalkChildren[] = new Array<IAstWalkChildren>(SyntaxKind.LastNode + 1);
// Tokens/trivia can't ever be walked into.
for (var i = SyntaxKind.FirstToken, n = SyntaxKind.LastToken; i <= n; i++) {
childrenWalkers[i] = null;
}
for (var i = SyntaxKind.FirstTrivia, n = SyntaxKind.LastTrivia; i <= n; i++) {
childrenWalkers[i] = null;
}
childrenWalkers[SyntaxKind.AddAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.AddExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.AndAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.AnyKeyword] = null;
childrenWalkers[SyntaxKind.ArgumentList] = walkArgumentListChildren;
childrenWalkers[SyntaxKind.ArrayLiteralExpression] = walkArrayLiteralExpressionChildren;
childrenWalkers[SyntaxKind.ArrayType] = walkArrayTypeChildren;
childrenWalkers[SyntaxKind.SimpleArrowFunctionExpression] = walkSimpleArrowFunctionExpressionChildren;
childrenWalkers[SyntaxKind.ParenthesizedArrowFunctionExpression] = walkParenthesizedArrowFunctionExpressionChildren;
childrenWalkers[SyntaxKind.AssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.BitwiseAndExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.BitwiseExclusiveOrExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.BitwiseNotExpression] = walkPrefixUnaryExpressionChildren;
childrenWalkers[SyntaxKind.BitwiseOrExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.Block] = walkBlockChildren;
childrenWalkers[SyntaxKind.BooleanKeyword] = null;
childrenWalkers[SyntaxKind.BreakStatement] = null;
childrenWalkers[SyntaxKind.CallSignature] = walkCallSignatureChildren;
childrenWalkers[SyntaxKind.CaseSwitchClause] = walkCaseSwitchClauseChildren;
childrenWalkers[SyntaxKind.CastExpression] = walkCastExpressionChildren;
childrenWalkers[SyntaxKind.CatchClause] = walkCatchClauseChildren;
childrenWalkers[SyntaxKind.ClassDeclaration] = walkClassDeclChildren;
childrenWalkers[SyntaxKind.CommaExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.ConditionalExpression] = walkTrinaryExpressionChildren;
childrenWalkers[SyntaxKind.Constraint] = walkConstraintChildren;
childrenWalkers[SyntaxKind.ConstructorDeclaration] = walkConstructorDeclarationChildren;
childrenWalkers[SyntaxKind.ConstructSignature] = walkConstructSignatureChildren;
childrenWalkers[SyntaxKind.ContinueStatement] = null;
childrenWalkers[SyntaxKind.ConstructorType] = walkConstructorTypeChildren;
childrenWalkers[SyntaxKind.DebuggerStatement] = null;
childrenWalkers[SyntaxKind.DefaultSwitchClause] = walkDefaultSwitchClauseChildren;
childrenWalkers[SyntaxKind.DeleteExpression] = walkDeleteExpressionChildren;
childrenWalkers[SyntaxKind.DivideAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.DivideExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.DoStatement] = walkDoStatementChildren;
childrenWalkers[SyntaxKind.ElementAccessExpression] = walkElementAccessExpressionChildren;
childrenWalkers[SyntaxKind.ElseClause] = walkElseClauseChildren;
childrenWalkers[SyntaxKind.EmptyStatement] = null;
childrenWalkers[SyntaxKind.EnumDeclaration] = walkEnumDeclarationChildren;
childrenWalkers[SyntaxKind.EnumElement] = walkEnumElementChildren;
childrenWalkers[SyntaxKind.EqualsExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.EqualsValueClause] = walkEqualsValueClauseChildren;
childrenWalkers[SyntaxKind.EqualsWithTypeConversionExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.ExclusiveOrAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.ExportAssignment] = walkExportAssignmentChildren;
childrenWalkers[SyntaxKind.ExpressionStatement] = walkExpressionStatementChildren;
childrenWalkers[SyntaxKind.ExtendsHeritageClause] = walkHeritageClauseChildren;
childrenWalkers[SyntaxKind.ExternalModuleReference] = walkExternalModuleReferenceChildren;
childrenWalkers[SyntaxKind.FalseKeyword] = null;
childrenWalkers[SyntaxKind.FinallyClause] = walkFinallyClauseChildren;
childrenWalkers[SyntaxKind.ForInStatement] = walkForInStatementChildren;
childrenWalkers[SyntaxKind.ForStatement] = walkForStatementChildren;
childrenWalkers[SyntaxKind.FunctionDeclaration] = walkFuncDeclChildren;
childrenWalkers[SyntaxKind.FunctionExpression] = walkFunctionExpressionChildren;
childrenWalkers[SyntaxKind.FunctionPropertyAssignment] = walkFunctionPropertyAssignmentChildren;
childrenWalkers[SyntaxKind.FunctionType] = walkFunctionTypeChildren;
childrenWalkers[SyntaxKind.GenericType] = walkGenericTypeChildren;
childrenWalkers[SyntaxKind.GetAccessor] = walkGetAccessorChildren;
childrenWalkers[SyntaxKind.GreaterThanExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.GreaterThanOrEqualExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.IfStatement] = walkIfStatementChildren;
childrenWalkers[SyntaxKind.ImplementsHeritageClause] = walkHeritageClauseChildren;
childrenWalkers[SyntaxKind.ImportDeclaration] = walkImportDeclarationChildren;
childrenWalkers[SyntaxKind.IndexMemberDeclaration] = walkIndexMemberDeclarationChildren;
childrenWalkers[SyntaxKind.IndexSignature] = walkIndexSignatureChildren;
childrenWalkers[SyntaxKind.InExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.InstanceOfExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.InterfaceDeclaration] = walkInterfaceDeclerationChildren;
childrenWalkers[SyntaxKind.InvocationExpression] = walkInvocationExpressionChildren;
childrenWalkers[SyntaxKind.LabeledStatement] = walkLabeledStatementChildren;
childrenWalkers[SyntaxKind.LeftShiftAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.LeftShiftExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.LessThanExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.LessThanOrEqualExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.List] = walkListChildren;
childrenWalkers[SyntaxKind.LogicalAndExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.LogicalNotExpression] = walkPrefixUnaryExpressionChildren;
childrenWalkers[SyntaxKind.LogicalOrExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.MemberAccessExpression] = walkMemberAccessExpressionChildren;
childrenWalkers[SyntaxKind.MemberFunctionDeclaration] = walkMemberFunctionDeclarationChildren;
childrenWalkers[SyntaxKind.MemberVariableDeclaration] = walkMemberVariableDeclarationChildren;
childrenWalkers[SyntaxKind.MethodSignature] = walkMethodSignatureChildren;
childrenWalkers[SyntaxKind.ModuleDeclaration] = walkModuleDeclarationChildren;
childrenWalkers[SyntaxKind.ModuleNameModuleReference] = walkModuleNameModuleReferenceChildren;
childrenWalkers[SyntaxKind.ModuloAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.ModuloExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.MultiplyAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.MultiplyExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.IdentifierName] = null;
childrenWalkers[SyntaxKind.NegateExpression] = walkPrefixUnaryExpressionChildren;
childrenWalkers[SyntaxKind.None] = null;
childrenWalkers[SyntaxKind.NotEqualsExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.NotEqualsWithTypeConversionExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.NullKeyword] = null;
childrenWalkers[SyntaxKind.NumberKeyword] = null;
childrenWalkers[SyntaxKind.NumericLiteral] = null;
childrenWalkers[SyntaxKind.ObjectCreationExpression] = walkObjectCreationExpressionChildren;
childrenWalkers[SyntaxKind.ObjectLiteralExpression] = walkObjectLiteralExpressionChildren;
childrenWalkers[SyntaxKind.ObjectType] = walkObjectTypeChildren;
childrenWalkers[SyntaxKind.OmittedExpression] = null;
childrenWalkers[SyntaxKind.OrAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.Parameter] = walkParameterChildren;
childrenWalkers[SyntaxKind.ParameterList] = walkParameterListChildren;
childrenWalkers[SyntaxKind.ParenthesizedExpression] = walkParenthesizedExpressionChildren;
childrenWalkers[SyntaxKind.PlusExpression] = walkPrefixUnaryExpressionChildren;
childrenWalkers[SyntaxKind.PostDecrementExpression] = walkPostfixUnaryExpressionChildren;
childrenWalkers[SyntaxKind.PostIncrementExpression] = walkPostfixUnaryExpressionChildren;
childrenWalkers[SyntaxKind.PreDecrementExpression] = walkPrefixUnaryExpressionChildren;
childrenWalkers[SyntaxKind.PreIncrementExpression] = walkPrefixUnaryExpressionChildren;
childrenWalkers[SyntaxKind.PropertySignature] = walkPropertySignatureChildren;
childrenWalkers[SyntaxKind.QualifiedName] = walkQualifiedNameChildren;
childrenWalkers[SyntaxKind.RegularExpressionLiteral] = null;
childrenWalkers[SyntaxKind.ReturnStatement] = walkReturnStatementChildren;
childrenWalkers[SyntaxKind.SourceUnit] = walkScriptChildren;
childrenWalkers[SyntaxKind.SeparatedList] = walkSeparatedListChildren;
childrenWalkers[SyntaxKind.SetAccessor] = walkSetAccessorChildren;
childrenWalkers[SyntaxKind.SignedRightShiftAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.SignedRightShiftExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.SimplePropertyAssignment] = walkSimplePropertyAssignmentChildren;
childrenWalkers[SyntaxKind.StringLiteral] = null;
childrenWalkers[SyntaxKind.StringKeyword] = null;
childrenWalkers[SyntaxKind.SubtractAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.SubtractExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.SuperKeyword] = null;
childrenWalkers[SyntaxKind.SwitchStatement] = walkSwitchStatementChildren;
childrenWalkers[SyntaxKind.ThisKeyword] = null;
childrenWalkers[SyntaxKind.ThrowStatement] = walkThrowStatementChildren;
childrenWalkers[SyntaxKind.TriviaList] = null;
childrenWalkers[SyntaxKind.TrueKeyword] = null;
childrenWalkers[SyntaxKind.TryStatement] = walkTryStatementChildren;
childrenWalkers[SyntaxKind.TypeAnnotation] = walkTypeAnnotationChildren;
childrenWalkers[SyntaxKind.TypeArgumentList] = walkTypeArgumentListChildren;
childrenWalkers[SyntaxKind.TypeOfExpression] = walkTypeOfExpressionChildren;
childrenWalkers[SyntaxKind.TypeParameter] = walkTypeParameterChildren;
childrenWalkers[SyntaxKind.TypeParameterList] = walkTypeParameterListChildren;
childrenWalkers[SyntaxKind.TypeQuery] = walkTypeQueryChildren;
childrenWalkers[SyntaxKind.UnsignedRightShiftAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.UnsignedRightShiftExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.VariableDeclaration] = walkVariableDeclarationChildren;
childrenWalkers[SyntaxKind.VariableDeclarator] = walkVariableDeclaratorChildren;
childrenWalkers[SyntaxKind.VariableStatement] = walkVariableStatementChildren;
childrenWalkers[SyntaxKind.VoidExpression] = walkVoidExpressionChildren;
childrenWalkers[SyntaxKind.VoidKeyword] = null;
childrenWalkers[SyntaxKind.WhileStatement] = walkWhileStatementChildren;
childrenWalkers[SyntaxKind.WithStatement] = walkWithStatementChildren;
// Verify the code is up to date with the enum
for (var e in SyntaxKind) {
if (SyntaxKind.hasOwnProperty(e) && StringUtilities.isString(SyntaxKind[e])) {
TypeScript.Debug.assert(childrenWalkers[e] !== undefined, "Fix initWalkers: " + SyntaxKind[e]);
}
}
export class AstWalkOptions {
public goChildren = true;
public stopWalking = false;
}
interface IAstWalkChildren {
(preAst: ISyntaxElement, walker: AstWalker): void;
}
export interface IAstWalker {
options: AstWalkOptions;
state: any
}
interface AstWalker {
walk(ast: ISyntaxElement): void;
}
class SimplePreAstWalker implements AstWalker {
public options: AstWalkOptions = new AstWalkOptions();
constructor(
private pre: (ast: ISyntaxElement, state: any) => void,
public state: any) {
}
public walk(ast: ISyntaxElement): void {
if (!ast) {
return;
}
this.pre(ast, this.state);
var walker = childrenWalkers[ast.kind()];
if (walker) {
walker(ast, this);
}
}
}
class SimplePrePostAstWalker implements AstWalker {
public options: AstWalkOptions = new AstWalkOptions();
constructor(
private pre: (ast: ISyntaxElement, state: any) => void,
private post: (ast: ISyntaxElement, state: any) => void,
public state: any) {
}
public walk(ast: ISyntaxElement): void {
if (!ast) {
return;
}
this.pre(ast, this.state);
var walker = childrenWalkers[ast.kind()];
if (walker) {
walker(ast, this);
}
this.post(ast, this.state);
}
}
class NormalAstWalker implements AstWalker {
public options: AstWalkOptions = new AstWalkOptions();
constructor(
private pre: (ast: ISyntaxElement, walker: IAstWalker) => void,
private post: (ast: ISyntaxElement, walker: IAstWalker) => void,
public state: any) {
}
public walk(ast: ISyntaxElement): void {
if (!ast) {
return;
}
// If we're stopping, then bail out immediately.
if (this.options.stopWalking) {
return;
}
this.pre(ast, this);
// If we were asked to stop, then stop.
if (this.options.stopWalking) {
return;
}
if (this.options.goChildren) {
// Call the "walkChildren" function corresponding to "nodeType".
var walker = childrenWalkers[ast.kind()];
if (walker) {
walker(ast, this);
}
}
else {
// no go only applies to children of node issuing it
this.options.goChildren = true;
}
if (this.post) {
this.post(ast, this);
}
}
}
export class AstWalkerFactory {
public walk(ast: ISyntaxElement, pre: (ast: ISyntaxElement, walker: IAstWalker) => void, post?: (ast: ISyntaxElement, walker: IAstWalker) => void, state?: any): void {
new NormalAstWalker(pre, post, state).walk(ast);
}
public simpleWalk(ast: ISyntaxElement, pre: (ast: ISyntaxElement, state: any) => void, post?: (ast: ISyntaxElement, state: any) => void, state?: any): void {
if (post) {
new SimplePrePostAstWalker(pre, post, state).walk(ast);
}
else {
new SimplePreAstWalker(pre, state).walk(ast);
}
}
}
var globalAstWalkerFactory = new AstWalkerFactory();
export function getAstWalkerFactory(): AstWalkerFactory {
return globalAstWalkerFactory;
}
}
@@ -476,8 +476,6 @@ module TypeScript {
//}
}
var funcPullDecl = this.semanticInfoChain.getDeclForAST(funcDecl);
var funcSignature = funcPullDecl.getSignatureSymbol(this.semanticInfoChain);
this.emitDeclarationComments(funcDecl);
this.emitIndent();
@@ -603,11 +601,6 @@ module TypeScript {
private emitConstructSignature(funcDecl: ConstructSignatureSyntax) {
var funcPullDecl = this.semanticInfoChain.getDeclForAST(funcDecl);
var start = new Date().getTime();
var funcSymbol = this.semanticInfoChain.getSymbolForAST(funcDecl);
TypeScript.declarationEmitFunctionDeclarationGetSymbolTime += new Date().getTime() - start;
this.emitDeclarationComments(funcDecl);
this.emitIndent();
@@ -633,11 +626,6 @@ module TypeScript {
private emitMethodSignature(funcDecl: MethodSignatureSyntax) {
var funcPullDecl = this.semanticInfoChain.getDeclForAST(funcDecl);
var start = new Date().getTime();
var funcSymbol = this.semanticInfoChain.getSymbolForAST(funcDecl);
TypeScript.declarationEmitFunctionDeclarationGetSymbolTime += new Date().getTime() - start;
this.emitDeclarationComments(funcDecl);
this.emitIndent();
@@ -817,7 +805,6 @@ module TypeScript {
var parameter = funcDecl.callSignature.parameterList.parameters[i];
var parameterDecl = this.semanticInfoChain.getDeclForAST(parameter);
if (hasFlag(parameterDecl.flags, PullElementFlags.PropertyParameter)) {
var funcPullDecl = this.semanticInfoChain.getDeclForAST(funcDecl);
this.emitDeclarationComments(parameter);
this.declFile.Write(this.getIndentString());
this.emitClassElementModifiers(parameter.modifiers);
@@ -838,7 +825,6 @@ module TypeScript {
var className = classDecl.identifier.text();
this.emitDeclarationComments(classDecl);
var classPullDecl = this.semanticInfoChain.getDeclForAST(classDecl);
this.emitDeclFlags(classDecl, "class");
this.declFile.Write(className);
@@ -934,7 +920,6 @@ module TypeScript {
var interfaceName = interfaceDecl.identifier.text();
this.emitDeclarationComments(interfaceDecl);
var interfacePullDecl = this.semanticInfoChain.getDeclForAST(interfaceDecl);
this.emitDeclFlags(interfaceDecl, "interface");
this.declFile.Write(interfaceName);
@@ -980,7 +965,6 @@ module TypeScript {
}
this.emitDeclarationComments(moduleDecl);
var modulePullDecl = this.semanticInfoChain.getDeclForAST(moduleDecl);
this.emitDeclFlags(moduleDecl, "enum");
this.declFile.WriteLine(moduleDecl.identifier.text() + " {");
-164
View File
@@ -16,56 +16,6 @@
///<reference path='references.ts' />
module TypeScript {
export function stripStartAndEndQuotes(str: string) {
var firstCharCode = str && str.charCodeAt(0);
if (str && str.length >= 2 && firstCharCode === str.charCodeAt(str.length - 1) && (firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote)) {
return str.substring(1, str.length - 1);
}
return str;
}
export function isSingleQuoted(str: string) {
return str && str.length >= 2 && str.charCodeAt(0) === str.charCodeAt(str.length - 1) && str.charCodeAt(0) === CharacterCodes.singleQuote;
}
export function isDoubleQuoted(str: string) {
return str && str.length >= 2 && str.charCodeAt(0) === str.charCodeAt(str.length - 1) && str.charCodeAt(0) === CharacterCodes.doubleQuote;
}
export function isQuoted(str: string) {
return isDoubleQuoted(str) || isSingleQuoted(str);
}
export function quoteStr(str: string) {
return "\"" + str + "\"";
}
var switchToForwardSlashesRegEx = /\\/g;
export function switchToForwardSlashes(path: string) {
return path.replace(switchToForwardSlashesRegEx, "/");
}
export function trimModName(modName: string) {
// in case's it's a declare file...
if (modName.length > 5 && modName.substring(modName.length - 5, modName.length) === ".d.ts") {
return modName.substring(0, modName.length - 5);
}
if (modName.length > 3 && modName.substring(modName.length - 3, modName.length) === ".ts") {
return modName.substring(0, modName.length - 3);
}
// in case's it's a .js file
if (modName.length > 3 && modName.substring(modName.length - 3, modName.length) === ".js") {
return modName.substring(0, modName.length - 3);
}
return modName;
}
export function getDeclareFilePath(fname: string) {
return isTSFile(fname) ? changePathToDTS(fname) : changePathToDTS(fname);
}
function isFileOfExtension(fname: string, ext: string) {
var invariantFname = fname.toLocaleUpperCase();
var invariantExt = ext.toLocaleUpperCase();
@@ -73,121 +23,7 @@ module TypeScript {
return invariantFname.length > extLength && invariantFname.substring(invariantFname.length - extLength, invariantFname.length) === invariantExt;
}
export function isTSFile(fname: string) {
return isFileOfExtension(fname, ".ts");
}
export function isDTSFile(fname: string) {
return isFileOfExtension(fname, ".d.ts");
}
export function getPrettyName(modPath: string, quote=true, treatAsFileName=false): any {
var modName = treatAsFileName ? switchToForwardSlashes(modPath) : trimModName(stripStartAndEndQuotes(modPath));
var components = this.getPathComponents(modName);
return components.length ? (quote ? quoteStr(components[components.length - 1]) : components[components.length - 1]) : modPath;
}
export function getPathComponents(path: string) {
return path.split("/");
}
export function getRelativePathToFixedPath(fixedModFilePath: string, absoluteModPath: string, isAbsoultePathURL = true) {
absoluteModPath = switchToForwardSlashes(absoluteModPath);
var modComponents = this.getPathComponents(absoluteModPath);
var fixedModComponents = this.getPathComponents(fixedModFilePath);
// Find the component that differs
var joinStartIndex = 0;
for (; joinStartIndex < modComponents.length && joinStartIndex < fixedModComponents.length ; joinStartIndex++) {
if (fixedModComponents[joinStartIndex] !== modComponents[joinStartIndex]) {
break;
}
}
// Get the relative path
if (joinStartIndex !== 0) {
var relativePath = "";
var relativePathComponents = modComponents.slice(joinStartIndex, modComponents.length);
for (; joinStartIndex < fixedModComponents.length; joinStartIndex++) {
if (fixedModComponents[joinStartIndex] !== "") {
relativePath = relativePath + "../";
}
}
return relativePath + relativePathComponents.join("/");
}
if (isAbsoultePathURL && absoluteModPath.indexOf("://") === -1) {
absoluteModPath = "file:///" + absoluteModPath;
}
return absoluteModPath;
}
export function changePathToDTS(modPath: string) {
return trimModName(stripStartAndEndQuotes(modPath)) + ".d.ts";
}
export function isRelative(path: string) {
return path.length > 0 && path.charAt(0) === ".";
}
export function isRooted(path: string) {
return path.length > 0 && (path.charAt(0) === "\\" || path.charAt(0) === "/" || (path.indexOf(":\\") !== -1) || (path.indexOf(":/") !== -1));
}
export function getRootFilePath(outFname: string) {
if (outFname === "") {
return outFname;
}
else {
var isPath = outFname.indexOf("/") !== -1;
return isPath ? filePath(outFname) : "";
}
}
export function filePathComponents(fullPath: string) {
fullPath = switchToForwardSlashes(fullPath);
var components = getPathComponents(fullPath);
return components.slice(0, components.length - 1);
}
export function filePath(fullPath: string) {
var path = filePathComponents(fullPath);
return path.join("/") + "/";
}
export function convertToDirectoryPath(dirPath: string) {
if (dirPath && dirPath.charAt(dirPath.length - 1) !== "/") {
dirPath += "/";
}
return dirPath;
}
var normalizePathRegEx = /^\\\\[^\\]/;
export function normalizePath(path: string): string {
// If it's a UNC style path (i.e. \\server\share), convert to a URI style (i.e. file://server/share)
if (normalizePathRegEx.test(path)) {
path = "file:" + path;
}
var parts = this.getPathComponents(switchToForwardSlashes(path));
var normalizedParts: string[] = [];
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
if (part === ".") {
continue;
}
if (normalizedParts.length > 0 && ArrayUtilities.last(normalizedParts) !== ".." && part === "..") {
normalizedParts.pop();
continue;
}
normalizedParts.push(part);
}
return normalizedParts.join("/");
}
}
-208
View File
@@ -1,208 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
module TypeScript {
export interface ILineAndCharacter {
line: number;
character: number;
}
// Note: This is being using by the host (VS) and is marshaled back and forth. When changing this make sure the changes
// are reflected in the managed side as well.
export interface IFileReference extends ILineAndCharacter {
path: string;
isResident: boolean;
position: number;
length: number;
}
///
/// Preprocessing
///
export interface IPreProcessedFileInfo {
referencedFiles: IFileReference[];
importedFiles: IFileReference[];
diagnostics: Diagnostic[];
isLibFile: boolean;
}
interface ITripleSlashDirectiveProperties {
noDefaultLib: boolean;
diagnostics: Diagnostic[];
referencedFiles: IFileReference[];
}
function isNoDefaultLibMatch(comment: string): RegExpExecArray {
var isNoDefaultLibRegex = /^(\/\/\/\s*<reference\s+no-default-lib=)('|")(.+?)\2\s*\/>/gim;
return isNoDefaultLibRegex.exec(comment);
}
export var tripleSlashReferenceRegExp = /^(\/\/\/\s*<reference\s+path=)('|")(.+?)\2\s*(static=('|")(.+?)\5\s*)*\/>/;
function getFileReferenceFromReferencePath(fileName: string, text: ISimpleText, position: number, comment: string, diagnostics: Diagnostic[]): IFileReference {
// First, just see if they've written: /// <reference\s+
// If so, then we'll consider this a reference directive and we'll report errors if it's
// malformed. Otherwise, we'll completely ignore this.
var lineMap = text.lineMap();
var simpleReferenceRegEx = /^\/\/\/\s*<reference\s+/gim;
if (simpleReferenceRegEx.exec(comment)) {
var isNoDefaultLib = isNoDefaultLibMatch(comment);
if (!isNoDefaultLib) {
var fullReferenceRegEx = tripleSlashReferenceRegExp;
var fullReference = fullReferenceRegEx.exec(comment);
if (!fullReference) {
// It matched the start of a reference directive, but wasn't well formed. Report
// an appropriate error to the user.
diagnostics.push(new Diagnostic(fileName, lineMap, position, comment.length, DiagnosticCode.Invalid_reference_directive_syntax));
}
else {
var path: string = normalizePath(fullReference[3]);
var adjustedPath = normalizePath(path);
var isResident = fullReference.length >= 7 && fullReference[6] === "true";
return {
line: 0,
character: 0,
position: 0,
length: 0,
path: switchToForwardSlashes(adjustedPath),
isResident: isResident
};
}
}
}
return null;
}
var reportDiagnostic = () => { };
function processImports(text: ISimpleText, scanner: Scanner.IScanner, token: ISyntaxToken, importedFiles: IFileReference[]): void {
var lineChar = { line: -1, character: -1 };
var lineMap = text.lineMap();
var start = new Date().getTime();
// Look for:
// import foo = module("foo")
while (token.kind() !== SyntaxKind.EndOfFileToken) {
if (token.kind() === SyntaxKind.ImportKeyword) {
var importToken = token;
token = scanner.scan(/*allowRegularExpression:*/ false);
if (SyntaxFacts.isIdentifierNameOrAnyKeyword(token)) {
token = scanner.scan(/*allowRegularExpression:*/ false);
if (token.kind() === SyntaxKind.EqualsToken) {
token = scanner.scan(/*allowRegularExpression:*/ false);
if (token.kind() === SyntaxKind.ModuleKeyword || token.kind() === SyntaxKind.RequireKeyword) {
token = scanner.scan(/*allowRegularExpression:*/ false);
if (token.kind() === SyntaxKind.OpenParenToken) {
token = scanner.scan(/*allowRegularExpression:*/ false);
lineMap.fillLineAndCharacterFromPosition(TypeScript.start(importToken, text), lineChar);
if (token.kind() === SyntaxKind.StringLiteral) {
var ref = {
line: lineChar.line,
character: lineChar.character,
position: TypeScript.start(token, text),
length: width(token),
path: stripStartAndEndQuotes(switchToForwardSlashes(token.text())),
isResident: false
};
importedFiles.push(ref);
}
}
}
}
}
}
token = scanner.scan(/*allowRegularExpression:*/ false);
}
var totalTime = new Date().getTime() - start;
//TypeScript.fileResolutionScanImportsTime += totalTime;
}
function processTripleSlashDirectives(fileName: string, text: ISimpleText, firstToken: ISyntaxToken): ITripleSlashDirectiveProperties {
var leadingTrivia = firstToken.leadingTrivia(text);
var position = 0;
var lineChar = { line: -1, character: -1 };
var noDefaultLib = false;
var diagnostics: Diagnostic[] = [];
var referencedFiles: IFileReference[] = [];
var lineMap = text.lineMap();
for (var i = 0, n = leadingTrivia.count(); i < n; i++) {
var trivia = leadingTrivia.syntaxTriviaAt(i);
if (trivia.kind() === SyntaxKind.SingleLineCommentTrivia) {
var triviaText = trivia.fullText();
var referencedCode = getFileReferenceFromReferencePath(fileName, text, position, triviaText, diagnostics);
if (referencedCode) {
lineMap.fillLineAndCharacterFromPosition(position, lineChar);
referencedCode.position = position;
referencedCode.length = trivia.fullWidth();
referencedCode.line = lineChar.line;
referencedCode.character = lineChar.character;
referencedFiles.push(referencedCode);
}
// is it a lib file?
var isNoDefaultLib = isNoDefaultLibMatch(triviaText);
if (isNoDefaultLib) {
noDefaultLib = isNoDefaultLib[3] === "true";
}
}
position += trivia.fullWidth();
}
return { noDefaultLib: noDefaultLib, diagnostics: diagnostics, referencedFiles: referencedFiles };
}
export function preProcessFile(fileName: string, sourceText: IScriptSnapshot, readImportFiles = true): IPreProcessedFileInfo {
var text = SimpleText.fromScriptSnapshot(sourceText);
var scanner = Scanner.createScanner(ts.ScriptTarget.ES5, text, reportDiagnostic);
var firstToken = scanner.scan(/*allowRegularExpression:*/ false);
// only search out dynamic mods
// if you find a dynamic mod, ignore every other mod inside, until you balance rcurlies
// var position
var importedFiles: IFileReference[] = [];
if (readImportFiles) {
processImports(text, scanner, firstToken, importedFiles);
}
var properties = processTripleSlashDirectives(fileName, text, firstToken);
return { referencedFiles: properties.referencedFiles, importedFiles: importedFiles, isLibFile: properties.noDefaultLib, diagnostics: properties.diagnostics };
}
export function getReferencedFiles(fileName: string, sourceText: IScriptSnapshot): IFileReference[] {
return preProcessFile(fileName, sourceText, false).referencedFiles;
}
} // Tools
-1
View File
@@ -12,7 +12,6 @@
/////<reference path='base64.ts' />
/////<reference path='sourceMapping.ts' />
/////<reference path='emitter.ts' />
/////<reference path='types.ts' />
/////<reference path='pathUtils.ts' />
/////<reference path='referenceResolution.ts' />
/////<reference path='precompile.ts' />
-102
View File
@@ -1,102 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='references.ts' />
module TypeScript {
export class MemberName {
public prefix: string = "";
public suffix: string = "";
public isString() { return false; }
public isArray() { return false; }
public isMarker() { return !this.isString() && !this.isArray(); }
public toString(): string {
return MemberName.memberNameToString(this);
}
static memberNameToString(memberName: MemberName, markerInfo?: number[], markerBaseLength: number = 0): string {
var result = memberName.prefix;
if (memberName.isString()) {
result += (<MemberNameString>memberName).text;
}
else if (memberName.isArray()) {
var ar = <MemberNameArray>memberName;
for (var index = 0; index < ar.entries.length; index++) {
if (ar.entries[index].isMarker()) {
if (markerInfo) {
markerInfo.push(markerBaseLength + result.length);
}
continue;
}
result += MemberName.memberNameToString(ar.entries[index], markerInfo, markerBaseLength + result.length);
result += ar.delim;
}
}
result += memberName.suffix;
return result;
}
static create(text: string): MemberName;
static create(entry: MemberName, prefix: string, suffix: string): MemberName;
static create(arg1: any, arg2?: any, arg3?: any): MemberName {
if (typeof arg1 === "string") {
return new MemberNameString(arg1);
}
else {
var result = new MemberNameArray();
if (arg2)
result.prefix = arg2;
if (arg3)
result.suffix = arg3;
result.entries.push(arg1);
return result;
}
}
}
export class MemberNameString extends MemberName {
constructor(public text: string) {
super();
}
public isString() { return true; }
}
export class MemberNameArray extends MemberName {
public delim: string = "";
public entries: MemberName[] = [];
public isArray() { return true; }
public add(entry: MemberName) {
this.entries.push(entry);
}
public addAll(entries: MemberName[]) {
for (var i = 0 ; i < entries.length; i++) {
this.entries.push(entries[i]);
}
}
constructor() {
super();
}
}
}
+1 -5
View File
@@ -512,7 +512,7 @@ module TypeScript {
for (var i = 0, n = fileNames.length; i < n; i++) {
var fileName = fileNames[i];
var document = this.getDocument(fileNames[i]);
var document = this.getDocument(fileName);
sharedEmitter = this._emitDocumentDeclarations(document, emitOptions,
file => emitOutput.outputFiles.push(file), sharedEmitter);
@@ -578,7 +578,6 @@ module TypeScript {
var sourceUnit = document.sourceUnit();
Debug.assert(this._shouldEmit(document));
var typeScriptFileName = document.fileName;
if (!emitter) {
var javaScriptFileName = this.mapOutputFileName(document, emitOptions, TypeScriptCompiler.mapToJSFileName);
var outFile = new TextWriter(javaScriptFileName, this.writeByteOrderMarkForDocument(document), OutputFileType.JavaScript);
@@ -799,8 +798,6 @@ module TypeScript {
}
private extractResolutionContextFromAST(resolver: PullTypeResolver, ast: ISyntaxElement, document: Document, propagateContextualTypes: boolean): { ast: ISyntaxElement; enclosingDecl: PullDecl; resolutionContext: PullTypeResolutionContext; inContextuallyTypedAssignment: boolean; inWithBlock: boolean; } {
var scriptName = document.fileName;
var enclosingDecl: PullDecl = null;
var enclosingDeclAST: ISyntaxElement = null;
var inContextuallyTypedAssignment = false;
@@ -981,7 +978,6 @@ module TypeScript {
case SyntaxKind.ReturnStatement:
if (propagateContextualTypes) {
var returnStatement = <ReturnStatementSyntax>current;
var contextualType: PullTypeSymbol = null;
if (enclosingDecl && (enclosingDecl.kind & PullElementKind.SomeFunction)) {
+3 -3
View File
@@ -7,7 +7,7 @@ module TypeScript {
return true;
}
if (array1 === null || array2 === null) {
if (!array1 || !array2) {
return false;
}
@@ -71,7 +71,7 @@ module TypeScript {
}
}
return null;
return undefined;
}
public static firstOrDefault<T>(array: T[], func: (v: T, index: number) => boolean): T {
@@ -82,7 +82,7 @@ module TypeScript {
}
}
return null;
return undefined;
}
public static first<T>(array: T[], func?: (v: T, index: number) => boolean): T {
+2 -1
View File
@@ -14,13 +14,14 @@ module TypeScript {
return this.currentAssertionLevel >= level;
}
public static assert(expression: any, message: string = "", verboseDebugInfo: () => string = null): void {
public static assert(expression: any, message?: string, verboseDebugInfo?: () => string): void {
if (!expression) {
var verboseDebugString = "";
if (verboseDebugInfo) {
verboseDebugString = "\r\nVerbose Debug Information:" + verboseDebugInfo();
}
message = message || "";
throw new Error("Debug Failure. False expression: " + message + verboseDebugString);
}
}
+3 -5
View File
@@ -1,8 +1,6 @@
///<reference path='references.ts' />
module TypeScript {
export var LocalizedDiagnosticMessages: ts.Map<any> = null;
export class Location {
private _fileName: string;
private _lineMap: LineMap;
@@ -52,11 +50,11 @@ module TypeScript {
private _arguments: any[];
private _additionalLocations: Location[];
constructor(fileName: string, lineMap: LineMap, start: number, length: number, diagnosticKey: string, _arguments: any[]= null, additionalLocations: Location[] = null) {
constructor(fileName: string, lineMap: LineMap, start: number, length: number, diagnosticKey: string, _arguments?: any[], additionalLocations?: Location[]) {
super(fileName, lineMap, start, length);
this._diagnosticKey = diagnosticKey;
this._arguments = (_arguments && _arguments.length > 0) ? _arguments : null;
this._additionalLocations = (additionalLocations && additionalLocations.length > 0) ? additionalLocations : null;
this._arguments = (_arguments && _arguments.length > 0) ? _arguments : undefined;
this._additionalLocations = (additionalLocations && additionalLocations.length > 0) ? additionalLocations : undefined;
}
public toJSON(key: any): any {
-6
View File
@@ -7,12 +7,6 @@ module TypeScript {
}
export function integerMultiplyLow32Bits(n1: number, n2: number): number {
var n1Low16 = n1 & 0x0000ffff;
var n1High16 = n1 >>> 16;
var n2Low16 = n2 & 0x0000ffff;
var n2High16 = n2 >>> 16;
var resultLow32 = (((n1 & 0xffff0000) * n2) >>> 0) + (((n1 & 0x0000ffff) * n2) >>> 0) >>> 0;
return resultLow32;
}
+7 -2
View File
@@ -1,9 +1,14 @@
///<reference path='references.ts' />
module TypeScript {
export interface ILineAndCharacter {
line: number;
character: number;
}
export class LineMap {
public static empty = new LineMap(() => [0], 0);
private _lineStarts: number[] = null;
private _lineStarts: number[] = undefined;
constructor(private _computeLineStarts: () => number[], private length: number) {
}
@@ -18,7 +23,7 @@ module TypeScript {
}
public lineStarts(): number[] {
if (this._lineStarts === null) {
if (!this._lineStarts) {
this._lineStarts = this._computeLineStarts();
}
+953
View File
@@ -0,0 +1,953 @@
///<reference path='services.ts' />
///<reference path='formatting\indentation.ts' />
///<reference path='formatting\formattingScanner.ts' />
///<reference path='formatting\rulesProvider.ts' />
module ts.formatting {
export interface TextRangeWithKind extends TextRange {
kind: SyntaxKind;
}
export interface TokenInfo {
leadingTrivia: TextRangeWithKind[];
token: TextRangeWithKind;
trailingTrivia: TextRangeWithKind[];
}
const enum Constants {
Unknown = -1
}
/*
* Indentation for the scope that can be dynamically recomputed.
* i.e
* while(true)
* { var x;
* }
* Normally indentation is applied only to the first token in line so at glance 'var' should not be touched.
* However if some format rule adds new line between '}' and 'var' 'var' will become
* the first token in line so it should be indented
*/
interface DynamicIndentation {
getIndentationForToken(tokenLine: number, tokenKind: SyntaxKind): number;
getIndentationForComment(owningToken: SyntaxKind): number;
/**
* Indentation for open and close tokens of the node if it is block or another node that needs special indentation
* ... {
* .........<child>
* ....}
* ____ - indentation
* ____ - delta
**/
getIndentation(): number;
/**
* Prefered relative indentation for child nodes.
* Delta is used to carry the indentation info
* foo(bar({
* $
* }))
* Both 'foo', 'bar' introduce new indentation with delta = 4, but total indentation in $ is not 8.
* foo: { indentation: 0, delta: 4 }
* bar: { indentation: foo.indentation + foo.delta = 4, delta: 4} however 'foo' and 'bar' are on the same line
* so bar inherits indentation from foo and bar.delta will be 4
*
*/
getDelta(): number;
/**
* Formatter calls this function when rule adds or deletes new lines from the text
* so indentation scope can adjust values of indentation and delta.
*/
recomputeIndentation(lineAddedByFormatting: boolean): void;
}
interface Indentation {
indentation: number;
delta: number
}
export function formatOnEnter(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
var line = sourceFile.getLineAndCharacterFromPosition(position).line;
Debug.assert(line >= 2);
// get the span for the previous\current line
var span = {
// get start position for the previous line
pos: getStartPositionOfLine(line - 1, sourceFile),
// get end position for the current line (end value is exclusive so add 1 to the result)
end: getEndLinePosition(line, sourceFile) + 1
}
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnEnter);
}
export function formatOnSemicolon(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
return formatOutermostParent(position, SyntaxKind.SemicolonToken, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnSemicolon);
}
export function formatOnClosingCurly(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
return formatOutermostParent(position, SyntaxKind.CloseBraceToken, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnClosingCurlyBrace);
}
export function formatDocument(sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
var span = {
pos: 0,
end: sourceFile.text.length
};
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatDocument);
}
export function formatSelection(start: number, end: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
// format from the beginning of the line
var span = {
pos: getStartLinePositionForPosition(start, sourceFile),
end: end
};
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatSelection);
}
function formatOutermostParent(position: number, expectedLastToken: SyntaxKind, sourceFile: SourceFile, options: FormatCodeOptions, rulesProvider: RulesProvider, requestKind: FormattingRequestKind): TextChange[] {
var parent = findOutermostParent(position, expectedLastToken, sourceFile);
if (!parent) {
return [];
}
var span = {
pos: getStartLinePositionForPosition(parent.getStart(sourceFile), sourceFile),
end: parent.end
};
return formatSpan(span, sourceFile, options, rulesProvider, requestKind);
}
function findOutermostParent(position: number, expectedTokenKind: SyntaxKind, sourceFile: SourceFile): Node {
var precedingToken = findPrecedingToken(position, sourceFile);
if (!precedingToken || precedingToken.kind !== expectedTokenKind) {
return undefined;
}
// walk up and search for the parent node that ends at the same position with precedingToken.
// for cases like this
//
// var x = 1;
// while (true) {
// }
// after typing close curly in while statement we want to reformat just the while statement.
// However if we just walk upwards searching for the parent that has the same end value -
// we'll end up with the whole source file. isListElement allows to stop on the list element level
var current = precedingToken;
while (current &&
current.parent &&
current.parent.end === precedingToken.end &&
!isListElement(current.parent, current)) {
current = current.parent;
}
return current;
}
// Returns true if node is a element in some list in parent
// i.e. parent is class declaration with the list of members and node is one of members.
function isListElement(parent: Node, node: Node): boolean {
switch (parent.kind) {
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
return rangeContainsRange((<InterfaceDeclaration>parent).members, node);
case SyntaxKind.ModuleDeclaration:
var body = (<ModuleDeclaration>parent).body;
return body && body.kind === SyntaxKind.Block && rangeContainsRange((<Block>body).statements, node);
case SyntaxKind.SourceFile:
case SyntaxKind.Block:
case SyntaxKind.TryBlock:
case SyntaxKind.CatchBlock:
case SyntaxKind.FinallyBlock:
case SyntaxKind.ModuleBlock:
return rangeContainsRange((<Block>parent).statements, node)
}
return false;
}
/** find node that fully contains given text range */
function findEnclosingNode(range: TextRange, sourceFile: SourceFile): Node {
return find(sourceFile);
function find(n: Node): Node {
var candidate = forEachChild(n, c => startEndContainsRange(c.getStart(sourceFile), c.end, range) && c);
if (candidate) {
var result = find(candidate);
if (result) {
return result;
}
}
return n;
}
}
/** formatting is not applied to ranges that contain parse errors.
* This function will return a predicate that for a given text range will tell
* if there are any parse errors that overlap with the range.
*/
function prepareRangeContainsErrorFunction(errors: Diagnostic[], originalRange: TextRange): (r: TextRange) => boolean {
if (!errors.length) {
return rangeHasNoErrors;
}
// pick only errors that fall in range
var sorted = errors
.filter(d => d.isParseError && rangeOverlapsWithStartEnd(originalRange, d.start, d.start + d.length))
.sort((e1, e2) => e1.start - e2.start);
if (!sorted.length) {
return rangeHasNoErrors;
}
var index = 0;
return r => {
// in current implementation sequence of arguments [r1, r2...] is monotonically increasing.
// 'index' tracks the index of the most recent error that was checked.
while (true) {
if (index >= sorted.length) {
// all errors in the range were already checked -> no error in specified range
return false;
}
var error = sorted[index];
if (r.end <= error.start) {
// specified range ends before the error refered by 'index' - no error in range
return false;
}
if (startEndOverlapsWithStartEnd(r.pos, r.end, error.start, error.start + error.length)) {
// specified range overlaps with error range
return true;
}
index++;
}
};
function rangeHasNoErrors(r: TextRange): boolean {
return false;
}
}
/**
* Start of the original range might fall inside the comment - scanner will not yield appropriate results
* This function will look for token that is located before the start of target range
* and return its end as start position for the scanner.
*/
function getScanStartPosition(enclosingNode: Node, originalRange: TextRange, sourceFile: SourceFile): number {
var start = enclosingNode.getStart(sourceFile);
if (start === originalRange.pos && enclosingNode.end === originalRange.end) {
return start;
}
var precedingToken = findPrecedingToken(originalRange.pos, sourceFile);
// no preceding token found - start from the beginning of enclosing node
return precedingToken ? precedingToken.end : enclosingNode.pos;
}
function formatSpan(originalRange: TextRange,
sourceFile: SourceFile,
options: FormatCodeOptions,
rulesProvider: RulesProvider,
requestKind: FormattingRequestKind): TextChange[] {
var rangeContainsError = prepareRangeContainsErrorFunction(sourceFile.getSyntacticDiagnostics(), originalRange);
// formatting context is used by rules provider
var formattingContext = new FormattingContext(sourceFile, requestKind);
// find the smallest node that fully wraps the range and compute the initial indentation for the node
var enclosingNode = findEnclosingNode(originalRange, sourceFile);
var formattingScanner = getFormattingScanner(sourceFile, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end);
var initialIndentation = SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, options);
var previousRangeHasError: boolean;
var previousRange: TextRangeWithKind;
var previousParent: Node;
var previousRangeStartLine: number;
var edits: TextChange[] = [];
formattingScanner.advance();
if (formattingScanner.isOnToken()) {
var startLine = sourceFile.getLineAndCharacterFromPosition(enclosingNode.getStart(sourceFile)).line;
var delta = SmartIndenter.shouldIndentChildNode(enclosingNode.kind, SyntaxKind.Unknown) ? options.IndentSize : 0;
processNode(enclosingNode, enclosingNode, startLine, initialIndentation, delta);
}
formattingScanner.close();
return edits;
// local functions
/** Tries to compute the indentation for a list element.
* If list element is not in range then
* function will pick its actual indentation
* so it can be pushed downstream as inherited indentation.
* If list element is in the range - its indentation will be equal
* to inherited indentation from its predecessors.
*/
function tryComputeIndentationForListItem(startPos: number,
endPos: number,
parentStartLine: number,
range: TextRange,
inheritedIndentation: number): number {
if (rangeOverlapsWithStartEnd(range, startPos, endPos)) {
if (inheritedIndentation !== Constants.Unknown) {
return inheritedIndentation;
}
}
else {
var startLine = sourceFile.getLineAndCharacterFromPosition(startPos).line;
var startLinePosition = getStartLinePositionForPosition(startPos, sourceFile);
var column = SmartIndenter.findFirstNonWhitespaceColumn(startLinePosition, startPos, sourceFile, options);
if (startLine !== parentStartLine || startPos === column) {
return column
}
}
return Constants.Unknown;
}
function computeIndentation(
node: TextRangeWithKind,
startLine: number,
inheritedIndentation: number,
parent: Node,
parentDynamicIndentation: DynamicIndentation,
effectiveParentStartLine: number): Indentation {
var indentation = inheritedIndentation;
if (indentation === Constants.Unknown) {
if (isSomeBlock(node.kind)) {
// blocks should be indented in
// - other blocks
// - source file
// - switch\default clauses
if (isSomeBlock(parent.kind) ||
parent.kind === SyntaxKind.SourceFile ||
parent.kind === SyntaxKind.CaseClause ||
parent.kind === SyntaxKind.DefaultClause) {
indentation = parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta();
}
else {
indentation = parentDynamicIndentation.getIndentation();
}
}
else {
if (SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(parent, node, startLine, sourceFile)) {
indentation = parentDynamicIndentation.getIndentation();
}
else {
indentation = parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta();
}
}
}
var delta = SmartIndenter.shouldIndentChildNode(node.kind, SyntaxKind.Unknown) ? options.IndentSize : 0;
if (effectiveParentStartLine === startLine) {
// if node is located on the same line with the parent
// - inherit indentation from the parent
// - push children if either parent of node itself has non-zero delta
indentation = parentDynamicIndentation.getIndentation();
delta = Math.min(options.IndentSize, parentDynamicIndentation.getDelta() + delta);
}
return {
indentation,
delta
}
}
function getDynamicIndentation(node: Node, nodeStartLine: number, indentation: number, delta: number): DynamicIndentation {
return {
getIndentationForComment: kind => {
switch (kind) {
// preceding comment to the token that closes the indentation scope inherits the indentation from the scope
// .. {
// // comment
// }
case SyntaxKind.CloseBraceToken:
case SyntaxKind.CloseBracketToken:
return indentation + delta;
}
return indentation;
},
getIndentationForToken: (line, kind) => {
switch (kind) {
// open and close brace, 'else' and 'while' (in do statement) tokens has indentation of the parent
case SyntaxKind.OpenBraceToken:
case SyntaxKind.CloseBraceToken:
case SyntaxKind.OpenBracketToken:
case SyntaxKind.CloseBracketToken:
case SyntaxKind.ElseKeyword:
case SyntaxKind.WhileKeyword:
return indentation;
default:
// if token line equals to the line of containing node (this is a first token in the node) - use node indentation
return nodeStartLine !== line ? indentation + delta : indentation;
}
},
getIndentation: () => indentation,
getDelta: () => delta,
recomputeIndentation: lineAdded => {
if (node.parent && SmartIndenter.shouldIndentChildNode(node.parent.kind, node.kind)) {
if (lineAdded) {
indentation += options.IndentSize;
}
else {
indentation -= options.IndentSize;
}
if (SmartIndenter.shouldIndentChildNode(node.kind, SyntaxKind.Unknown)) {
delta = options.IndentSize;
}
else {
delta = 0;
}
}
},
}
}
function processNode(node: Node, contextNode: Node, nodeStartLine: number, indentation: number, delta: number) {
if (!rangeOverlapsWithStartEnd(originalRange, node.getStart(sourceFile), node.getEnd())) {
return;
}
var nodeDynamicIndentation = getDynamicIndentation(node, nodeStartLine, indentation, delta);
// a useful observations when tracking context node
// /
// [a]
// / | \
// [b] [c] [d]
// node 'a' is a context node for nodes 'b', 'c', 'd'
// except for the leftmost leaf token in [b] - in this case context node ('e') is located somewhere above 'a'
// this rule can be applied recursively to child nodes of 'a'.
//
// context node is set to parent node value after processing every child node
// context node is set to parent of the token after processing every token
var childContextNode = contextNode;
// if there are any tokens that logically belong to node and interleave child nodes
// such tokens will be consumed in processChildNode for for the child that follows them
forEachChild(
node,
child => {
processChildNode(child, /*inheritedIndentation*/ Constants.Unknown, node, nodeDynamicIndentation, nodeStartLine, /*isListElement*/ false)
},
(nodes: NodeArray<Node>) => {
processChildNodes(nodes, node, nodeStartLine, nodeDynamicIndentation);
});
// proceed any tokens in the node that are located after child nodes
while (formattingScanner.isOnToken()) {
var tokenInfo = formattingScanner.readTokenInfo(node);
if (tokenInfo.token.end > node.end) {
break;
}
consumeTokenAndAdvanceScanner(tokenInfo, node, nodeDynamicIndentation);
}
function processChildNode(
child: Node,
inheritedIndentation: number,
parent: Node,
parentDynamicIndentation: DynamicIndentation,
parentStartLine: number,
isListItem: boolean): number {
var childStartPos = child.getStart(sourceFile);
var childStart = sourceFile.getLineAndCharacterFromPosition(childStartPos);
// if child is a list item - try to get its indentation
var childIndentationAmount = Constants.Unknown;
if (isListItem) {
childIndentationAmount = tryComputeIndentationForListItem(childStartPos, child.end, parentStartLine, originalRange, inheritedIndentation);
if (childIndentationAmount !== Constants.Unknown) {
inheritedIndentation = childIndentationAmount;
}
}
// child node is outside the target range - do not dive inside
if (!rangeOverlapsWithStartEnd(originalRange, child.pos, child.end)) {
return inheritedIndentation;
}
if (child.kind === SyntaxKind.Missing) {
return inheritedIndentation;
}
while (formattingScanner.isOnToken()) {
// proceed any parent tokens that are located prior to child.getStart()
var tokenInfo = formattingScanner.readTokenInfo(node);
if (tokenInfo.token.end > childStartPos) {
// stop when formatting scanner advances past the beginning of the child
break;
}
consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation);
}
if (!formattingScanner.isOnToken()) {
return inheritedIndentation;
}
if (isToken(child)) {
// if child node is a token, it does not impact indentation, proceed it using parent indentation scope rules
var tokenInfo = formattingScanner.readTokenInfo(node);
Debug.assert(tokenInfo.token.end === child.end);
consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation);
return inheritedIndentation;
}
var childIndentation = computeIndentation(child, childStart.line, childIndentationAmount, node, parentDynamicIndentation, parentStartLine);
processNode(child, childContextNode, childStart.line, childIndentation.indentation, childIndentation.delta);
childContextNode = node;
return inheritedIndentation;
}
function processChildNodes(nodes: NodeArray<Node>,
parent: Node,
parentStartLine: number,
parentDynamicIndentation: DynamicIndentation): void {
var listStartToken = getOpenTokenForList(parent, nodes);
var listEndToken = getCloseTokenForOpenToken(listStartToken);
var listDynamicIndentation = parentDynamicIndentation;
var startLine = parentStartLine;
if (listStartToken !== SyntaxKind.Unknown) {
// introduce a new indentation scope for lists (including list start and end tokens)
while (formattingScanner.isOnToken()) {
var tokenInfo = formattingScanner.readTokenInfo(parent);
if (tokenInfo.token.end > nodes.pos) {
// stop when formatting scanner moves past the beginning of node list
break;
}
else if (tokenInfo.token.kind === listStartToken) {
// consume list start token
startLine = sourceFile.getLineAndCharacterFromPosition(tokenInfo.token.pos).line;
var indentation =
computeIndentation(tokenInfo.token, startLine, Constants.Unknown, parent, parentDynamicIndentation, startLine);
listDynamicIndentation = getDynamicIndentation(parent, parentStartLine, indentation.indentation, indentation.delta);
consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation);
}
else {
// consume any tokens that precede the list as child elements of 'node' using its indentation scope
consumeTokenAndAdvanceScanner(tokenInfo, parent, parentDynamicIndentation);
}
}
}
var inheritedIndentation = Constants.Unknown;
for (var i = 0, len = nodes.length; i < len; ++i) {
inheritedIndentation = processChildNode(nodes[i], inheritedIndentation, node, listDynamicIndentation, startLine, /*isListElement*/ true)
}
if (listEndToken !== SyntaxKind.Unknown) {
if (formattingScanner.isOnToken()) {
var tokenInfo = formattingScanner.readTokenInfo(parent);
if (tokenInfo.token.kind === listEndToken) {
// consume list end token
consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation);
}
}
}
}
function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation): void {
Debug.assert(rangeContainsRange(parent, currentTokenInfo.token));
var lastTriviaWasNewLine = formattingScanner.lastTrailingTriviaWasNewLine();
var indentToken = false;
if (currentTokenInfo.leadingTrivia) {
processTrivia(currentTokenInfo.leadingTrivia, parent, childContextNode, dynamicIndentation);
}
var lineAdded: boolean;
var isTokenInRange = rangeContainsRange(originalRange, currentTokenInfo.token);
var tokenStart = sourceFile.getLineAndCharacterFromPosition(currentTokenInfo.token.pos);
if (isTokenInRange) {
// save prevStartLine since processRange will overwrite this value with current ones
var prevStartLine = previousRangeStartLine;
lineAdded = processRange(currentTokenInfo.token, tokenStart, parent, childContextNode, dynamicIndentation);
if (lineAdded !== undefined) {
indentToken = lineAdded;
}
else {
indentToken = lastTriviaWasNewLine && tokenStart.line !== prevStartLine;
}
}
if (currentTokenInfo.trailingTrivia) {
processTrivia(currentTokenInfo.trailingTrivia, parent, childContextNode, dynamicIndentation);
}
if (indentToken) {
var indentNextTokenOrTrivia = true;
if (currentTokenInfo.leadingTrivia) {
for (var i = 0, len = currentTokenInfo.leadingTrivia.length; i < len; ++i) {
var triviaItem = currentTokenInfo.leadingTrivia[i];
if (!rangeContainsRange(originalRange, triviaItem)) {
continue;
}
var triviaStartLine = sourceFile.getLineAndCharacterFromPosition(triviaItem.pos).line;
switch (triviaItem.kind) {
case SyntaxKind.MultiLineCommentTrivia:
var commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind);
indentMultilineComment(triviaItem, commentIndentation, /*firstLineIsIndented*/ !indentNextTokenOrTrivia);
indentNextTokenOrTrivia = false;
break;
case SyntaxKind.SingleLineCommentTrivia:
if (indentNextTokenOrTrivia) {
var commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind);
insertIndentation(triviaItem.pos, commentIndentation, /*lineAdded*/ false);
indentNextTokenOrTrivia = false;
}
break;
case SyntaxKind.NewLineTrivia:
indentNextTokenOrTrivia = true;
break;
}
}
}
// indent token only if is it is in target range and does not overlap with any error ranges
if (isTokenInRange && !rangeContainsError(currentTokenInfo.token)) {
var tokenIndentation = dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind);
insertIndentation(currentTokenInfo.token.pos, tokenIndentation, lineAdded);
}
}
formattingScanner.advance();
childContextNode = parent;
}
}
function processTrivia(trivia: TextRangeWithKind[], parent: Node, contextNode: Node, dynamicIndentation: DynamicIndentation): void {
for (var i = 0, len = trivia.length; i < len; ++i) {
var triviaItem = trivia[i];
if (isComment(triviaItem.kind) && rangeContainsRange(originalRange, triviaItem)) {
var triviaItemStart = sourceFile.getLineAndCharacterFromPosition(triviaItem.pos);
processRange(triviaItem, triviaItemStart, parent, contextNode, dynamicIndentation);
}
}
}
function processRange(range: TextRangeWithKind,
rangeStart: LineAndCharacter,
parent: Node,
contextNode: Node,
dynamicIndentation: DynamicIndentation): boolean {
var rangeHasError = rangeContainsError(range);
var lineAdded: boolean;
if (!rangeHasError && !previousRangeHasError) {
if (!previousRange) {
// trim whitespaces starting from the beginning of the span up to the current line
var originalStart = sourceFile.getLineAndCharacterFromPosition(originalRange.pos);
trimTrailingWhitespacesForLines(originalStart.line, rangeStart.line);
}
else {
lineAdded =
processPair(range, rangeStart.line, parent, previousRange, previousRangeStartLine, previousParent, contextNode, dynamicIndentation)
}
}
previousRange = range;
previousParent = parent;
previousRangeStartLine = rangeStart.line;
previousRangeHasError = rangeHasError;
return lineAdded;
}
function processPair(currentItem: TextRangeWithKind,
currentStartLine: number,
currentParent: Node,
previousItem: TextRangeWithKind,
previousStartLine: number,
previousParent: Node,
contextNode: Node,
dynamicIndentation: DynamicIndentation): boolean {
formattingContext.updateContext(previousItem, previousParent, currentItem, currentParent, contextNode);
var rule = rulesProvider.getRulesMap().GetRule(formattingContext);
var trimTrailingWhitespaces: boolean;
var lineAdded: boolean;
if (rule) {
applyRuleEdits(rule, previousItem, previousStartLine, currentItem, currentStartLine);
if (rule.Operation.Action & (RuleAction.Space | RuleAction.Delete) && currentStartLine !== previousStartLine) {
// Handle the case where the next line is moved to be the end of this line.
// In this case we don't indent the next line in the next pass.
if (currentParent.getStart(sourceFile) === currentItem.pos) {
lineAdded = false;
}
}
else if (rule.Operation.Action & RuleAction.NewLine && currentStartLine === previousStartLine) {
// Handle the case where token2 is moved to the new line.
// In this case we indent token2 in the next pass but we set
// sameLineIndent flag to notify the indenter that the indentation is within the line.
if (currentParent.getStart(sourceFile) === currentItem.pos) {
lineAdded = true;
}
}
if (lineAdded !== undefined) {
dynamicIndentation.recomputeIndentation(lineAdded);
}
// We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line
trimTrailingWhitespaces =
(rule.Operation.Action & (RuleAction.NewLine | RuleAction.Space)) &&
rule.Flag !== RuleFlags.CanDeleteNewLines;
}
else {
trimTrailingWhitespaces = true;
}
if (currentStartLine !== previousStartLine && trimTrailingWhitespaces) {
// We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line
trimTrailingWhitespacesForLines(previousStartLine, currentStartLine, previousItem);
}
return lineAdded;
}
function insertIndentation(pos: number, indentation: number, lineAdded: boolean): void {
var indentationString = getIndentationString(indentation, options);
if (lineAdded) {
// new line is added before the token by the formatting rules
// insert indentation string at the very beginning of the token
recordReplace(pos, 0, indentationString);
}
else {
var tokenStart = sourceFile.getLineAndCharacterFromPosition(pos);
if (indentation !== tokenStart.character - 1) {
var startLinePosition = getStartPositionOfLine(tokenStart.line, sourceFile);
recordReplace(startLinePosition, tokenStart.character - 1, indentationString);
}
}
}
function indentMultilineComment(commentRange: TextRange, indentation: number, firstLineIsIndented: boolean) {
// split comment in lines
var startLine = sourceFile.getLineAndCharacterFromPosition(commentRange.pos).line;
var endLine = sourceFile.getLineAndCharacterFromPosition(commentRange.end).line;
if (startLine === endLine) {
if (!firstLineIsIndented) {
// treat as single line comment
insertIndentation(commentRange.pos, indentation, /*lineAdded*/ false);
}
return;
}
else {
var parts: TextRange[] = [];
var startPos = commentRange.pos;
for (var line = startLine; line < endLine; ++line) {
var endOfLine = getEndLinePosition(line, sourceFile);
parts.push({ pos: startPos, end: endOfLine });
startPos = getStartPositionOfLine(line + 1, sourceFile);
}
parts.push({ pos: startPos, end: commentRange.end });
}
var startLinePos = getStartPositionOfLine(startLine, sourceFile);
var nonWhitespaceColumnInFirstPart =
SmartIndenter.findFirstNonWhitespaceColumn(startLinePos, parts[0].pos, sourceFile, options);
if (indentation === nonWhitespaceColumnInFirstPart) {
return;
}
var startIndex = 0;
if (firstLineIsIndented) {
startIndex = 1;
startLine++;
}
// shift all parts on the delta size
var delta = indentation - nonWhitespaceColumnInFirstPart;
for (var i = startIndex, len = parts.length; i < len; ++i, ++startLine) {
var startLinePos = getStartPositionOfLine(startLine, sourceFile);
var nonWhitespaceColumn =
i === 0
? nonWhitespaceColumnInFirstPart
: SmartIndenter.findFirstNonWhitespaceColumn(parts[i].pos, parts[i].end, sourceFile, options);
var newIndentation = nonWhitespaceColumn + delta;
if (newIndentation > 0) {
var indentationString = getIndentationString(newIndentation, options);
recordReplace(startLinePos, nonWhitespaceColumn, indentationString);
}
else {
recordDelete(startLinePos, nonWhitespaceColumn);
}
}
}
function trimTrailingWhitespacesForLines(line1: number, line2: number, range?: TextRangeWithKind) {
for (var line = line1; line < line2; ++line) {
var lineStartPosition = getStartPositionOfLine(line, sourceFile);
var lineEndPosition = getEndLinePosition(line, sourceFile);
// do not trim whitespaces in comments
if (range && isComment(range.kind) && range.pos <= lineEndPosition && range.end > lineEndPosition) {
continue;
}
var pos = lineEndPosition;
while (pos >= lineStartPosition && isWhiteSpace(sourceFile.text.charCodeAt(pos))) {
pos--;
}
if (pos !== lineEndPosition) {
Debug.assert(pos === lineStartPosition || !isWhiteSpace(sourceFile.text.charCodeAt(pos)));
recordDelete(pos + 1, lineEndPosition - pos);
}
}
}
function newTextChange(start: number, len: number, newText: string): TextChange {
return { span: new TextSpan(start, len), newText }
}
function recordDelete(start: number, len: number) {
if (len) {
edits.push(newTextChange(start, len, ""));
}
}
function recordReplace(start: number, len: number, newText: string) {
if (len || newText) {
edits.push(newTextChange(start, len, newText));
}
}
function applyRuleEdits(rule: Rule,
previousRange: TextRangeWithKind,
previousStartLine: number,
currentRange: TextRangeWithKind,
currentStartLine: number): void {
var between: TextRange;
switch (rule.Operation.Action) {
case RuleAction.Ignore:
// no action required
return;
case RuleAction.Delete:
if (previousRange.end !== currentRange.pos) {
// delete characters starting from t1.end up to t2.pos exclusive
recordDelete(previousRange.end, currentRange.pos - previousRange.end);
}
break;
case RuleAction.NewLine:
// exit early if we on different lines and rule cannot change number of newlines
// if line1 and line2 are on subsequent lines then no edits are required - ok to exit
// if line1 and line2 are separated with more than one newline - ok to exit since we cannot delete extra new lines
if (rule.Flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) {
return;
}
// edit should not be applied only if we have one line feed between elements
var lineDelta = currentStartLine - previousStartLine;
if (lineDelta !== 1) {
recordReplace(previousRange.end, currentRange.pos - previousRange.end, options.NewLineCharacter);
}
break;
case RuleAction.Space:
// exit early if we on different lines and rule cannot change number of newlines
if (rule.Flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) {
return;
}
var posDelta = currentRange.pos - previousRange.end;
if (posDelta !== 1 || sourceFile.text.charCodeAt(previousRange.end) !== CharacterCodes.space) {
recordReplace(previousRange.end, currentRange.pos - previousRange.end, " ");
}
break;
}
}
}
function isSomeBlock(kind: SyntaxKind): boolean {
switch (kind) {
case SyntaxKind.Block:
case SyntaxKind.FunctionBlock:
case SyntaxKind.TryBlock:
case SyntaxKind.CatchBlock:
case SyntaxKind.FinallyBlock:
case SyntaxKind.ModuleBlock:
return true;
}
return false;
}
function getOpenTokenForList(node: Node, list: Node[]) {
switch (node.kind) {
case SyntaxKind.Constructor:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.Method:
case SyntaxKind.ArrowFunction:
if ((<FunctionDeclaration>node).typeParameters === list) {
return SyntaxKind.LessThanToken;
}
else if ((<FunctionDeclaration>node).parameters === list) {
return SyntaxKind.OpenParenToken;
}
break;
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
if ((<CallExpression>node).typeArguments === list) {
return SyntaxKind.LessThanToken;
}
else if ((<CallExpression>node).arguments === list) {
return SyntaxKind.OpenParenToken;
}
break;
case SyntaxKind.TypeReference:
if ((<TypeReferenceNode>node).typeArguments === list) {
return SyntaxKind.LessThanToken;
}
}
return SyntaxKind.Unknown;
}
function getCloseTokenForOpenToken(kind: SyntaxKind) {
switch (kind) {
case SyntaxKind.OpenParenToken:
return SyntaxKind.CloseParenToken;
case SyntaxKind.LessThanToken:
return SyntaxKind.GreaterThanToken;
}
return SyntaxKind.Unknown;
}
}
-320
View File
@@ -1,320 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class Formatter extends MultipleTokenIndenter {
private previousTokenSpan: TokenSpan = null;
private previousTokenParent: IndentationNodeContext = null;
// TODO: implement it with skipped tokens in Fidelity
private scriptHasErrors: boolean = false;
private rulesProvider: RulesProvider;
private formattingRequestKind: FormattingRequestKind;
private formattingContext: FormattingContext;
constructor(textSpan: TextSpan,
sourceUnit: SourceUnitSyntax,
indentFirstToken: boolean,
options: FormattingOptions,
snapshot: ITextSnapshot,
rulesProvider: RulesProvider,
formattingRequestKind: FormattingRequestKind) {
super(textSpan, sourceUnit, snapshot, indentFirstToken, options);
this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool());
this.rulesProvider = rulesProvider;
this.formattingRequestKind = formattingRequestKind;
this.formattingContext = new FormattingContext(this.snapshot(), this.formattingRequestKind);
}
public static getEdits(textSpan: TextSpan,
sourceUnit: SourceUnitSyntax,
options: FormattingOptions,
indentFirstToken: boolean,
snapshot: ITextSnapshot,
rulesProvider: RulesProvider,
formattingRequestKind: FormattingRequestKind): TextEditInfo[] {
var walker = new Formatter(textSpan, sourceUnit, indentFirstToken, options, snapshot, rulesProvider, formattingRequestKind);
visitNodeOrToken(walker, sourceUnit);
return walker.edits();
}
public visitTokenInSpan(token: ISyntaxToken): void {
if (token.fullWidth() !== 0) {
var tokenSpan = new TextSpan(this.position() + token.leadingTriviaWidth(), width(token));
if (this.textSpan().containsTextSpan(tokenSpan)) {
this.processToken(token);
}
}
// Call the base class to process the token and indent it if needed
super.visitTokenInSpan(token);
}
private processToken(token: ISyntaxToken): void {
var position = this.position();
// Extract any leading comments
if (token.leadingTriviaWidth() !== 0) {
this.processTrivia(token.leadingTrivia(), position);
position += token.leadingTriviaWidth();
}
// Push the token
var currentTokenSpan = new TokenSpan(token.kind(), position, width(token));
if (!this.parent().hasSkippedOrMissingTokenChild()) {
if (this.previousTokenSpan) {
// Note that formatPair calls TrimWhitespaceInLineRange in between the 2 tokens
this.formatPair(this.previousTokenSpan, this.previousTokenParent, currentTokenSpan, this.parent());
}
else {
// We still want to trim whitespace even if it is the first trivia of the first token. Trim from the beginning of the span to the trivia
this.trimWhitespaceInLineRange(this.getLineNumber(this.textSpan()), this.getLineNumber(currentTokenSpan));
}
}
this.previousTokenSpan = currentTokenSpan;
if (this.previousTokenParent) {
// Make sure to clear the previous parent before assigning a new value to it
this.indentationNodeContextPool().releaseNode(this.previousTokenParent, /* recursive */true);
}
this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool());
position += width(token);
// Extract any trailing comments
if (token.trailingTriviaWidth() !== 0) {
this.processTrivia(token.trailingTrivia(), position);
}
}
private processTrivia(triviaList: ISyntaxTriviaList, fullStart: number) {
var position = fullStart;
for (var i = 0, n = triviaList.count(); i < n ; i++) {
var trivia = triviaList.syntaxTriviaAt(i);
// For a comment, format it like it is a token. For skipped text, eat it up as a token, but skip the formatting
if (trivia.isComment() || trivia.isSkippedToken()) {
var currentTokenSpan = new TokenSpan(trivia.kind(), position, trivia.fullWidth());
if (this.textSpan().containsTextSpan(currentTokenSpan)) {
if (trivia.isComment() && this.previousTokenSpan) {
// Note that formatPair calls TrimWhitespaceInLineRange in between the 2 tokens
this.formatPair(this.previousTokenSpan, this.previousTokenParent, currentTokenSpan, this.parent());
}
else {
// We still want to trim whitespace even if it is the first trivia of the first token. Trim from the beginning of the span to the trivia
var startLine = this.getLineNumber(this.previousTokenSpan || this.textSpan());
this.trimWhitespaceInLineRange(startLine, this.getLineNumber(currentTokenSpan));
}
this.previousTokenSpan = currentTokenSpan;
if (this.previousTokenParent) {
// Make sure to clear the previous parent before assigning a new value to it
this.indentationNodeContextPool().releaseNode(this.previousTokenParent, /* recursive */true);
}
this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool());
}
}
position += trivia.fullWidth();
}
}
private findCommonParents(parent1: IndentationNodeContext, parent2: IndentationNodeContext): IndentationNodeContext {
// TODO: disable debug assert message
var shallowParent: IndentationNodeContext;
var shallowParentDepth: number;
var deepParent: IndentationNodeContext;
var deepParentDepth: number;
if (parent1.depth() < parent2.depth()) {
shallowParent = parent1;
shallowParentDepth = parent1.depth();
deepParent = parent2;
deepParentDepth = parent2.depth();
}
else {
shallowParent = parent2;
shallowParentDepth = parent2.depth();
deepParent = parent1;
deepParentDepth = parent1.depth();
}
Debug.assert(shallowParentDepth >= 0, "Expected shallowParentDepth >= 0");
Debug.assert(deepParentDepth >= 0, "Expected deepParentDepth >= 0");
Debug.assert(deepParentDepth >= shallowParentDepth, "Expected deepParentDepth >= shallowParentDepth");
while (deepParentDepth > shallowParentDepth) {
deepParent = <IndentationNodeContext>deepParent.parent();
deepParentDepth--;
}
Debug.assert(deepParentDepth === shallowParentDepth, "Expected deepParentDepth === shallowParentDepth");
while (deepParent.node() && shallowParent.node()) {
if (deepParent.node() === shallowParent.node()) {
return deepParent;
}
deepParent = <IndentationNodeContext>deepParent.parent();
shallowParent = <IndentationNodeContext>shallowParent.parent();
}
// The root should be the first element in the parent chain, we can not be here unless something wrong
// happened along the way
throw Errors.invalidOperation();
}
private formatPair(t1: TokenSpan, t1Parent: IndentationNodeContext, t2: TokenSpan, t2Parent: IndentationNodeContext): void {
var token1Line = this.getLineNumber(t1);
var token2Line = this.getLineNumber(t2);
// Find common parent
var commonParent= this.findCommonParents(t1Parent, t2Parent);
// Update the context
this.formattingContext.updateContext(t1, t1Parent, t2, t2Parent, commonParent);
// Find rules matching the current context
var rule = this.rulesProvider.getRulesMap().GetRule(this.formattingContext);
if (rule != null) {
// Record edits from the rule
this.RecordRuleEdits(rule, t1, t2);
// Handle the case where the next line is moved to be the end of this line.
// In this case we don't indent the next line in the next pass.
if ((rule.Operation.Action == RuleAction.Space || rule.Operation.Action == RuleAction.Delete) &&
token1Line != token2Line) {
this.forceSkipIndentingNextToken(t2.start());
}
// Handle the case where token2 is moved to the new line.
// In this case we indent token2 in the next pass but we set
// sameLineIndent flag to notify the indenter that the indentation is within the line.
if (rule.Operation.Action == RuleAction.NewLine && token1Line == token2Line) {
this.forceIndentNextToken(t2.start());
}
}
// We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line
if (token1Line != token2Line && (!rule || (rule.Operation.Action != RuleAction.Delete && rule.Flag != RuleFlags.CanDeleteNewLines))) {
this.trimWhitespaceInLineRange(token1Line, token2Line, t1);
}
}
private getLineNumber(span: TextSpan): number {
return this.snapshot().getLineNumberFromPosition(span.start());
}
private trimWhitespaceInLineRange(startLine: number, endLine: number, token?: TokenSpan): void {
for (var lineNumber = startLine; lineNumber < endLine; ++lineNumber) {
var line = this.snapshot().getLineFromLineNumber(lineNumber);
this.trimWhitespace(line, token);
}
}
private trimWhitespace(line: ITextSnapshotLine, token?: TokenSpan): void {
// Don't remove the trailing spaces inside comments (this includes line comments and block comments)
if (token && (token.kind == SyntaxKind.MultiLineCommentTrivia || token.kind == SyntaxKind.SingleLineCommentTrivia) && token.start() <= line.endPosition() && token.end() >= line.endPosition())
return;
var text = line.getText();
var index = 0;
for (index = text.length - 1; index >= 0; --index) {
if (!CharacterInfo.isWhitespace(text.charCodeAt(index))) {
break;
}
}
++index;
if (index < text.length) {
this.recordEdit(line.startPosition() + index, line.length() - index, "");
}
}
private RecordRuleEdits(rule: Rule, t1: TokenSpan, t2: TokenSpan): void {
if (rule.Operation.Action == RuleAction.Ignore) {
return;
}
var betweenSpan: TextSpan;
switch (rule.Operation.Action) {
case RuleAction.Delete:
{
betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end());
if (betweenSpan.length() > 0) {
this.recordEdit(betweenSpan.start(), betweenSpan.length(), "");
return;
}
}
break;
case RuleAction.NewLine:
{
if (!(rule.Flag == RuleFlags.CanDeleteNewLines || this.getLineNumber(t1) == this.getLineNumber(t2))) {
return;
}
betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end());
var doEdit = false;
var betweenText = this.snapshot().getText(betweenSpan);
var lineFeedLoc = betweenText.indexOf(this.options.newLineCharacter);
if (lineFeedLoc < 0) {
// no linefeeds, do the edit
doEdit = true;
}
else {
// We only require one line feed. If there is another one, do the edit
lineFeedLoc = betweenText.indexOf(this.options.newLineCharacter, lineFeedLoc + 1);
if (lineFeedLoc >= 0) {
doEdit = true;
}
}
if (doEdit) {
this.recordEdit(betweenSpan.start(), betweenSpan.length(), this.options.newLineCharacter);
return;
}
}
break;
case RuleAction.Space:
{
if (!(rule.Flag == RuleFlags.CanDeleteNewLines || this.getLineNumber(t1) == this.getLineNumber(t2))) {
return;
}
betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end());
if (betweenSpan.length() > 1 || this.snapshot().getText(betweenSpan) != " ") {
this.recordEdit(betweenSpan.start(), betweenSpan.length(), " ");
return;
}
}
break;
}
}
}
}
+46 -47
View File
@@ -13,48 +13,48 @@
// limitations under the License.
//
/// <reference path="formatting.ts"/>
/// <reference path="references.ts"/>
module TypeScript.Services.Formatting {
module ts.formatting {
export class FormattingContext {
public currentTokenSpan: TokenSpan = null;
public nextTokenSpan: TokenSpan = null;
public contextNode: IndentationNodeContext = null;
public currentTokenParent: IndentationNodeContext = null;
public nextTokenParent: IndentationNodeContext = null;
public currentTokenSpan: TextRangeWithKind;
public nextTokenSpan: TextRangeWithKind;
public contextNode: Node;
public currentTokenParent: Node;
public nextTokenParent: Node;
private contextNodeAllOnSameLine: boolean = null;
private nextNodeAllOnSameLine: boolean = null;
private tokensAreOnSameLine: boolean = null;
private contextNodeBlockIsOnOneLine: boolean = null;
private nextNodeBlockIsOnOneLine: boolean = null;
private contextNodeAllOnSameLine: boolean;
private nextNodeAllOnSameLine: boolean;
private tokensAreOnSameLine: boolean;
private contextNodeBlockIsOnOneLine: boolean;
private nextNodeBlockIsOnOneLine: boolean;
constructor(private snapshot: ITextSnapshot, public formattingRequestKind: FormattingRequestKind) {
Debug.assert(this.snapshot != null, "snapshot is null");
constructor(private sourceFile: SourceFile, public formattingRequestKind: FormattingRequestKind) {
}
public updateContext(currentTokenSpan: TokenSpan, currentTokenParent: IndentationNodeContext, nextTokenSpan: TokenSpan, nextTokenParent: IndentationNodeContext, commonParent: IndentationNodeContext) {
Debug.assert(currentTokenSpan != null, "currentTokenSpan is null");
Debug.assert(currentTokenParent != null, "currentTokenParent is null");
Debug.assert(nextTokenSpan != null, "nextTokenSpan is null");
Debug.assert(nextTokenParent != null, "nextTokenParent is null");
Debug.assert(commonParent != null, "commonParent is null");
public updateContext(currentRange: TextRangeWithKind, currentTokenParent: Node, nextRange: TextRangeWithKind, nextTokenParent: Node, commonParent: Node) {
Debug.assert(currentRange !== undefined, "currentTokenSpan is null");
Debug.assert(currentTokenParent !== undefined, "currentTokenParent is null");
Debug.assert(nextRange !== undefined, "nextTokenSpan is null");
Debug.assert(nextTokenParent !== undefined, "nextTokenParent is null");
Debug.assert(commonParent !== undefined, "commonParent is null");
this.currentTokenSpan = currentTokenSpan;
this.currentTokenSpan = currentRange;
this.currentTokenParent = currentTokenParent;
this.nextTokenSpan = nextTokenSpan;
this.nextTokenSpan = nextRange;
this.nextTokenParent = nextTokenParent;
this.contextNode = commonParent;
this.contextNodeAllOnSameLine = null;
this.nextNodeAllOnSameLine = null;
this.tokensAreOnSameLine = null;
this.contextNodeBlockIsOnOneLine = null;
this.nextNodeBlockIsOnOneLine = null;
// drop cached results
this.contextNodeAllOnSameLine = undefined;
this.nextNodeAllOnSameLine = undefined;
this.tokensAreOnSameLine = undefined;
this.contextNodeBlockIsOnOneLine = undefined;
this.nextNodeBlockIsOnOneLine = undefined;
}
public ContextNodeAllOnSameLine(): boolean {
if (this.contextNodeAllOnSameLine === null) {
if (this.contextNodeAllOnSameLine === undefined) {
this.contextNodeAllOnSameLine = this.NodeIsOnOneLine(this.contextNode);
}
@@ -62,7 +62,7 @@ module TypeScript.Services.Formatting {
}
public NextNodeAllOnSameLine(): boolean {
if (this.nextNodeAllOnSameLine === null) {
if (this.nextNodeAllOnSameLine === undefined) {
this.nextNodeAllOnSameLine = this.NodeIsOnOneLine(this.nextTokenParent);
}
@@ -70,10 +70,9 @@ module TypeScript.Services.Formatting {
}
public TokensAreOnSameLine(): boolean {
if (this.tokensAreOnSameLine === null) {
var startLine = this.snapshot.getLineNumberFromPosition(this.currentTokenSpan.start());
var endLine = this.snapshot.getLineNumberFromPosition(this.nextTokenSpan.start());
if (this.tokensAreOnSameLine === undefined) {
var startLine = this.sourceFile.getLineAndCharacterFromPosition(this.currentTokenSpan.pos).line;
var endLine = this.sourceFile.getLineAndCharacterFromPosition(this.nextTokenSpan.pos).line;
this.tokensAreOnSameLine = (startLine == endLine);
}
@@ -81,7 +80,7 @@ module TypeScript.Services.Formatting {
}
public ContextNodeBlockIsOnOneLine() {
if (this.contextNodeBlockIsOnOneLine === null) {
if (this.contextNodeBlockIsOnOneLine === undefined) {
this.contextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.contextNode);
}
@@ -89,28 +88,28 @@ module TypeScript.Services.Formatting {
}
public NextNodeBlockIsOnOneLine() {
if (this.nextNodeBlockIsOnOneLine === null) {
if (this.nextNodeBlockIsOnOneLine === undefined) {
this.nextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.nextTokenParent);
}
return this.nextNodeBlockIsOnOneLine;
}
public NodeIsOnOneLine(node: IndentationNodeContext): boolean {
var startLine = this.snapshot.getLineNumberFromPosition(node.start());
var endLine = this.snapshot.getLineNumberFromPosition(node.end());
private NodeIsOnOneLine(node: Node): boolean {
var startLine = this.sourceFile.getLineAndCharacterFromPosition(node.getStart(this.sourceFile)).line;
var endLine = this.sourceFile.getLineAndCharacterFromPosition(node.getEnd()).line;
return startLine == endLine;
}
// Now we know we have a block (or a fake block represented by some other kind of node with an open and close brace as children).
// IMPORTANT!!! This relies on the invariant that IsBlockContext must return true ONLY for nodes with open and close braces as immediate children
public BlockIsOnOneLine(node: IndentationNodeContext): boolean {
var block = <BlockSyntax>node.node();
// Now check if they are on the same line
return this.snapshot.getLineNumberFromPosition(end(block.openBraceToken)) ===
this.snapshot.getLineNumberFromPosition(start(block.closeBraceToken));
private BlockIsOnOneLine(node: Node): boolean {
var openBrace = findChildOfKind(node, SyntaxKind.OpenBraceToken, this.sourceFile);
var closeBrace = findChildOfKind(node, SyntaxKind.CloseBraceToken, this.sourceFile);
if (openBrace && closeBrace) {
var startLine = this.sourceFile.getLineAndCharacterFromPosition(openBrace.getEnd()).line;
var endLine = this.sourceFile.getLineAndCharacterFromPosition(closeBrace.getStart(this.sourceFile)).line;
return startLine === endLine;
}
return false;
}
}
}
@@ -1,123 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/// <reference path="formatting.ts"/>
module TypeScript.Services.Formatting {
export class FormattingManager {
private options: FormattingOptions;
constructor(private syntaxTree: SyntaxTree,
private snapshot: ITextSnapshot,
private rulesProvider: RulesProvider,
editorOptions: ts.EditorOptions) {
//
// TODO: convert to use FormattingOptions instead of EditorOptions
this.options = new FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter)
}
public formatSelection(minChar: number, limChar: number): ts.TextChange[] {
var span = TextSpan.fromBounds(minChar, limChar);
return this.formatSpan(span, FormattingRequestKind.FormatSelection);
}
public formatDocument(): ts.TextChange[] {
var span = TextSpan.fromBounds(0, this.snapshot.getLength());
return this.formatSpan(span, FormattingRequestKind.FormatDocument);
}
public formatOnSemicolon(caretPosition: number): ts.TextChange[] {
var sourceUnit = this.syntaxTree.sourceUnit();
var semicolonPositionedToken = findToken(sourceUnit, caretPosition - 1);
if (semicolonPositionedToken.kind() === SyntaxKind.SemicolonToken) {
// Find the outer most parent that this semicolon terminates
var current: ISyntaxElement = semicolonPositionedToken;
while (current.parent !== null &&
end(current.parent) === end(semicolonPositionedToken) &&
current.parent.kind() !== SyntaxKind.List) {
current = current.parent;
}
// Compute the span
var span = new TextSpan(fullStart(current), fullWidth(current));
// Format the span
return this.formatSpan(span, FormattingRequestKind.FormatOnSemicolon);
}
return [];
}
public formatOnClosingCurlyBrace(caretPosition: number): ts.TextChange[] {
var sourceUnit = this.syntaxTree.sourceUnit();
var closeBracePositionedToken = findToken(sourceUnit, caretPosition - 1);
if (closeBracePositionedToken.kind() === SyntaxKind.CloseBraceToken) {
// Find the outer most parent that this closing brace terminates
var current: ISyntaxElement = closeBracePositionedToken;
while (current.parent !== null &&
end(current.parent) === end(closeBracePositionedToken) &&
current.parent.kind() !== SyntaxKind.List) {
current = current.parent;
}
// Compute the span
var span = new TextSpan(fullStart(current), fullWidth(current));
// Format the span
return this.formatSpan(span, FormattingRequestKind.FormatOnClosingCurlyBrace);
}
return [];
}
public formatOnEnter(caretPosition: number): ts.TextChange[] {
var lineNumber = this.snapshot.getLineNumberFromPosition(caretPosition);
if (lineNumber > 0) {
// Format both lines
var prevLine = this.snapshot.getLineFromLineNumber(lineNumber - 1);
var currentLine = this.snapshot.getLineFromLineNumber(lineNumber);
var span = TextSpan.fromBounds(prevLine.startPosition(), currentLine.endPosition());
// Format the span
return this.formatSpan(span, FormattingRequestKind.FormatOnEnter);
}
return [];
}
private formatSpan(span: TextSpan, formattingRequestKind: FormattingRequestKind): ts.TextChange[] {
// Always format from the beginning of the line
var startLine = this.snapshot.getLineFromPosition(span.start());
span = TextSpan.fromBounds(startLine.startPosition(), span.end());
var result: ts.TextChange[] = [];
var formattingEdits = Formatter.getEdits(span, this.syntaxTree.sourceUnit(), this.options, true, this.snapshot, this.rulesProvider, formattingRequestKind);
//
// TODO: Change the ILanguageService interface to return TextEditInfo (with start, and length) instead of TextEdit (with minChar and limChar)
formattingEdits.forEach((item) => {
var edit = new ts.TextChange(new TextSpan(item.position, item.length), item.replaceWith);
result.push(edit);
});
return result;
}
}
}
@@ -13,15 +13,14 @@
// limitations under the License.
//
/// <reference path="formatting.ts"/>
/// <reference path="references.ts"/>
module TypeScript.Services.Formatting {
export enum FormattingRequestKind {
module ts.formatting {
export const enum FormattingRequestKind {
FormatDocument,
FormatSelection,
FormatOnEnter,
FormatOnSemicolon,
FormatOnClosingCurlyBrace,
FormatOnPaste
FormatOnClosingCurlyBrace
}
}
@@ -0,0 +1,222 @@
/// <reference path="..\formatting.ts"/>
/// <reference path="..\..\compiler\scanner.ts"/>
module ts.formatting {
var scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false);
export interface FormattingScanner {
advance(): void;
isOnToken(): boolean;
readTokenInfo(n: Node): TokenInfo;
lastTrailingTriviaWasNewLine(): boolean;
close(): void;
}
const enum ScanAction{
Scan,
RescanGreaterThanToken,
RescanSlashToken,
RescanTemplateToken
}
export function getFormattingScanner(sourceFile: SourceFile, startPos: number, endPos: number): FormattingScanner {
scanner.setText(sourceFile.text);
scanner.setTextPos(startPos);
var wasNewLine: boolean = true;
var leadingTrivia: TextRangeWithKind[];
var trailingTrivia: TextRangeWithKind[];
var savedPos: number;
var lastScanAction: ScanAction;
var lastTokenInfo: TokenInfo;
return {
advance: advance,
readTokenInfo: readTokenInfo,
isOnToken: isOnToken,
lastTrailingTriviaWasNewLine: () => wasNewLine,
close: () => {
lastTokenInfo = undefined;
scanner.setText(undefined);
}
}
function advance(): void {
lastTokenInfo = undefined;
var isStarted = scanner.getStartPos() !== startPos;
if (isStarted) {
if (trailingTrivia) {
Debug.assert(trailingTrivia.length !== 0);
wasNewLine = trailingTrivia[trailingTrivia.length - 1].kind === SyntaxKind.NewLineTrivia;
}
else {
wasNewLine = false;
}
}
leadingTrivia = undefined;
trailingTrivia = undefined;
if (!isStarted) {
scanner.scan();
}
var t: SyntaxKind;
var pos = scanner.getStartPos();
// Read leading trivia and token
while (pos < endPos) {
var t = scanner.getToken();
if (!isTrivia(t)) {
break;
}
// consume leading trivia
scanner.scan();
var item = {
pos: pos,
end: scanner.getStartPos(),
kind: t
}
pos = scanner.getStartPos();
if (!leadingTrivia) {
leadingTrivia = [];
}
leadingTrivia.push(item);
}
savedPos = scanner.getStartPos();
}
function shouldRescanGreaterThanToken(container: Node): boolean {
if (container.kind !== SyntaxKind.BinaryExpression) {
return false;
}
switch ((<BinaryExpression>container).operator) {
case SyntaxKind.GreaterThanEqualsToken:
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
case SyntaxKind.GreaterThanGreaterThanToken:
return true;
}
return false;
}
function shouldRescanSlashToken(container: Node): boolean {
return container.kind === SyntaxKind.RegularExpressionLiteral;
}
function shouldRescanTemplateToken(container: Node): boolean {
return container.kind === SyntaxKind.TemplateSpan;
}
function startsWithSlashToken(t: SyntaxKind): boolean {
return t === SyntaxKind.SlashToken || t === SyntaxKind.SlashEqualsToken;
}
function readTokenInfo(n: Node): TokenInfo {
if (!isOnToken()) {
// scanner is not on the token (either advance was not called yet or scanner is already past the end position)
return {
leadingTrivia: leadingTrivia,
trailingTrivia: undefined,
token: undefined
};
}
// normally scanner returns the smallest available token
// check the kind of context node to determine if scanner should have more greedy behavior and consume more text.
var expectedScanAction =
shouldRescanGreaterThanToken(n)
? ScanAction.RescanGreaterThanToken
: shouldRescanSlashToken(n)
? ScanAction.RescanSlashToken
: shouldRescanTemplateToken(n)
? ScanAction.RescanTemplateToken
: ScanAction.Scan
if (lastTokenInfo && expectedScanAction === lastScanAction) {
// readTokenInfo was called before with the same expected scan action.
// No need to re-scan text, return existing 'lastTokenInfo'
return lastTokenInfo;
}
if (scanner.getStartPos() !== savedPos) {
Debug.assert(lastTokenInfo !== undefined);
// readTokenInfo was called before but scan action differs - rescan text
scanner.setTextPos(savedPos);
scanner.scan();
}
var currentToken = scanner.getToken();
if (expectedScanAction === ScanAction.RescanGreaterThanToken && currentToken === SyntaxKind.GreaterThanToken) {
currentToken = scanner.reScanGreaterToken();
Debug.assert((<BinaryExpression>n).operator === currentToken);
lastScanAction = ScanAction.RescanGreaterThanToken;
}
else if (expectedScanAction === ScanAction.RescanSlashToken && startsWithSlashToken(currentToken)) {
currentToken = scanner.reScanSlashToken();
Debug.assert(n.kind === currentToken);
lastScanAction = ScanAction.RescanSlashToken;
}
else if (expectedScanAction === ScanAction.RescanTemplateToken && currentToken === SyntaxKind.CloseBraceToken) {
currentToken = scanner.reScanTemplateToken();
lastScanAction = ScanAction.RescanTemplateToken;
}
else {
lastScanAction = ScanAction.Scan;
}
var token: TextRangeWithKind = {
pos: scanner.getStartPos(),
end: scanner.getTextPos(),
kind: currentToken
}
// consume trailing trivia
while(scanner.getStartPos() < endPos) {
currentToken = scanner.scan();
if (!isTrivia(currentToken)) {
break;
}
var trivia = {
pos: scanner.getStartPos(),
end: scanner.getTextPos(),
kind: currentToken
};
if (!trailingTrivia) {
trailingTrivia = [];
}
trailingTrivia.push(trivia);
if (currentToken === SyntaxKind.NewLineTrivia) {
// move past new line
scanner.scan();
break;
}
}
return lastTokenInfo = {
leadingTrivia: leadingTrivia,
trailingTrivia: trailingTrivia,
token: token
}
}
function isOnToken(): boolean {
var current = (lastTokenInfo && lastTokenInfo.token.kind) || scanner.getToken();
var startPos = (lastTokenInfo && lastTokenInfo.token.pos) || scanner.getStartPos();
return startPos < endPos && current !== SyntaxKind.EndOfFileToken && !isTrivia(current);
}
}
}
+54
View File
@@ -0,0 +1,54 @@
module ts.formatting {
var internedTabsIndentation: string[];
var internedSpacesIndentation: string[];
export function getIndentationString(indentation: number, options: FormatCodeOptions): string {
if (!options.ConvertTabsToSpaces) {
var tabs = Math.floor(indentation / options.TabSize);
var spaces = indentation - tabs * options.TabSize;
var tabString: string;
if (!internedTabsIndentation) {
internedTabsIndentation = [];
}
if (internedTabsIndentation[tabs] === undefined) {
internedTabsIndentation[tabs] = tabString = repeat('\t', tabs);
}
else {
tabString = internedTabsIndentation[tabs];
}
return spaces ? tabString + repeat(" ", spaces) : tabString;
}
else {
var spacesString: string;
var quotient = Math.floor(indentation / options.IndentSize);
var remainder = indentation % options.IndentSize;
if (!internedSpacesIndentation) {
internedSpacesIndentation = [];
}
if (internedSpacesIndentation[quotient] === undefined) {
spacesString = repeat(" ", options.IndentSize * quotient);
internedSpacesIndentation[quotient] = spacesString;
}
else {
spacesString = internedSpacesIndentation[quotient];
}
return remainder ? spacesString + repeat(" ", remainder) : spacesString;
}
function repeat(value: string, count: number): string {
var s = "";
for (var i = 0; i < count; ++i) {
s += value;
}
return s;
}
}
}
@@ -1,103 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class IndentationNodeContext {
private _node: ISyntaxNode;
private _parent: IndentationNodeContext;
private _fullStart: number;
private _indentationAmount: number;
private _childIndentationAmountDelta: number;
private _depth: number;
private _hasSkippedOrMissingTokenChild: boolean;
constructor(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationAmount: number, childIndentationAmountDelta: number) {
this.update(parent, node, fullStart, indentationAmount, childIndentationAmountDelta);
}
public parent(): IndentationNodeContext {
return this._parent;
}
public node(): ISyntaxNode {
return this._node;
}
public fullStart(): number {
return this._fullStart;
}
public fullWidth(): number {
return fullWidth(this._node);
}
public start(): number {
return this._fullStart + leadingTriviaWidth(this._node);
}
public end(): number {
return this._fullStart + leadingTriviaWidth(this._node) + width(this._node);
}
public indentationAmount(): number {
return this._indentationAmount;
}
public childIndentationAmountDelta(): number {
return this._childIndentationAmountDelta;
}
public depth(): number {
return this._depth;
}
public kind(): SyntaxKind {
return this._node.kind();
}
public hasSkippedOrMissingTokenChild(): boolean {
if (this._hasSkippedOrMissingTokenChild === null) {
this._hasSkippedOrMissingTokenChild = Syntax.nodeHasSkippedOrMissingTokens(this._node);
}
return this._hasSkippedOrMissingTokenChild;
}
public clone(pool: IndentationNodeContextPool): IndentationNodeContext {
var parent: IndentationNodeContext = null;
if (this._parent) {
parent = this._parent.clone(pool);
}
return pool.getNode(parent, this._node, this._fullStart, this._indentationAmount, this._childIndentationAmountDelta);
}
public update(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationAmount: number, childIndentationAmountDelta: number) {
this._parent = parent;
this._node = node;
this._fullStart = fullStart;
this._indentationAmount = indentationAmount;
this._childIndentationAmountDelta = childIndentationAmountDelta;
this._hasSkippedOrMissingTokenChild = null;
if (parent) {
this._depth = parent.depth() + 1;
}
else {
this._depth = 0;
}
}
}
}
@@ -1,43 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class IndentationNodeContextPool {
private nodes: IndentationNodeContext[] = [];
public getNode(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationLevel: number, childIndentationLevelDelta: number): IndentationNodeContext {
if (this.nodes.length > 0) {
var cachedNode = this.nodes.pop();
cachedNode.update(parent, node, fullStart, indentationLevel, childIndentationLevelDelta);
return cachedNode;
}
return new IndentationNodeContext(parent, node, fullStart, indentationLevel, childIndentationLevelDelta);
}
public releaseNode(node: IndentationNodeContext, recursive: boolean = false): void {
this.nodes.push(node);
if (recursive) {
var parent = node.parent();
if (parent) {
this.releaseNode(parent, recursive);
}
}
}
}
}
@@ -1,349 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class IndentationTrackingWalker extends SyntaxWalker {
private _position: number = 0;
private _parent: IndentationNodeContext = null;
private _textSpan: TextSpan;
private _snapshot: ITextSnapshot;
private _lastTriviaWasNewLine: boolean;
private _indentationNodeContextPool: IndentationNodeContextPool;
private _text: ISimpleText;
constructor(textSpan: TextSpan, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, indentFirstToken: boolean, public options: FormattingOptions) {
super();
// Create a pool object to manage context nodes while walking the tree
this._indentationNodeContextPool = new IndentationNodeContextPool();
this._textSpan = textSpan;
this._text = sourceUnit.syntaxTree.text;
this._snapshot = snapshot;
this._parent = this._indentationNodeContextPool.getNode(null, sourceUnit, 0, 0, 0);
// Is the first token in the span at the start of a new line.
this._lastTriviaWasNewLine = indentFirstToken;
}
public position(): number {
return this._position;
}
public parent(): IndentationNodeContext {
return this._parent;
}
public textSpan(): TextSpan {
return this._textSpan;
}
public snapshot(): ITextSnapshot {
return this._snapshot;
}
public indentationNodeContextPool(): IndentationNodeContextPool {
return this._indentationNodeContextPool;
}
public forceIndentNextToken(tokenStart: number): void {
this._lastTriviaWasNewLine = true;
this.forceRecomputeIndentationOfParent(tokenStart, true);
}
public forceSkipIndentingNextToken(tokenStart: number): void {
this._lastTriviaWasNewLine = false;
this.forceRecomputeIndentationOfParent(tokenStart, false);
}
public indentToken(token: ISyntaxToken, indentationAmount: number, commentIndentationAmount: number): void {
throw Errors.abstract();
}
public visitTokenInSpan(token: ISyntaxToken): void {
if (this._lastTriviaWasNewLine) {
// Compute the indentation level at the current token
var indentationAmount = this.getTokenIndentationAmount(token);
var commentIndentationAmount = this.getCommentIndentationAmount(token);
// Process the token
this.indentToken(token, indentationAmount, commentIndentationAmount);
}
}
public visitToken(token: ISyntaxToken): void {
var tokenSpan = new TextSpan(this._position, token.fullWidth());
if (tokenSpan.intersectsWithTextSpan(this._textSpan)) {
this.visitTokenInSpan(token);
// Only track new lines on tokens within the range. Make sure to check that the last trivia is a newline, and not just one of the trivia
var trivia = token.trailingTrivia();
this._lastTriviaWasNewLine = trivia.hasNewLine() && trivia.syntaxTriviaAt(trivia.count() - 1).kind() == SyntaxKind.NewLineTrivia;
}
// Update the position
this._position += token.fullWidth();
}
public visitNode(node: ISyntaxNode): void {
var nodeSpan = new TextSpan(this._position, fullWidth(node));
if (nodeSpan.intersectsWithTextSpan(this._textSpan)) {
// Update indentation level
var indentation = this.getNodeIndentation(node);
// Update the parent
var currentParent = this._parent;
this._parent = this._indentationNodeContextPool.getNode(currentParent, node, this._position, indentation.indentationAmount, indentation.indentationAmountDelta);
// Visit node
visitNodeOrToken(this, node);
// Reset state
this._indentationNodeContextPool.releaseNode(this._parent);
this._parent = currentParent;
}
else {
// We're skipping the node, so update our position accordingly.
this._position += fullWidth(node);
}
}
private getTokenIndentationAmount(token: ISyntaxToken): number {
// If this is the first token of a node, it should follow the node indentation and not the child indentation;
// (e.g.class in a class declaration or module in module declariotion).
// Open and close braces should follow the indentation of thier parent as well(e.g.
// class {
// }
// Also in a do-while statement, the while should be indented like the parent.
if (firstToken(this._parent.node()) === token ||
token.kind() === SyntaxKind.OpenBraceToken || token.kind() === SyntaxKind.CloseBraceToken ||
token.kind() === SyntaxKind.OpenBracketToken || token.kind() === SyntaxKind.CloseBracketToken ||
(token.kind() === SyntaxKind.WhileKeyword && this._parent.node().kind() == SyntaxKind.DoStatement)) {
return this._parent.indentationAmount();
}
return (this._parent.indentationAmount() + this._parent.childIndentationAmountDelta());
}
private getCommentIndentationAmount(token: ISyntaxToken): number {
// If this is token terminating an indentation scope, leading comments should be indented to follow the children
// indentation level and not the node
if (token.kind() === SyntaxKind.CloseBraceToken || token.kind() === SyntaxKind.CloseBracketToken) {
return (this._parent.indentationAmount() + this._parent.childIndentationAmountDelta());
}
return this._parent.indentationAmount();
}
private getNodeIndentation(node: ISyntaxNode, newLineInsertedByFormatting?: boolean): { indentationAmount: number; indentationAmountDelta: number; } {
var parent = this._parent;
// We need to get the parent's indentation, which could be one of 2 things. If first token of the parent is in the span, use the parent's computed indentation.
// If the parent was outside the span, use the actual indentation of the parent.
var parentIndentationAmount: number;
if (this._textSpan.containsPosition(parent.start())) {
parentIndentationAmount = parent.indentationAmount();
}
else {
if (parent.kind() === SyntaxKind.Block && !this.shouldIndentBlockInParent(this._parent.parent())) {
// Blocks preserve the indentation of their containing node (unless they're a
// standalone block in a list). i.e. if you have:
//
// function foo(
// a: number) {
//
// Then we expect the indentation of the block to be tied to the function, not to
// the line that the block is defined on. If we were to do the latter, then the
// indentation would be here:
//
// function foo(
// a: number) {
// |
//
// Instead of:
//
// function foo(
// a: number) {
// |
parent = this._parent.parent();
}
var line = this._snapshot.getLineFromPosition(parent.start()).getText();
var firstNonWhiteSpacePosition = Indentation.firstNonWhitespacePosition(line);
parentIndentationAmount = Indentation.columnForPositionInString(line, firstNonWhiteSpacePosition, this.options);
}
var parentIndentationAmountDelta = parent.childIndentationAmountDelta();
// The indentation level of the node
var indentationAmount: number;
// The delta it adds to its children.
var indentationAmountDelta: number;
var parentNode = parent.node();
switch (node.kind()) {
default:
// General case
// This node should follow the child indentation set by its parent
// This node does not introduce any new indentation scope, indent any decendants of this node (tokens or child nodes)
// using the same indentation level
indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta);
indentationAmountDelta = 0;
break;
// Statements introducing {}
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ObjectType:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.SwitchStatement:
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.ConstructorDeclaration:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.MemberFunctionDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.IndexMemberDeclaration:
case SyntaxKind.CatchClause:
// Statements introducing []
case SyntaxKind.ArrayLiteralExpression:
case SyntaxKind.ArrayType:
case SyntaxKind.ElementAccessExpression:
case SyntaxKind.IndexSignature:
// Other statements
case SyntaxKind.ForStatement:
case SyntaxKind.ForInStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.WithStatement:
case SyntaxKind.CaseSwitchClause:
case SyntaxKind.DefaultSwitchClause:
case SyntaxKind.ReturnStatement:
case SyntaxKind.ThrowStatement:
case SyntaxKind.SimpleArrowFunctionExpression:
case SyntaxKind.ParenthesizedArrowFunctionExpression:
case SyntaxKind.VariableDeclaration:
case SyntaxKind.ExportAssignment:
// Expressions which have argument lists or parameter lists
case SyntaxKind.InvocationExpression:
case SyntaxKind.ObjectCreationExpression:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
// These nodes should follow the child indentation set by its parent;
// they introduce a new indenation scope; children should be indented at one level deeper
indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta);
indentationAmountDelta = this.options.indentSpaces;
break;
case SyntaxKind.IfStatement:
if (parent.kind() === SyntaxKind.ElseClause &&
!SyntaxUtilities.isLastTokenOnLine((<ElseClauseSyntax>parentNode).elseKeyword, this._text)) {
// This is an else if statement with the if on the same line as the else, do not indent the if statmement.
// Note: Children indentation has already been set by the parent if statement, so no need to increment
indentationAmount = parentIndentationAmount;
}
else {
// Otherwise introduce a new indenation scope; children should be indented at one level deeper
indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta);
}
indentationAmountDelta = this.options.indentSpaces;
break;
case SyntaxKind.ElseClause:
// Else should always follow its parent if statement indentation.
// Note: Children indentation has already been set by the parent if statement, so no need to increment
indentationAmount = parentIndentationAmount;
indentationAmountDelta = this.options.indentSpaces;
break;
case SyntaxKind.Block:
// Check if the block is a member in a list of statements (if the parent is a source unit, module, or block, or switch clause)
if (this.shouldIndentBlockInParent(parent)) {
indentationAmount = parentIndentationAmount + parentIndentationAmountDelta;
}
else {
indentationAmount = parentIndentationAmount;
}
indentationAmountDelta = this.options.indentSpaces;
break;
}
// If the parent happens to start on the same line as this node, then override the current node indenation with that
// of the parent. This avoid having to add an extra level of indentation for the children. e.g.:
// return {
// a:1
// };
// instead of:
// return {
// a:1
// };
// We also need to pass the delta (if it is nonzero) to the children, so that subsequent lines get indented. Essentially, if any node starting on the given line
// has a nonzero delta , the resulting delta should be inherited from this node. This is to indent cases like the following:
// return a
// || b;
// Lastly, it is possible the node indentation needs to be recomputed because the formatter inserted a newline before its first token.
// If this is the case, we know the node no longer starts on the same line as its parent (or at least we shouldn't treat it as such).
if (parentNode) {
if (!newLineInsertedByFormatting /*This could be false or undefined here*/) {
var parentStartLine = this._snapshot.getLineNumberFromPosition(parent.start());
var currentNodeStartLine = this._snapshot.getLineNumberFromPosition(this._position + leadingTriviaWidth(node));
if (parentStartLine === currentNodeStartLine || newLineInsertedByFormatting === false /*meaning a new line was removed and we are force recomputing*/) {
indentationAmount = parentIndentationAmount;
indentationAmountDelta = Math.min(this.options.indentSpaces, parentIndentationAmountDelta + indentationAmountDelta);
}
}
}
return {
indentationAmount: indentationAmount,
indentationAmountDelta: indentationAmountDelta
};
}
private shouldIndentBlockInParent(parent: IndentationNodeContext): boolean {
switch (parent.kind()) {
case SyntaxKind.SourceUnit:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.Block:
case SyntaxKind.CaseSwitchClause:
case SyntaxKind.DefaultSwitchClause:
return true;
default:
return false;
}
}
private forceRecomputeIndentationOfParent(tokenStart: number, newLineAdded: boolean /*as opposed to removed*/): void {
var parent = this._parent;
if (parent.fullStart() === tokenStart) {
// Temporarily pop the parent before recomputing
this._parent = parent.parent();
var indentation = this.getNodeIndentation(parent.node(), /* newLineInsertedByFormatting */ newLineAdded);
parent.update(parent.parent(), parent.node(), parent.fullStart(), indentation.indentationAmount, indentation.indentationAmountDelta);
this._parent = parent;
}
}
}
}
@@ -1,206 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class MultipleTokenIndenter extends IndentationTrackingWalker {
private _edits: TextEditInfo[] = [];
constructor(textSpan: TextSpan, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, indentFirstToken: boolean, options: FormattingOptions) {
super(textSpan, sourceUnit, snapshot, indentFirstToken, options);
}
public indentToken(token: ISyntaxToken, indentationAmount: number, commentIndentationAmount: number): void {
// Ignore generated tokens
if (token.fullWidth() === 0) {
return;
}
// If we have any skipped tokens as children, do not process this node for indentation or formatting
if (this.parent().hasSkippedOrMissingTokenChild()) {
return;
}
// Be strict, and only consider nodes that fall inside the span. This avoids indenting a multiline string
// on enter at the end of, as the whole token was not included in the span
var tokenSpan = new TextSpan(this.position() + token.leadingTriviaWidth(), width(token));
if (!this.textSpan().containsTextSpan(tokenSpan)) {
return;
}
// Compute an indentation string for this token
var indentationString = Indentation.indentationString(indentationAmount, this.options);
var commentIndentationString = Indentation.indentationString(commentIndentationAmount, this.options);
// Record any needed indentation edits
this.recordIndentationEditsForToken(token, indentationString, commentIndentationString);
}
public edits(): TextEditInfo[]{
return this._edits;
}
public recordEdit(position: number, length: number, replaceWith: string): void {
this._edits.push(new TextEditInfo(position, length, replaceWith));
}
private recordIndentationEditsForToken(token: ISyntaxToken, indentationString: string, commentIndentationString: string) {
var position = this.position();
var indentNextTokenOrTrivia = true;
var leadingWhiteSpace = ""; // We need to track the whitespace before a multiline comment
// Process any leading trivia if any
var triviaList = token.leadingTrivia();
if (triviaList) {
for (var i = 0, length = triviaList.count(); i < length; i++, position += trivia.fullWidth()) {
var trivia = triviaList.syntaxTriviaAt(i);
// Skip this trivia if it is not in the span
if (!this.textSpan().containsTextSpan(new TextSpan(position, trivia.fullWidth()))) {
continue;
}
switch (trivia.kind()) {
case SyntaxKind.MultiLineCommentTrivia:
// We will only indent the first line of the multiline comment if we were planning to indent the next trivia. However,
// subsequent lines will always be indented
this.recordIndentationEditsForMultiLineComment(trivia, position, commentIndentationString, leadingWhiteSpace, !indentNextTokenOrTrivia /* already indented first line */);
indentNextTokenOrTrivia = false;
leadingWhiteSpace = "";
break;
case SyntaxKind.SingleLineCommentTrivia:
case SyntaxKind.SkippedTokenTrivia:
if (indentNextTokenOrTrivia) {
this.recordIndentationEditsForSingleLineOrSkippedText(trivia, position, commentIndentationString);
indentNextTokenOrTrivia = false;
}
break;
case SyntaxKind.WhitespaceTrivia:
// If the next trivia is a comment, use the comment indentation level instead of the regular indentation level
// If the next trivia is a newline, this whole line is just whitespace, so don't do anything (trimming will take care of it)
var nextTrivia = length > i + 1 && triviaList.syntaxTriviaAt(i + 1);
var whiteSpaceIndentationString = nextTrivia && nextTrivia.isComment() ? commentIndentationString : indentationString;
if (indentNextTokenOrTrivia) {
if (!(nextTrivia && nextTrivia.isNewLine())) {
this.recordIndentationEditsForWhitespace(trivia, position, whiteSpaceIndentationString);
}
indentNextTokenOrTrivia = false;
}
leadingWhiteSpace += trivia.fullText();
break;
case SyntaxKind.NewLineTrivia:
// We hit a newline processing the trivia. We need to add the indentation to the
// next line as well. Note: don't bother indenting the newline itself. This will
// just insert ugly whitespace that most users probably will not want.
indentNextTokenOrTrivia = true;
leadingWhiteSpace = "";
break;
default:
throw Errors.invalidOperation();
}
}
}
if (token.kind() !== SyntaxKind.EndOfFileToken && indentNextTokenOrTrivia) {
// If the last trivia item was a new line, or no trivia items were encounterd record the
// indentation edit at the token position
if (indentationString.length > 0) {
this.recordEdit(position, 0, indentationString);
}
}
}
private recordIndentationEditsForSingleLineOrSkippedText(trivia: ISyntaxTrivia, fullStart: number, indentationString: string): void {
// Record the edit
if (indentationString.length > 0) {
this.recordEdit(fullStart, 0, indentationString);
}
}
private recordIndentationEditsForWhitespace(trivia: ISyntaxTrivia, fullStart: number, indentationString: string): void {
var text = trivia.fullText();
// Check if the current indentation matches the desired indentation or not
if (indentationString === text) {
return;
}
// Record the edit
this.recordEdit(fullStart, text.length, indentationString);
}
private recordIndentationEditsForMultiLineComment(trivia: ISyntaxTrivia, fullStart: number, indentationString: string, leadingWhiteSpace: string, firstLineAlreadyIndented: boolean): void {
// If the multiline comment spans multiple lines, we need to add the right indent amount to
// each successive line segment as well.
var position = fullStart;
var segments = Syntax.splitMultiLineCommentTriviaIntoMultipleLines(trivia);
if (segments.length <= 1) {
if (!firstLineAlreadyIndented) {
// Process the one-line multiline comment just like a single line comment
this.recordIndentationEditsForSingleLineOrSkippedText(trivia, fullStart, indentationString);
}
return;
}
// Find number of columns in first segment
var whiteSpaceColumnsInFirstSegment = Indentation.columnForPositionInString(leadingWhiteSpace, leadingWhiteSpace.length, this.options);
var indentationColumns = Indentation.columnForPositionInString(indentationString, indentationString.length, this.options);
var startIndex = 0;
if (firstLineAlreadyIndented) {
startIndex = 1;
position += segments[0].length;
}
for (var i = startIndex; i < segments.length; i++) {
var segment = segments[i];
this.recordIndentationEditsForSegment(segment, position, indentationColumns, whiteSpaceColumnsInFirstSegment);
position += segment.length;
}
}
private recordIndentationEditsForSegment(segment: string, fullStart: number, indentationColumns: number, whiteSpaceColumnsInFirstSegment: number): void {
// Indent subsequent lines using a column delta of the actual indentation relative to the first line
var firstNonWhitespacePosition = Indentation.firstNonWhitespacePosition(segment);
var leadingWhiteSpaceColumns = Indentation.columnForPositionInString(segment, firstNonWhitespacePosition, this.options);
var deltaFromFirstSegment = leadingWhiteSpaceColumns - whiteSpaceColumnsInFirstSegment;
var finalColumns = indentationColumns + deltaFromFirstSegment;
if (finalColumns < 0) {
finalColumns = 0;
}
var indentationString = Indentation.indentationString(finalColumns, this.options);
if (firstNonWhitespacePosition < segment.length &&
CharacterInfo.isLineTerminator(segment.charCodeAt(firstNonWhitespacePosition))) {
// If this segment was just a newline, then don't bother indenting it. That will just
// leave the user with an ugly indent in their output that they probably do not want.
return;
}
if (indentationString === segment.substring(0, firstNonWhitespacePosition)) {
return;
}
// Record the edit
this.recordEdit(fullStart, firstNonWhitespacePosition, indentationString);
}
}
}
@@ -13,12 +13,9 @@
// limitations under the License.
//
///<reference path='..\text.ts' />
///<reference path='..\services.ts' />
///<reference path='textSnapshot.ts' />
///<reference path='textSnapshotLine.ts' />
///<reference path='snapshotPoint.ts' />
///<reference path='formattingContext.ts' />
///<reference path='formattingManager.ts' />
///<reference path='formattingRequestKind.ts' />
///<reference path='rule.ts' />
///<reference path='ruleAction.ts' />
@@ -28,13 +25,5 @@
///<reference path='ruleOperationContext.ts' />
///<reference path='rules.ts' />
///<reference path='rulesMap.ts' />
///<reference path='rulesProvider.ts' />
///<reference path='textEditInfo.ts' />
///<reference path='tokenRange.ts' />
///<reference path='tokenSpan.ts' />
///<reference path='indentationNodeContext.ts' />
///<reference path='indentationNodeContextPool.ts' />
///<reference path='indentationTrackingWalker.ts' />
///<reference path='multipleTokenIndenter.ts' />
///<reference path='singleTokenIndenter.ts' />
///<reference path='formatter.ts' />
///<reference path='tokenSpan.ts' />
+2 -2
View File
@@ -13,9 +13,9 @@
// limitations under the License.
//
///<reference path='formatting.ts' />
///<reference path='references.ts' />
module TypeScript.Services.Formatting {
module ts.formatting {
export class Rule {
constructor(
public Descriptor: RuleDescriptor,
+7 -7
View File
@@ -13,13 +13,13 @@
// limitations under the License.
//
///<reference path='formatting.ts' />
///<reference path='references.ts' />
module TypeScript.Services.Formatting {
export enum RuleAction {
Ignore,
Space,
NewLine,
Delete
module ts.formatting {
export const enum RuleAction {
Ignore = 0x00000001,
Space = 0x00000002,
NewLine = 0x00000004,
Delete = 0x00000008
}
}
+2 -3
View File
@@ -13,9 +13,9 @@
// limitations under the License.
//
///<reference path='formatting.ts' />
///<reference path='references.ts' />
module TypeScript.Services.Formatting {
module ts.formatting {
export class RuleDescriptor {
constructor(public LeftTokenRange: Shared.TokenRange, public RightTokenRange: Shared.TokenRange) {
}
@@ -34,7 +34,6 @@ module TypeScript.Services.Formatting {
}
static create3(left: SyntaxKind, right: Shared.TokenRange): RuleDescriptor
//: this(TokenRange.FromToken(left), right)
{
return RuleDescriptor.create4(Shared.TokenRange.FromToken(left), right);
}
+3 -3
View File
@@ -13,10 +13,10 @@
// limitations under the License.
//
///<reference path='formatting.ts' />
///<reference path='references.ts' />
module TypeScript.Services.Formatting {
export enum RuleFlags {
module ts.formatting {
export const enum RuleFlags {
None,
CanDeleteNewLines
}
+2 -2
View File
@@ -13,9 +13,9 @@
// limitations under the License.
//
///<reference path='formatting.ts' />
///<reference path='references.ts' />
module TypeScript.Services.Formatting {
module ts.formatting {
export class RuleOperation {
public Context: RuleOperationContext;
public Action: RuleAction;
@@ -13,9 +13,9 @@
// limitations under the License.
//
///<reference path='formatting.ts' />
///<reference path='references.ts' />
module TypeScript.Services.Formatting {
module ts.formatting {
export class RuleOperationContext {
private customContextChecks: { (context: FormattingContext): boolean; }[];
+75 -74
View File
@@ -13,9 +13,9 @@
// limitations under the License.
//
///<reference path='formatting.ts' />
///<reference path='references.ts' />
module TypeScript.Services.Formatting {
module ts.formatting {
export class Rules {
public getRuleName(rule: Rule) {
var o: ts.Map<any> = <any>this;
@@ -24,7 +24,7 @@ module TypeScript.Services.Formatting {
return name;
}
}
throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Unknown_rule, null));
throw new Error("Unknown rule");
}
[name: string]: any;
@@ -241,7 +241,7 @@ module TypeScript.Services.Formatting {
this.SpaceBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);
// Place a space before open brace in a TypeScript declaration that has braces as children (class, module, enum, etc)
this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.MultiLineCommentTrivia]);
this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.MultiLineCommentTrivia]);
this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsTypeScriptDeclWithBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);
// Place a space before open brace in a control flow construct
@@ -299,7 +299,7 @@ module TypeScript.Services.Formatting {
// get x() {}
// set x(val) {}
this.SpaceAfterGetSetInMember = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.GetKeyword, SyntaxKind.SetKeyword]), SyntaxKind.IdentifierName), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space));
this.SpaceAfterGetSetInMember = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.GetKeyword, SyntaxKind.SetKeyword]), SyntaxKind.Identifier), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space));
// Special case for binary operators (that are keywords). For these we have to add a space and shouldn't follow any user options.
this.SpaceBeforeBinaryKeywordOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryKeywordOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
@@ -324,7 +324,7 @@ module TypeScript.Services.Formatting {
this.SpaceAfterArrow = new Rule(RuleDescriptor.create3(SyntaxKind.EqualsGreaterThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
// Optional parameters and var args
this.NoSpaceAfterEllipsis = new Rule(RuleDescriptor.create1(SyntaxKind.DotDotDotToken, SyntaxKind.IdentifierName), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
this.NoSpaceAfterEllipsis = new Rule(RuleDescriptor.create1(SyntaxKind.DotDotDotToken, SyntaxKind.Identifier), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
this.NoSpaceAfterOptionalParameters = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.CommaToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete));
// generics
@@ -437,7 +437,7 @@ module TypeScript.Services.Formatting {
///
static IsForContext(context: FormattingContext): boolean {
return context.contextNode.kind() === SyntaxKind.ForStatement;
return context.contextNode.kind === SyntaxKind.ForStatement;
}
static IsNotForContext(context: FormattingContext): boolean {
@@ -446,51 +446,19 @@ module TypeScript.Services.Formatting {
static IsBinaryOpContext(context: FormattingContext): boolean {
switch (context.contextNode.kind()) {
// binary expressions
case SyntaxKind.AssignmentExpression:
case SyntaxKind.AddAssignmentExpression:
case SyntaxKind.SubtractAssignmentExpression:
case SyntaxKind.MultiplyAssignmentExpression:
case SyntaxKind.DivideAssignmentExpression:
case SyntaxKind.ModuloAssignmentExpression:
case SyntaxKind.AndAssignmentExpression:
case SyntaxKind.ExclusiveOrAssignmentExpression:
case SyntaxKind.OrAssignmentExpression:
case SyntaxKind.LeftShiftAssignmentExpression:
case SyntaxKind.SignedRightShiftAssignmentExpression:
case SyntaxKind.UnsignedRightShiftAssignmentExpression:
switch (context.contextNode.kind) {
case SyntaxKind.BinaryExpression:
case SyntaxKind.ConditionalExpression:
case SyntaxKind.LogicalOrExpression:
case SyntaxKind.LogicalAndExpression:
case SyntaxKind.BitwiseOrExpression:
case SyntaxKind.BitwiseExclusiveOrExpression:
case SyntaxKind.BitwiseAndExpression:
case SyntaxKind.EqualsWithTypeConversionExpression:
case SyntaxKind.NotEqualsWithTypeConversionExpression:
case SyntaxKind.EqualsExpression:
case SyntaxKind.NotEqualsExpression:
case SyntaxKind.LessThanExpression:
case SyntaxKind.GreaterThanExpression:
case SyntaxKind.LessThanOrEqualExpression:
case SyntaxKind.GreaterThanOrEqualExpression:
case SyntaxKind.InstanceOfExpression:
case SyntaxKind.InExpression:
case SyntaxKind.LeftShiftExpression:
case SyntaxKind.SignedRightShiftExpression:
case SyntaxKind.UnsignedRightShiftExpression:
case SyntaxKind.MultiplyExpression:
case SyntaxKind.DivideExpression:
case SyntaxKind.ModuloExpression:
case SyntaxKind.AddExpression:
case SyntaxKind.SubtractExpression:
return true;
// equal in import a = module('a');
case SyntaxKind.ImportDeclaration:
// equal in var a = 0;
case SyntaxKind.VariableDeclarator:
case SyntaxKind.EqualsValueClause:
case SyntaxKind.VariableDeclaration:
// equal in p = 0;
case SyntaxKind.Parameter:
case SyntaxKind.EnumMember:
case SyntaxKind.Property:
return context.currentTokenSpan.kind === SyntaxKind.EqualsToken || context.nextTokenSpan.kind === SyntaxKind.EqualsToken;
// "in" keyword in for (var x in []) { }
case SyntaxKind.ForInStatement:
@@ -546,16 +514,21 @@ module TypeScript.Services.Formatting {
}
// IMPORTANT!!! This method must return true ONLY for nodes with open and close braces as immediate children
static NodeIsBlockContext(node: IndentationNodeContext): boolean {
static NodeIsBlockContext(node: Node): boolean {
if (Rules.NodeIsTypeScriptDeclWithBlockContext(node)) {
// This means we are in a context that looks like a block to the user, but in the grammar is actually not a node (it's a class, module, enum, object type literal, etc).
return true;
}
switch (node.kind()) {
switch (node.kind) {
case SyntaxKind.Block:
case SyntaxKind.SwitchStatement:
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.ObjectLiteral:
case SyntaxKind.TryBlock:
case SyntaxKind.CatchBlock:
case SyntaxKind.FinallyBlock:
case SyntaxKind.FunctionBlock:
case SyntaxKind.ModuleBlock:
return true;
}
@@ -563,17 +536,20 @@ module TypeScript.Services.Formatting {
}
static IsFunctionDeclContext(context: FormattingContext): boolean {
switch (context.contextNode.kind()) {
switch (context.contextNode.kind) {
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.MemberFunctionDeclaration:
case SyntaxKind.Method:
//case SyntaxKind.MemberFunctionDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.MethodSignature:
///case SyntaxKind.MethodSignature:
case SyntaxKind.CallSignature:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ConstructorDeclaration:
case SyntaxKind.SimpleArrowFunctionExpression:
case SyntaxKind.ParenthesizedArrowFunctionExpression:
case SyntaxKind.Constructor:
case SyntaxKind.ArrowFunction:
//case SyntaxKind.ConstructorDeclaration:
//case SyntaxKind.SimpleArrowFunctionExpression:
//case SyntaxKind.ParenthesizedArrowFunctionExpression:
case SyntaxKind.InterfaceDeclaration: // This one is not truly a function, but for formatting purposes, it acts just like one
return true;
}
@@ -585,11 +561,12 @@ module TypeScript.Services.Formatting {
return Rules.NodeIsTypeScriptDeclWithBlockContext(context.contextNode);
}
static NodeIsTypeScriptDeclWithBlockContext(node: IndentationNodeContext): boolean {
switch (node.kind()) {
static NodeIsTypeScriptDeclWithBlockContext(node: Node): boolean {
switch (node.kind) {
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.ObjectType:
case SyntaxKind.TypeLiteral:
case SyntaxKind.ModuleDeclaration:
return true;
}
@@ -598,11 +575,16 @@ module TypeScript.Services.Formatting {
}
static IsAfterCodeBlockContext(context: FormattingContext): boolean {
switch (context.currentTokenParent.kind()) {
switch (context.currentTokenParent.kind) {
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.Block:
case SyntaxKind.TryBlock:
case SyntaxKind.CatchBlock:
case SyntaxKind.FinallyBlock:
case SyntaxKind.FunctionBlock:
case SyntaxKind.ModuleBlock:
case SyntaxKind.SwitchStatement:
return true;
}
@@ -610,7 +592,7 @@ module TypeScript.Services.Formatting {
}
static IsControlDeclContext(context: FormattingContext): boolean {
switch (context.contextNode.kind()) {
switch (context.contextNode.kind) {
case SyntaxKind.IfStatement:
case SyntaxKind.SwitchStatement:
case SyntaxKind.ForStatement:
@@ -619,9 +601,10 @@ module TypeScript.Services.Formatting {
case SyntaxKind.TryStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.WithStatement:
case SyntaxKind.ElseClause:
case SyntaxKind.CatchClause:
case SyntaxKind.FinallyClause:
// TODO
// case SyntaxKind.ElseClause:
case SyntaxKind.CatchBlock:
case SyntaxKind.FinallyBlock:
return true;
default:
@@ -630,15 +613,15 @@ module TypeScript.Services.Formatting {
}
static IsObjectContext(context: FormattingContext): boolean {
return context.contextNode.kind() === SyntaxKind.ObjectLiteralExpression;
return context.contextNode.kind === SyntaxKind.ObjectLiteral;
}
static IsFunctionCallContext(context: FormattingContext): boolean {
return context.contextNode.kind() === SyntaxKind.InvocationExpression;
return context.contextNode.kind === SyntaxKind.CallExpression;
}
static IsNewContext(context: FormattingContext): boolean {
return context.contextNode.kind() === SyntaxKind.ObjectCreationExpression;
return context.contextNode.kind === SyntaxKind.NewExpression;
}
static IsFunctionCallOrNewContext(context: FormattingContext): boolean {
@@ -654,25 +637,43 @@ module TypeScript.Services.Formatting {
}
static IsModuleDeclContext(context: FormattingContext): boolean {
return context.contextNode.kind() === SyntaxKind.ModuleDeclaration;
return context.contextNode.kind === SyntaxKind.ModuleDeclaration;
}
static IsObjectTypeContext(context: FormattingContext): boolean {
return context.contextNode.kind() === SyntaxKind.ObjectType && context.contextNode.parent().kind() !== SyntaxKind.InterfaceDeclaration;
return context.contextNode.kind === SyntaxKind.TypeLiteral;// && context.contextNode.parent.kind !== SyntaxKind.InterfaceDeclaration;
}
static IsTypeArgumentOrParameter(tokenKind: SyntaxKind, parentKind: SyntaxKind): boolean {
return ((tokenKind === SyntaxKind.LessThanToken || tokenKind === SyntaxKind.GreaterThanToken) &&
(parentKind === SyntaxKind.TypeParameterList || parentKind === SyntaxKind.TypeArgumentList));
static IsTypeArgumentOrParameter(token: TextRangeWithKind, parent: Node): boolean {
if (token.kind !== SyntaxKind.LessThanToken && token.kind !== SyntaxKind.GreaterThanToken) {
return false;
}
switch (parent.kind) {
case SyntaxKind.TypeReference:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
case SyntaxKind.Method:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
return true;
default:
return false;
}
}
static IsTypeArgumentOrParameterContext(context: FormattingContext): boolean {
return Rules.IsTypeArgumentOrParameter(context.currentTokenSpan.kind, context.currentTokenParent.kind()) ||
Rules.IsTypeArgumentOrParameter(context.nextTokenSpan.kind, context.nextTokenParent.kind());
return Rules.IsTypeArgumentOrParameter(context.currentTokenSpan, context.currentTokenParent) ||
Rules.IsTypeArgumentOrParameter(context.nextTokenSpan, context.nextTokenParent);
}
static IsVoidOpContext(context: FormattingContext): boolean {
return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind() === SyntaxKind.VoidExpression;
return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind === SyntaxKind.PrefixOperator;
}
}
}
+2 -2
View File
@@ -13,9 +13,9 @@
// limitations under the License.
//
///<reference path='formatting.ts' />
///<reference path='references.ts' />
module TypeScript.Services.Formatting {
module ts.formatting {
export class RulesMap {
public map: RulesBucket[];
public mapRowLength: number;
+3 -3
View File
@@ -13,16 +13,16 @@
// limitations under the License.
//
/// <reference path="formatting.ts"/>
/// <reference path="references.ts"/>
module TypeScript.Services.Formatting {
module ts.formatting {
export class RulesProvider {
private globalRules: Rules;
private options: ts.FormatCodeOptions;
private activeRules: Rule[];
private rulesMap: RulesMap;
constructor(private logger: TypeScript.Logger) {
constructor(private logger: Logger) {
this.globalRules = new Rules();
}
@@ -1,46 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class SingleTokenIndenter extends IndentationTrackingWalker {
private indentationAmount: number = null;
private indentationPosition: number;
constructor(indentationPosition: number, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, indentFirstToken: boolean, options: FormattingOptions) {
super(new TextSpan(indentationPosition, 1), sourceUnit, snapshot, indentFirstToken, options);
this.indentationPosition = indentationPosition;
}
public static getIndentationAmount(position: number, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, options: FormattingOptions): number {
var walker = new SingleTokenIndenter(position, sourceUnit, snapshot, true, options);
visitNodeOrToken(walker, sourceUnit);
return walker.indentationAmount;
}
public indentToken(token: ISyntaxToken, indentationAmount: number, commentIndentationAmount: number): void {
// Compute an indentation string for this token
if (token.fullWidth() === 0 || (this.indentationPosition - this.position() < token.leadingTriviaWidth())) {
// The position is in the leading trivia, use comment indentation
this.indentationAmount = commentIndentationAmount;
}
else {
this.indentationAmount = indentationAmount;
}
}
}
}
-30
View File
@@ -1,30 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class SnapshotPoint {
constructor(public snapshot: ITextSnapshot, public position: number) {
}
public getContainingLine(): ITextSnapshotLine {
return this.snapshot.getLineFromPosition(this.position);
}
public add(offset: number): SnapshotPoint {
return new SnapshotPoint(this.snapshot, this.position + offset);
}
}
}
-28
View File
@@ -1,28 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class TextEditInfo {
constructor(public position: number, public length: number, public replaceWith: string) {
}
public toString() {
return "[ position: " + this.position + ", length: " + this.length + ", replaceWith: '" + this.replaceWith + "' ]";
}
}
}
-89
View File
@@ -1,89 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export interface ITextSnapshot {
getLength(): number;
getText(span: TextSpan): string;
getLineNumberFromPosition(position: number): number;
getLineFromPosition(position: number): ITextSnapshotLine;
getLineFromLineNumber(lineNumber: number): ITextSnapshotLine;
}
export class TextSnapshot implements ITextSnapshot {
private lines: TextSnapshotLine[];
constructor(private snapshot: ISimpleText) {
this.lines = [];
}
public getLength(): number {
return this.snapshot.length();
}
public getText(span: TextSpan): string {
return this.snapshot.substr(span.start(), span.length());
}
public getLineNumberFromPosition(position: number): number {
return this.snapshot.lineMap().getLineNumberFromPosition(position);
}
public getLineFromPosition(position: number): ITextSnapshotLine {
var lineNumber = this.getLineNumberFromPosition(position);
return this.getLineFromLineNumber(lineNumber);
}
public getLineFromLineNumber(lineNumber: number): ITextSnapshotLine {
var line = this.lines[lineNumber];
if (line === undefined) {
line = <TextSnapshotLine>this.getLineFromLineNumberWorker(lineNumber);
this.lines[lineNumber] = line;
}
return line;
}
private getLineFromLineNumberWorker(lineNumber: number): ITextSnapshotLine {
var lineMap = this.snapshot.lineMap().lineStarts();
var lineMapIndex = lineNumber; //Note: lineMap is 0-based
if (lineMapIndex < 0 || lineMapIndex >= lineMap.length)
throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Invalid_line_number_0, [lineMapIndex]));
var start = lineMap[lineMapIndex];
var end: number;
var endIncludingLineBreak: number;
var lineBreak = "";
if (lineMapIndex == lineMap.length) {
end = endIncludingLineBreak = this.snapshot.length();
}
else {
endIncludingLineBreak = (lineMapIndex >= lineMap.length - 1 ? this.snapshot.length() : lineMap[lineMapIndex + 1]);
for (var p = endIncludingLineBreak - 1; p >= start; p--) {
var c = this.snapshot.substr(p, 1);
//TODO: Other ones?
if (c != "\r" && c != "\n") {
break;
}
}
end = p + 1;
lineBreak = this.snapshot.substr(end, endIncludingLineBreak - end);
}
var result = new TextSnapshotLine(this, lineNumber, start, end, lineBreak);
return result;
}
}
}
@@ -1,80 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export interface ITextSnapshotLine {
snapshot(): ITextSnapshot;
start(): SnapshotPoint;
startPosition(): number;
end(): SnapshotPoint;
endPosition(): number;
endIncludingLineBreak(): SnapshotPoint;
endIncludingLineBreakPosition(): number;
length(): number;
lineNumber(): number;
getText(): string;
}
export class TextSnapshotLine implements ITextSnapshotLine {
constructor(private _snapshot: ITextSnapshot, private _lineNumber: number, private _start: number, private _end: number, private _lineBreak: string) {
}
public snapshot() {
return this._snapshot;
}
public start() {
return new SnapshotPoint(this._snapshot, this._start);
}
public startPosition() {
return this._start;
}
public end() {
return new SnapshotPoint(this._snapshot, this._end);
}
public endPosition() {
return this._end;
}
public endIncludingLineBreak() {
return new SnapshotPoint(this._snapshot, this._end + this._lineBreak.length);
}
public endIncludingLineBreakPosition() {
return this._end + this._lineBreak.length;
}
public length() {
return this._end - this._start;
}
public lineNumber() {
return this._lineNumber;
}
public getText(): string {
return this._snapshot.getText(TextSpan.fromBounds(this._start, this._end));
}
}
}
+11 -21
View File
@@ -13,9 +13,9 @@
// limitations under the License.
//
///<reference path='formatting.ts' />
///<reference path='references.ts' />
module TypeScript.Services.Formatting {
module ts.formatting {
export module Shared {
export interface ITokenAccess {
GetTokens(): SyntaxKind[];
@@ -41,12 +41,6 @@ module TypeScript.Services.Formatting {
public Contains(token: SyntaxKind): boolean {
return this.tokens.indexOf(token) >= 0;
}
public toString(): string {
return "[tokenRangeStart=" + SyntaxKind[this.tokens[0]] + "," +
"tokenRangeEnd=" + SyntaxKind[this.tokens[this.tokens.length - 1]] + "]";
}
}
export class TokenValuesAccess implements ITokenAccess {
@@ -76,10 +70,6 @@ module TypeScript.Services.Formatting {
public Contains(tokenValue: SyntaxKind): boolean {
return tokenValue == this.token;
}
public toString(): string {
return "[singleTokenKind=" + SyntaxKind[this.token] + "]";
}
}
export class TokenAllAccess implements ITokenAccess {
@@ -135,18 +125,18 @@ module TypeScript.Services.Formatting {
static Any: TokenRange = TokenRange.AllTokens();
static AnyIncludingMultilineComments = TokenRange.FromTokens(TokenRange.Any.GetTokens().concat([SyntaxKind.MultiLineCommentTrivia]));
static Keywords = TokenRange.FromRange(SyntaxKind.FirstKeyword, SyntaxKind.LastKeyword);
static Operators = TokenRange.FromRange(SyntaxKind.SemicolonToken, SyntaxKind.SlashEqualsToken);
static BinaryOperators = TokenRange.FromRange(SyntaxKind.LessThanToken, SyntaxKind.SlashEqualsToken);
static Operators = TokenRange.FromRange(SyntaxKind.FirstOperator, SyntaxKind.LastOperator);
static BinaryOperators = TokenRange.FromRange(SyntaxKind.FirstBinaryOperator, SyntaxKind.LastBinaryOperator);
static BinaryKeywordOperators = TokenRange.FromTokens([SyntaxKind.InKeyword, SyntaxKind.InstanceOfKeyword]);
static ReservedKeywords = TokenRange.FromRange(SyntaxKind.FirstFutureReservedStrictKeyword, SyntaxKind.LastFutureReservedStrictKeyword);
static ReservedKeywords = TokenRange.FromRange(SyntaxKind.FirstFutureReservedWord, SyntaxKind.LastFutureReservedWord);
static UnaryPrefixOperators = TokenRange.FromTokens([SyntaxKind.PlusPlusToken, SyntaxKind.MinusMinusToken, SyntaxKind.TildeToken, SyntaxKind.ExclamationToken]);
static UnaryPrefixExpressions = TokenRange.FromTokens([SyntaxKind.NumericLiteral, SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.OpenBraceToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
static UnaryPreincrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
static UnaryPostincrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
static UnaryPredecrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
static UnaryPostdecrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
static UnaryPrefixExpressions = TokenRange.FromTokens([SyntaxKind.NumericLiteral, SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.OpenBraceToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
static UnaryPreincrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
static UnaryPostincrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
static UnaryPredecrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
static UnaryPostdecrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
static Comments = TokenRange.FromTokens([SyntaxKind.SingleLineCommentTrivia, SyntaxKind.MultiLineCommentTrivia]);
static TypeNames = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.NumberKeyword, SyntaxKind.StringKeyword, SyntaxKind.BooleanKeyword, SyntaxKind.VoidKeyword, SyntaxKind.AnyKeyword]);
static TypeNames = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.NumberKeyword, SyntaxKind.StringKeyword, SyntaxKind.BooleanKeyword, SyntaxKind.VoidKeyword, SyntaxKind.AnyKeyword]);
}
}
}

Some files were not shown because too many files have changed in this diff Show More