mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' of https://github.com/Microsoft/TypeScript
This commit is contained in:
+8
-3
@@ -6,6 +6,8 @@ tests/cases/perf/*
|
||||
!tests/cases/webharness/compilerToString.js
|
||||
test-args.txt
|
||||
~*.docx
|
||||
\#*\#
|
||||
.\#*
|
||||
tests/baselines/local/*
|
||||
tests/services/baselines/local/*
|
||||
tests/baselines/prototyping/local/*
|
||||
@@ -26,11 +28,12 @@ rwc-report.html
|
||||
*.swp
|
||||
build.json
|
||||
*.actual
|
||||
tests/webTestServer.js
|
||||
tests/webTestServer.js.map
|
||||
tests/webhost/*.d.ts
|
||||
tests/webhost/webtsc.js
|
||||
tests/cases/**/*.js
|
||||
tests/cases/**/*.js.map
|
||||
tests/cases/**/*.d.ts
|
||||
*.config
|
||||
scripts/debug.bat
|
||||
scripts/run.bat
|
||||
@@ -42,5 +45,7 @@ coverage/
|
||||
internal/
|
||||
**/.DS_Store
|
||||
.settings
|
||||
.vscode/*
|
||||
!.vscode/tasks.json
|
||||
**/.vs
|
||||
**/.vscode
|
||||
!**/.vscode/tasks.json
|
||||
!tests/cases/projects/projectOption/**/node_modules
|
||||
|
||||
+3
-1
@@ -1,10 +1,12 @@
|
||||
built
|
||||
doc
|
||||
internal
|
||||
issue_template.md
|
||||
lib/README.md
|
||||
pull_request_template.md
|
||||
scripts
|
||||
src
|
||||
tests
|
||||
internal
|
||||
tslint.json
|
||||
Jakefile.js
|
||||
.editorconfig
|
||||
|
||||
Vendored
+1
-20
@@ -7,7 +7,7 @@
|
||||
// ${cwd}: the current working directory of the spawned process
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"command": "jake",
|
||||
"command": "gulp",
|
||||
"isShellCommand": true,
|
||||
"showOutput": "silent",
|
||||
"tasks": [
|
||||
@@ -18,25 +18,6 @@
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"taskName": "lint-server",
|
||||
"args": [],
|
||||
"problemMatcher": {
|
||||
"owner": "typescript",
|
||||
"fileLocation": ["relative", "${workspaceRoot}"],
|
||||
"pattern": {
|
||||
"regexp": "^(warning|error)\\s+([^(]+)\\s+\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(.*)$",
|
||||
"severity": 1,
|
||||
"file": 2,
|
||||
"location": 3,
|
||||
"message": 4
|
||||
},
|
||||
"watchedTaskBeginsRegExp": "^\\*\\*\\*Lint failure\\*\\*\\*$",
|
||||
"watchedTaskEndsRegExp": "^\\*\\*\\* Total \\d+ failures\\.$"
|
||||
},
|
||||
"showOutput": "always",
|
||||
"isWatching": true
|
||||
}
|
||||
]
|
||||
}
|
||||
+6
-2
@@ -40,6 +40,10 @@ In general, things we find useful when reviewing suggestions are:
|
||||
|
||||
# Instructions for Contributing Code
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
## Contributing bug fixes
|
||||
|
||||
TypeScript is currently accepting contributions in the form of bug fixes. A bug must have an issue tracking it in the issue tracker that has been approved ("Milestone == Community") by the TypeScript team. Your pull request should include a link to the bug that you are fixing. If you've submitted a PR for a bug, please post a comment in the bug to avoid duplication of effort.
|
||||
@@ -91,10 +95,10 @@ These two files represent the DOM typings and are auto-generated. To make any mo
|
||||
|
||||
## Running the Tests
|
||||
|
||||
To run all tests, invoke the `runtests` target using jake:
|
||||
To run all tests, invoke the `runtests-parallel` target using jake:
|
||||
|
||||
```Shell
|
||||
jake runtests
|
||||
jake runtests-parallel
|
||||
```
|
||||
|
||||
This run will all tests; to run only a specific subset of tests, use:
|
||||
|
||||
+1047
File diff suppressed because it is too large
Load Diff
+187
-102
@@ -5,6 +5,7 @@ var os = require("os");
|
||||
var path = require("path");
|
||||
var child_process = require("child_process");
|
||||
var Linter = require("tslint");
|
||||
var runTestsInParallel = require("./scripts/mocha-parallel").runTestsInParallel;
|
||||
|
||||
// Variables
|
||||
var compilerDirectory = "src/compiler/";
|
||||
@@ -120,6 +121,7 @@ var languageServiceLibrarySources = [
|
||||
|
||||
var harnessCoreSources = [
|
||||
"harness.ts",
|
||||
"virtualFileSystem.ts",
|
||||
"sourceMapRecorder.ts",
|
||||
"harnessLanguageService.ts",
|
||||
"fourslash.ts",
|
||||
@@ -153,14 +155,16 @@ var harnessSources = harnessCoreSources.concat([
|
||||
"tsconfigParsing.ts",
|
||||
"commandLineParsing.ts",
|
||||
"convertCompilerOptionsFromJson.ts",
|
||||
"convertTypingOptionsFromJson.ts"
|
||||
"convertTypingOptionsFromJson.ts",
|
||||
"tsserverProjectSystem.ts",
|
||||
"matchFiles.ts"
|
||||
].map(function (f) {
|
||||
return path.join(unittestsDirectory, f);
|
||||
})).concat([
|
||||
"protocol.d.ts",
|
||||
"session.ts",
|
||||
"client.ts",
|
||||
"editorServices.ts",
|
||||
"editorServices.ts"
|
||||
].map(function (f) {
|
||||
return path.join(serverDirectory, f);
|
||||
}));
|
||||
@@ -174,7 +178,7 @@ var es2015LibrarySources = [
|
||||
"es2015.proxy.d.ts",
|
||||
"es2015.reflect.d.ts",
|
||||
"es2015.symbol.d.ts",
|
||||
"es2015.symbol.wellknown.d.ts",
|
||||
"es2015.symbol.wellknown.d.ts"
|
||||
];
|
||||
|
||||
var es2015LibrarySourceMap = es2015LibrarySources.map(function(source) {
|
||||
@@ -183,28 +187,38 @@ var es2015LibrarySourceMap = es2015LibrarySources.map(function(source) {
|
||||
|
||||
var es2016LibrarySource = [ "es2016.array.include.d.ts" ];
|
||||
|
||||
var es2016LibrarySourceMap = es2016LibrarySource.map(function(source) {
|
||||
var es2016LibrarySourceMap = es2016LibrarySource.map(function (source) {
|
||||
return { target: "lib." + source, sources: ["header.d.ts", source] };
|
||||
})
|
||||
});
|
||||
|
||||
var hostsLibrarySources = ["dom.generated.d.ts", "webworker.importscripts.d.ts", "scripthost.d.ts"]
|
||||
var es2017LibrarySource = [
|
||||
"es2017.object.d.ts",
|
||||
"es2017.sharedmemory.d.ts"
|
||||
];
|
||||
|
||||
var es2017LibrarySourceMap = es2017LibrarySource.map(function (source) {
|
||||
return { target: "lib." + source, sources: ["header.d.ts", source] };
|
||||
});
|
||||
|
||||
var hostsLibrarySources = ["dom.generated.d.ts", "webworker.importscripts.d.ts", "scripthost.d.ts"];
|
||||
|
||||
var librarySourceMap = [
|
||||
// Host library
|
||||
{ target: "lib.dom.d.ts", sources: ["header.d.ts", "dom.generated.d.ts"], },
|
||||
{ target: "lib.dom.iterable.d.ts", sources: ["header.d.ts", "dom.iterable.d.ts"], },
|
||||
{ target: "lib.webworker.d.ts", sources: ["header.d.ts", "webworker.generated.d.ts"], },
|
||||
{ target: "lib.scripthost.d.ts", sources: ["header.d.ts", "scripthost.d.ts"], },
|
||||
|
||||
{ target: "lib.dom.d.ts", sources: ["header.d.ts", "dom.generated.d.ts"] },
|
||||
{ target: "lib.dom.iterable.d.ts", sources: ["header.d.ts", "dom.iterable.d.ts"] },
|
||||
{ target: "lib.webworker.d.ts", sources: ["header.d.ts", "webworker.generated.d.ts"] },
|
||||
{ target: "lib.scripthost.d.ts", sources: ["header.d.ts", "scripthost.d.ts"] },
|
||||
|
||||
// JavaScript library
|
||||
{ target: "lib.es5.d.ts", sources: ["header.d.ts", "es5.d.ts"] },
|
||||
{ target: "lib.es2015.d.ts", sources: ["header.d.ts", "es2015.d.ts"] },
|
||||
{ target: "lib.es2016.d.ts", sources: ["header.d.ts", "es2016.d.ts"] },
|
||||
|
||||
{ target: "lib.es2017.d.ts", sources: ["header.d.ts", "es2017.d.ts"] },
|
||||
|
||||
// JavaScript + all host library
|
||||
{ target: "lib.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(hostsLibrarySources), },
|
||||
{ target: "lib.es6.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(es2015LibrarySources, hostsLibrarySources), },
|
||||
].concat(es2015LibrarySourceMap, es2016LibrarySourceMap);
|
||||
{ target: "lib.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(hostsLibrarySources) },
|
||||
{ target: "lib.es6.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(es2015LibrarySources, hostsLibrarySources, "dom.iterable.d.ts") }
|
||||
].concat(es2015LibrarySourceMap, es2016LibrarySourceMap, es2017LibrarySourceMap);
|
||||
|
||||
var libraryTargets = librarySourceMap.map(function (f) {
|
||||
return path.join(builtLocalDirectory, f.target);
|
||||
@@ -244,7 +258,7 @@ function concatenateFiles(destinationFile, sourceFiles) {
|
||||
}
|
||||
|
||||
var useDebugMode = true;
|
||||
var host = (process.env.host || process.env.TYPESCRIPT_HOST || "node");
|
||||
var host = process.env.TYPESCRIPT_HOST || process.env.host || "node";
|
||||
var compilerFilename = "tsc.js";
|
||||
var LKGCompiler = path.join(LKGDirectory, compilerFilename);
|
||||
var builtLocalCompiler = path.join(builtLocalDirectory, compilerFilename);
|
||||
@@ -264,12 +278,13 @@ var builtLocalCompiler = path.join(builtLocalDirectory, compilerFilename);
|
||||
* @param {boolean} opts.noResolve: true if compiler should not include non-rooted files in compilation
|
||||
* @param {boolean} opts.stripInternal: true if compiler should remove declarations marked as @internal
|
||||
* @param {boolean} opts.noMapRoot: true if compiler omit mapRoot option
|
||||
* @param {boolean} opts.inlineSourceMap: true if compiler should inline sourceMap
|
||||
* @param callback: a function to execute after the compilation process ends
|
||||
*/
|
||||
function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts, callback) {
|
||||
file(outFile, prereqs, function() {
|
||||
var compilerPath = useBuiltCompiler ? builtLocalCompiler : LKGCompiler;
|
||||
var options = "--noImplicitAny --noEmitOnError --pretty";
|
||||
var options = "--noImplicitAny --noEmitOnError --types --pretty";
|
||||
opts = opts || {};
|
||||
// Keep comments when specifically requested
|
||||
// or when in debug mode.
|
||||
@@ -293,7 +308,7 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts
|
||||
options += " --out " + outFile;
|
||||
}
|
||||
else {
|
||||
options += " --module commonjs"
|
||||
options += " --module commonjs";
|
||||
}
|
||||
|
||||
if(opts.noResolve) {
|
||||
@@ -301,14 +316,20 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts
|
||||
}
|
||||
|
||||
if (useDebugMode) {
|
||||
options += " -sourcemap";
|
||||
if (!opts.noMapRoot) {
|
||||
options += " -mapRoot file:///" + path.resolve(path.dirname(outFile));
|
||||
if (opts.inlineSourceMap) {
|
||||
options += " --inlineSourceMap --inlineSources";
|
||||
} else {
|
||||
options += " -sourcemap";
|
||||
if (!opts.noMapRoot) {
|
||||
options += " -mapRoot file:///" + path.resolve(path.dirname(outFile));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
options += " --newLine LF";
|
||||
}
|
||||
|
||||
if (opts.stripInternal) {
|
||||
options += " --stripInternal"
|
||||
options += " --stripInternal";
|
||||
}
|
||||
|
||||
var cmd = host + " " + compilerPath + " " + options + " ";
|
||||
@@ -446,9 +467,9 @@ file(scriptsTsdJson);
|
||||
|
||||
task("tsd-scripts", [scriptsTsdJson], function () {
|
||||
var cmd = "tsd --config " + scriptsTsdJson + " install";
|
||||
console.log(cmd)
|
||||
console.log(cmd);
|
||||
exec(cmd);
|
||||
}, { async: true })
|
||||
}, { async: true });
|
||||
|
||||
var importDefinitelyTypedTestsDirectory = path.join(scriptsDirectory, "importDefinitelyTypedTests");
|
||||
var importDefinitelyTypedTestsJs = path.join(importDefinitelyTypedTestsDirectory, "importDefinitelyTypedTests.js");
|
||||
@@ -481,7 +502,13 @@ var nodeStandaloneDefinitionsFile = path.join(builtLocalDirectory, "typescript_s
|
||||
compileFile(servicesFile, servicesSources,[builtLocalDirectory, copyright].concat(servicesSources),
|
||||
/*prefixes*/ [copyright],
|
||||
/*useBuiltCompiler*/ true,
|
||||
{ noOutFile: false, generateDeclarations: true, preserveConstEnums: true, keepComments: true, noResolve: false, stripInternal: true },
|
||||
/*opts*/ { noOutFile: false,
|
||||
generateDeclarations: true,
|
||||
preserveConstEnums: true,
|
||||
keepComments: true,
|
||||
noResolve: false,
|
||||
stripInternal: true
|
||||
},
|
||||
/*callback*/ function () {
|
||||
jake.cpR(servicesFile, nodePackageFile, {silent: true});
|
||||
|
||||
@@ -504,23 +531,29 @@ compileFile(servicesFile, servicesSources,[builtLocalDirectory, copyright].conca
|
||||
fs.writeFileSync(nodeStandaloneDefinitionsFile, nodeStandaloneDefinitionsFileContents);
|
||||
});
|
||||
|
||||
compileFile(servicesFileInBrowserTest, servicesSources,[builtLocalDirectory, copyright].concat(servicesSources),
|
||||
/*prefixes*/ [copyright],
|
||||
/*useBuiltCompiler*/ true,
|
||||
{ noOutFile: false, generateDeclarations: true, preserveConstEnums: true, keepComments: true, noResolve: false, stripInternal: true, noMapRoot: true },
|
||||
/*callback*/ function () {
|
||||
var content = fs.readFileSync(servicesFileInBrowserTest).toString();
|
||||
var i = content.lastIndexOf("\n");
|
||||
fs.writeFileSync(servicesFileInBrowserTest, content.substring(0, i) + "\r\n//# sourceURL=../built/local/typeScriptServices.js" + content.substring(i));
|
||||
});
|
||||
|
||||
compileFile(
|
||||
servicesFileInBrowserTest,
|
||||
servicesSources,
|
||||
[builtLocalDirectory, copyright].concat(servicesSources),
|
||||
/*prefixes*/ [copyright],
|
||||
/*useBuiltCompiler*/ true,
|
||||
{ noOutFile: false,
|
||||
generateDeclarations: true,
|
||||
preserveConstEnums: true,
|
||||
keepComments: true,
|
||||
noResolve: false,
|
||||
stripInternal: true,
|
||||
noMapRoot: true,
|
||||
inlineSourceMap: true
|
||||
});
|
||||
|
||||
var serverFile = path.join(builtLocalDirectory, "tsserver.js");
|
||||
compileFile(serverFile, serverSources,[builtLocalDirectory, copyright].concat(serverSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true);
|
||||
|
||||
var lsslFile = path.join(builtLocalDirectory, "tslssl.js");
|
||||
var tsserverLibraryFile = path.join(builtLocalDirectory, "tsserverlibrary.js");
|
||||
var tsserverLibraryDefinitionFile = path.join(builtLocalDirectory, "tsserverlibrary.d.ts");
|
||||
compileFile(
|
||||
lsslFile,
|
||||
tsserverLibraryFile,
|
||||
languageServiceLibrarySources,
|
||||
[builtLocalDirectory, copyright].concat(languageServiceLibrarySources),
|
||||
/*prefixes*/ [copyright],
|
||||
@@ -529,7 +562,7 @@ compileFile(
|
||||
|
||||
// Local target to build the language service server library
|
||||
desc("Builds language service server library");
|
||||
task("lssl", [lsslFile]);
|
||||
task("lssl", [tsserverLibraryFile, tsserverLibraryDefinitionFile]);
|
||||
|
||||
// Local target to build the compiler and services
|
||||
desc("Builds the full compiler and services");
|
||||
@@ -588,8 +621,8 @@ 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", ["clean", "release", "local"].concat(libraryTargets), function() {
|
||||
var expectedFiles = [tscFile, servicesFile, serverFile, nodePackageFile, nodeDefinitionsFile, standaloneDefinitionsFile].concat(libraryTargets);
|
||||
task("LKG", ["clean", "release", "local", "lssl"].concat(libraryTargets), function() {
|
||||
var expectedFiles = [tscFile, servicesFile, serverFile, nodePackageFile, nodeDefinitionsFile, standaloneDefinitionsFile, tsserverLibraryFile, tsserverLibraryDefinitionFile].concat(libraryTargets);
|
||||
var missingFiles = expectedFiles.filter(function (f) {
|
||||
return !fs.existsSync(f);
|
||||
});
|
||||
@@ -613,9 +646,15 @@ directory(builtLocalDirectory);
|
||||
|
||||
// Task to build the tests infrastructure using the built compiler
|
||||
var run = path.join(builtLocalDirectory, "run.js");
|
||||
compileFile(run, harnessSources, [builtLocalDirectory, tscFile].concat(libraryTargets).concat(harnessSources), [], /*useBuiltCompiler:*/ true);
|
||||
compileFile(
|
||||
/*outFile*/ run,
|
||||
/*source*/ harnessSources,
|
||||
/*prereqs*/ [builtLocalDirectory, tscFile].concat(libraryTargets).concat(harnessSources),
|
||||
/*prefixes*/ [],
|
||||
/*useBuiltCompiler:*/ true,
|
||||
/*opts*/ { inlineSourceMap: true });
|
||||
|
||||
var internalTests = "internal/"
|
||||
var internalTests = "internal/";
|
||||
|
||||
var localBaseline = "tests/baselines/local/";
|
||||
var refBaseline = "tests/baselines/reference/";
|
||||
@@ -672,9 +711,8 @@ function cleanTestDirs() {
|
||||
}
|
||||
|
||||
// used to pass data from jake command line directly to run.js
|
||||
function writeTestConfigFile(tests, light, testConfigFile) {
|
||||
console.log('Running test(s): ' + tests);
|
||||
var testConfigContents = JSON.stringify({ test: [tests], light: light });
|
||||
function writeTestConfigFile(tests, light, taskConfigsFolder, workerCount) {
|
||||
var testConfigContents = JSON.stringify({ test: tests ? [tests] : undefined, light: light, workerCount: workerCount, taskConfigsFolder: taskConfigsFolder });
|
||||
fs.writeFileSync('test.config', testConfigContents);
|
||||
}
|
||||
|
||||
@@ -684,7 +722,7 @@ function deleteTemporaryProjectOutput() {
|
||||
}
|
||||
}
|
||||
|
||||
function runConsoleTests(defaultReporter, defaultSubsets) {
|
||||
function runConsoleTests(defaultReporter, runInParallel) {
|
||||
cleanTestDirs();
|
||||
var debug = process.env.debug || process.env.d;
|
||||
tests = process.env.test || process.env.tests || process.env.t;
|
||||
@@ -693,59 +731,106 @@ function runConsoleTests(defaultReporter, defaultSubsets) {
|
||||
if(fs.existsSync(testConfigFile)) {
|
||||
fs.unlinkSync(testConfigFile);
|
||||
}
|
||||
var workerCount, taskConfigsFolder;
|
||||
if (runInParallel) {
|
||||
// generate name to store task configuration files
|
||||
var prefix = os.tmpdir() + "/ts-tests";
|
||||
var i = 1;
|
||||
do {
|
||||
taskConfigsFolder = prefix + i;
|
||||
i++;
|
||||
} while (fs.existsSync(taskConfigsFolder));
|
||||
fs.mkdirSync(taskConfigsFolder);
|
||||
|
||||
if (tests || light) {
|
||||
writeTestConfigFile(tests, light, testConfigFile);
|
||||
workerCount = process.env.workerCount || os.cpus().length;
|
||||
}
|
||||
|
||||
if (tests || light || taskConfigsFolder) {
|
||||
writeTestConfigFile(tests, light, taskConfigsFolder, workerCount);
|
||||
}
|
||||
|
||||
if (tests && tests.toLocaleLowerCase() === "rwc") {
|
||||
testTimeout = 100000;
|
||||
}
|
||||
|
||||
colors = process.env.colors || process.env.color
|
||||
colors = process.env.colors || process.env.color;
|
||||
colors = colors ? ' --no-colors ' : ' --colors ';
|
||||
reporter = process.env.reporter || process.env.r || defaultReporter;
|
||||
var bail = (process.env.bail || process.env.b) ? "--bail" : "";
|
||||
var lintFlag = process.env.lint !== 'false';
|
||||
|
||||
// timeout normally isn't necessary but Travis-CI has been timing out on compiler baselines occasionally
|
||||
// default timeout is 2sec which really should be enough, but maybe we just need a small amount longer
|
||||
var subsetRegexes;
|
||||
if(defaultSubsets.length === 0) {
|
||||
subsetRegexes = [tests]
|
||||
if(!runInParallel) {
|
||||
tests = tests ? ' -g "' + tests + '"' : '';
|
||||
var cmd = "mocha" + (debug ? " --debug-brk" : "") + " -R " + reporter + tests + colors + bail + ' -t ' + testTimeout + ' ' + run;
|
||||
console.log(cmd);
|
||||
|
||||
var savedNodeEnv = process.env.NODE_ENV;
|
||||
process.env.NODE_ENV = "development";
|
||||
exec(cmd, function () {
|
||||
process.env.NODE_ENV = savedNodeEnv;
|
||||
runLinter();
|
||||
finish();
|
||||
}, function(e, status) {
|
||||
process.env.NODE_ENV = savedNodeEnv;
|
||||
finish(status);
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
var subsets = tests ? tests.split("|") : defaultSubsets;
|
||||
subsetRegexes = subsets.map(function (sub) { return "^" + sub + ".*$"; });
|
||||
subsetRegexes.push("^(?!" + subsets.join("|") + ").*$");
|
||||
}
|
||||
subsetRegexes.forEach(function (subsetRegex, i) {
|
||||
tests = subsetRegex ? ' -g "' + subsetRegex + '"' : '';
|
||||
var cmd = "mocha" + (debug ? " --debug-brk" : "") + " -R " + reporter + tests + colors + ' -t ' + testTimeout + ' ' + run;
|
||||
console.log(cmd);
|
||||
exec(cmd, function () {
|
||||
var savedNodeEnv = process.env.NODE_ENV;
|
||||
process.env.NODE_ENV = "development";
|
||||
runTestsInParallel(taskConfigsFolder, run, { testTimeout: testTimeout, noColors: colors === " --no-colors " }, function (err) {
|
||||
process.env.NODE_ENV = savedNodeEnv;
|
||||
|
||||
// last worker clean everything and runs linter in case if there were no errors
|
||||
deleteTemporaryProjectOutput();
|
||||
if (i === 0) {
|
||||
var lint = jake.Task['lint'];
|
||||
lint.addListener('complete', function () {
|
||||
complete();
|
||||
});
|
||||
lint.invoke();
|
||||
jake.rmRf(taskConfigsFolder);
|
||||
if (err) {
|
||||
fail(err);
|
||||
}
|
||||
else {
|
||||
runLinter();
|
||||
complete();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function failWithStatus(status) {
|
||||
fail("Process exited with code " + status);
|
||||
}
|
||||
|
||||
function finish(errorStatus) {
|
||||
deleteTemporaryProjectOutput();
|
||||
if (errorStatus !== undefined) {
|
||||
failWithStatus(errorStatus);
|
||||
}
|
||||
else {
|
||||
complete();
|
||||
}
|
||||
}
|
||||
function runLinter() {
|
||||
if (!lintFlag) {
|
||||
return;
|
||||
}
|
||||
var lint = jake.Task['lint'];
|
||||
lint.addListener('complete', function () {
|
||||
complete();
|
||||
});
|
||||
lint.invoke();
|
||||
}
|
||||
}
|
||||
|
||||
var testTimeout = 20000;
|
||||
desc("Runs all the tests in parallel using the built run.js file. Optional arguments are: t[ests]=category1|category2|... d[ebug]=true.");
|
||||
task("runtests-parallel", ["build-rules", "tests", builtLocalDirectory], function() {
|
||||
runConsoleTests('min', ['compiler', 'conformance', 'Projects', 'fourslash']);
|
||||
runConsoleTests('min', /*runInParallel*/ true);
|
||||
}, {async: true});
|
||||
|
||||
desc("Runs the tests using the built run.js file. Optional arguments are: t[ests]=regex r[eporter]=[list|spec|json|<more>] d[ebug]=true color[s]=false.");
|
||||
desc("Runs the tests using the built run.js file. Optional arguments are: t[ests]=regex r[eporter]=[list|spec|json|<more>] d[ebug]=true color[s]=false lint=true bail=false.");
|
||||
task("runtests", ["build-rules", "tests", builtLocalDirectory], function() {
|
||||
runConsoleTests('mocha-fivemat-progress-reporter', []);
|
||||
runConsoleTests('mocha-fivemat-progress-reporter', /*runInParallel*/ false);
|
||||
}, {async: true});
|
||||
|
||||
desc("Generates code coverage data via instanbul");
|
||||
@@ -756,20 +841,20 @@ task("generate-code-coverage", ["tests", builtLocalDirectory], function () {
|
||||
}, { async: true });
|
||||
|
||||
// Browser tests
|
||||
var nodeServerOutFile = 'tests/webTestServer.js'
|
||||
var nodeServerInFile = 'tests/webTestServer.ts'
|
||||
var nodeServerOutFile = "tests/webTestServer.js";
|
||||
var nodeServerInFile = "tests/webTestServer.ts";
|
||||
compileFile(nodeServerOutFile, [nodeServerInFile], [builtLocalDirectory, tscFile], [], /*useBuiltCompiler:*/ true, { noOutFile: true });
|
||||
|
||||
desc("Runs browserify on run.js to produce a file suitable for running tests in the browser");
|
||||
task("browserify", ["tests", builtLocalDirectory, nodeServerOutFile], function() {
|
||||
var cmd = 'browserify built/local/run.js -o built/local/bundle.js';
|
||||
var cmd = 'browserify built/local/run.js -d -o built/local/bundle.js';
|
||||
exec(cmd);
|
||||
}, {async: true});
|
||||
|
||||
desc("Runs the tests using the built run.js file like 'jake runtests'. Syntax is jake runtests-browser. Additional optional parameters tests=[regex], port=, browser=[chrome|IE]");
|
||||
task("runtests-browser", ["tests", "browserify", builtLocalDirectory, servicesFileInBrowserTest], function() {
|
||||
cleanTestDirs();
|
||||
host = "node"
|
||||
host = "node";
|
||||
port = process.env.port || process.env.p || '8888';
|
||||
browser = process.env.browser || process.env.b || "IE";
|
||||
tests = process.env.test || process.env.tests || process.env.t;
|
||||
@@ -779,17 +864,17 @@ task("runtests-browser", ["tests", "browserify", builtLocalDirectory, servicesFi
|
||||
fs.unlinkSync(testConfigFile);
|
||||
}
|
||||
if(tests || light) {
|
||||
writeTestConfigFile(tests, light, testConfigFile);
|
||||
writeTestConfigFile(tests, light);
|
||||
}
|
||||
|
||||
tests = tests ? tests : '';
|
||||
var cmd = host + " tests/webTestServer.js " + port + " " + browser + " " + tests
|
||||
var cmd = host + " tests/webTestServer.js " + port + " " + browser + " " + JSON.stringify(tests);
|
||||
console.log(cmd);
|
||||
exec(cmd);
|
||||
}, {async: true});
|
||||
|
||||
function getDiffTool() {
|
||||
var program = process.env['DIFF']
|
||||
var program = process.env['DIFF'];
|
||||
if (!program) {
|
||||
fail("Add the 'DIFF' environment variable to the path of the program you want to use.");
|
||||
}
|
||||
@@ -818,11 +903,11 @@ task("tests-debug", ["setDebugMode", "tests"]);
|
||||
// Makes the test results the new baseline
|
||||
desc("Makes the most recent test results the new baseline, overwriting the old baseline");
|
||||
task("baseline-accept", function(hardOrSoft) {
|
||||
if (!hardOrSoft || hardOrSoft == "hard") {
|
||||
if (!hardOrSoft || hardOrSoft === "hard") {
|
||||
jake.rmRf(refBaseline);
|
||||
fs.renameSync(localBaseline, refBaseline);
|
||||
}
|
||||
else if (hardOrSoft == "soft") {
|
||||
else if (hardOrSoft === "soft") {
|
||||
var files = jake.readdirR(localBaseline);
|
||||
for (var i in files) {
|
||||
jake.cpR(files[i], refBaseline);
|
||||
@@ -901,15 +986,15 @@ task("update-sublime", ["local", serverFile], function() {
|
||||
});
|
||||
|
||||
var tslintRuleDir = "scripts/tslint";
|
||||
var tslintRules = ([
|
||||
var tslintRules = [
|
||||
"nextLineRule",
|
||||
"noNullRule",
|
||||
"preferConstRule",
|
||||
"booleanTriviaRule",
|
||||
"typeOperatorSpacingRule",
|
||||
"noInOperatorRule",
|
||||
"noIncrementDecrementRule"
|
||||
]);
|
||||
"noIncrementDecrementRule",
|
||||
"objectLiteralSurroundingSpaceRule",
|
||||
];
|
||||
var tslintRulesFiles = tslintRules.map(function(p) {
|
||||
return path.join(tslintRuleDir, p + ".ts");
|
||||
});
|
||||
@@ -934,7 +1019,7 @@ function getLinterOptions() {
|
||||
|
||||
function lintFileContents(options, path, contents) {
|
||||
var ll = new Linter(path, contents, options);
|
||||
console.log("Linting '" + path + "'.")
|
||||
console.log("Linting '" + path + "'.");
|
||||
return ll.lint();
|
||||
}
|
||||
|
||||
@@ -953,31 +1038,31 @@ function lintFileAsync(options, path, cb) {
|
||||
});
|
||||
}
|
||||
|
||||
var servicesLintTargets = [
|
||||
"navigateTo.ts",
|
||||
"outliningElementsCollector.ts",
|
||||
"patternMatcher.ts",
|
||||
"services.ts",
|
||||
"shims.ts",
|
||||
"jsTyping.ts"
|
||||
].map(function (s) {
|
||||
return path.join(servicesDirectory, s);
|
||||
});
|
||||
var lintTargets = compilerSources
|
||||
.concat(harnessCoreSources)
|
||||
.concat(harnessSources)
|
||||
// Other harness sources
|
||||
.concat(["instrumenter.ts"].map(function(f) { return path.join(harnessDirectory, f) }))
|
||||
.concat(serverCoreSources)
|
||||
.concat(tslintRulesFiles)
|
||||
.concat(servicesLintTargets);
|
||||
.concat(servicesSources)
|
||||
.concat(["Gulpfile.ts"]);
|
||||
|
||||
desc("Runs tslint on the compiler sources");
|
||||
|
||||
desc("Runs tslint on the compiler sources. Optional arguments are: f[iles]=regex");
|
||||
task("lint", ["build-rules"], function() {
|
||||
var lintOptions = getLinterOptions();
|
||||
var failed = 0;
|
||||
var fileMatcher = RegExp(process.env.f || process.env.file || process.env.files || "");
|
||||
var done = {};
|
||||
for (var i in lintTargets) {
|
||||
var result = lintFile(lintOptions, lintTargets[i]);
|
||||
if (result.failureCount > 0) {
|
||||
console.log(result.output);
|
||||
failed += result.failureCount;
|
||||
var target = lintTargets[i];
|
||||
if (!done[target] && fileMatcher.test(target)) {
|
||||
var result = lintFile(lintOptions, target);
|
||||
if (result.failureCount > 0) {
|
||||
console.log(result.output);
|
||||
failed += result.failureCount;
|
||||
}
|
||||
done[target] = true;
|
||||
}
|
||||
}
|
||||
if (failed > 0) {
|
||||
|
||||
@@ -56,29 +56,29 @@ Change to the TypeScript directory:
|
||||
cd TypeScript
|
||||
```
|
||||
|
||||
Install Jake tools and dev dependencies:
|
||||
Install Gulp tools and dev dependencies:
|
||||
|
||||
```
|
||||
npm install -g jake
|
||||
npm install -g gulp
|
||||
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.
|
||||
gulp local # Build the compiler into built/local
|
||||
gulp clean # Delete the built compiler
|
||||
gulp 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.
|
||||
gulp tests # Build the test infrastructure using the built compiler.
|
||||
gulp 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
|
||||
gulp runtests-browser # Runs the tests using the built run.js file. Syntax is gulp 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 lint # Runs tslint on the TypeScript source.
|
||||
jake -T # List the above commands.
|
||||
gulp baseline-accept # This replaces the baseline test results with the results obtained from gulp runtests.
|
||||
gulp lint # Runs tslint on the TypeScript source.
|
||||
gulp help # List the above commands.
|
||||
```
|
||||
|
||||
|
||||
|
||||
Vendored
-5255
File diff suppressed because it is too large
Load Diff
Vendored
-5344
File diff suppressed because it is too large
Load Diff
Vendored
+5901
-4288
File diff suppressed because it is too large
Load Diff
Vendored
+5042
-3649
File diff suppressed because it is too large
Load Diff
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
/*! *****************************************************************************
|
||||
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
|
||||
|
||||
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.
|
||||
***************************************************************************** */
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
/// <reference path="lib.dom.generated.d.ts" />
|
||||
|
||||
interface DOMTokenList {
|
||||
[Symbol.iterator](): IterableIterator<string>;
|
||||
}
|
||||
|
||||
interface NodeList {
|
||||
[Symbol.iterator](): IterableIterator<Node>
|
||||
}
|
||||
|
||||
interface NodeListOf<TNode extends Node> {
|
||||
[Symbol.iterator](): IterableIterator<TNode>
|
||||
}
|
||||
Vendored
+77
@@ -0,0 +1,77 @@
|
||||
/*! *****************************************************************************
|
||||
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
|
||||
|
||||
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.
|
||||
***************************************************************************** */
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
interface Map<K, V> {
|
||||
clear(): void;
|
||||
delete(key: K): boolean;
|
||||
forEach(callbackfn: (value: V, index: K, map: Map<K, V>) => void, thisArg?: any): void;
|
||||
get(key: K): V | undefined;
|
||||
has(key: K): boolean;
|
||||
set(key: K, value?: V): this;
|
||||
readonly size: number;
|
||||
}
|
||||
|
||||
interface MapConstructor {
|
||||
new (): Map<any, any>;
|
||||
new <K, V>(entries?: [K, V][]): Map<K, V>;
|
||||
readonly prototype: Map<any, any>;
|
||||
}
|
||||
declare var Map: MapConstructor;
|
||||
|
||||
interface WeakMap<K, V> {
|
||||
clear(): void;
|
||||
delete(key: K): boolean;
|
||||
get(key: K): V | undefined;
|
||||
has(key: K): boolean;
|
||||
set(key: K, value?: V): this;
|
||||
}
|
||||
|
||||
interface WeakMapConstructor {
|
||||
new (): WeakMap<any, any>;
|
||||
new <K, V>(entries?: [K, V][]): WeakMap<K, V>;
|
||||
readonly prototype: WeakMap<any, any>;
|
||||
}
|
||||
declare var WeakMap: WeakMapConstructor;
|
||||
|
||||
interface Set<T> {
|
||||
add(value: T): this;
|
||||
clear(): void;
|
||||
delete(value: T): boolean;
|
||||
forEach(callbackfn: (value: T, index: T, set: Set<T>) => void, thisArg?: any): void;
|
||||
has(value: T): boolean;
|
||||
readonly size: number;
|
||||
}
|
||||
|
||||
interface SetConstructor {
|
||||
new (): Set<any>;
|
||||
new <T>(values?: T[]): Set<T>;
|
||||
readonly prototype: Set<any>;
|
||||
}
|
||||
declare var Set: SetConstructor;
|
||||
|
||||
interface WeakSet<T> {
|
||||
add(value: T): this;
|
||||
clear(): void;
|
||||
delete(value: T): boolean;
|
||||
has(value: T): boolean;
|
||||
}
|
||||
|
||||
interface WeakSetConstructor {
|
||||
new (): WeakSet<any>;
|
||||
new <T>(values?: T[]): WeakSet<T>;
|
||||
readonly prototype: WeakSet<any>;
|
||||
}
|
||||
declare var WeakSet: WeakSetConstructor;
|
||||
Vendored
+512
@@ -0,0 +1,512 @@
|
||||
/*! *****************************************************************************
|
||||
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
|
||||
|
||||
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.
|
||||
***************************************************************************** */
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
declare type PropertyKey = string | number | symbol;
|
||||
|
||||
interface Array<T> {
|
||||
/**
|
||||
* Returns the value of the first element in the array where predicate is true, and undefined
|
||||
* otherwise.
|
||||
* @param predicate find calls predicate once for each element of the array, in ascending
|
||||
* order, until it finds one where predicate returns true. If such an element is found, find
|
||||
* immediately returns that element value. Otherwise, find returns undefined.
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: T, index: number, obj: Array<T>) => boolean, thisArg?: any): T | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and undefined
|
||||
* otherwise.
|
||||
* @param predicate find calls predicate once for each element of the array, in ascending
|
||||
* order, until it finds one where predicate returns true. If such an element is found,
|
||||
* findIndex immediately returns that element index. Otherwise, findIndex returns -1.
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: T) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Returns the this object after filling the section identified by start and end with value
|
||||
* @param value value to fill array section with
|
||||
* @param start index to start filling the array at. If start is negative, it is treated as
|
||||
* length+start where length is the length of the array.
|
||||
* @param end index to stop filling the array at. If end is negative, it is treated as
|
||||
* length+end.
|
||||
*/
|
||||
fill(value: T, start?: number, end?: number): this;
|
||||
|
||||
/**
|
||||
* Returns the this object after copying a section of the array identified by start and end
|
||||
* to the same array starting at position target
|
||||
* @param target If target is negative, it is treated as length+target where length is the
|
||||
* length of the array.
|
||||
* @param start If start is negative, it is treated as length+start. If end is negative, it
|
||||
* is treated as length+end.
|
||||
* @param end If not specified, length of the this object is used as its default value.
|
||||
*/
|
||||
copyWithin(target: number, start: number, end?: number): this;
|
||||
}
|
||||
|
||||
interface ArrayConstructor {
|
||||
/**
|
||||
* Creates an array from an array-like object.
|
||||
* @param arrayLike An array-like object to convert to an array.
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from<T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): Array<U>;
|
||||
|
||||
|
||||
/**
|
||||
* Creates an array from an array-like object.
|
||||
* @param arrayLike An array-like object to convert to an array.
|
||||
*/
|
||||
from<T>(arrayLike: ArrayLike<T>): Array<T>;
|
||||
|
||||
/**
|
||||
* Returns a new array from a set of elements.
|
||||
* @param items A set of elements to include in the new array object.
|
||||
*/
|
||||
of<T>(...items: T[]): Array<T>;
|
||||
}
|
||||
|
||||
interface Function {
|
||||
/**
|
||||
* Returns the name of the function. Function names are read-only and can not be changed.
|
||||
*/
|
||||
readonly name: string;
|
||||
}
|
||||
|
||||
interface Math {
|
||||
/**
|
||||
* Returns the number of leading zero bits in the 32-bit binary representation of a number.
|
||||
* @param x A numeric expression.
|
||||
*/
|
||||
clz32(x: number): number;
|
||||
|
||||
/**
|
||||
* Returns the result of 32-bit multiplication of two numbers.
|
||||
* @param x First number
|
||||
* @param y Second number
|
||||
*/
|
||||
imul(x: number, y: number): number;
|
||||
|
||||
/**
|
||||
* Returns the sign of the x, indicating whether x is positive, negative or zero.
|
||||
* @param x The numeric expression to test
|
||||
*/
|
||||
sign(x: number): number;
|
||||
|
||||
/**
|
||||
* Returns the base 10 logarithm of a number.
|
||||
* @param x A numeric expression.
|
||||
*/
|
||||
log10(x: number): number;
|
||||
|
||||
/**
|
||||
* Returns the base 2 logarithm of a number.
|
||||
* @param x A numeric expression.
|
||||
*/
|
||||
log2(x: number): number;
|
||||
|
||||
/**
|
||||
* Returns the natural logarithm of 1 + x.
|
||||
* @param x A numeric expression.
|
||||
*/
|
||||
log1p(x: number): number;
|
||||
|
||||
/**
|
||||
* Returns the result of (e^x - 1) of x (e raised to the power of x, where e is the base of
|
||||
* the natural logarithms).
|
||||
* @param x A numeric expression.
|
||||
*/
|
||||
expm1(x: number): number;
|
||||
|
||||
/**
|
||||
* Returns the hyperbolic cosine of a number.
|
||||
* @param x A numeric expression that contains an angle measured in radians.
|
||||
*/
|
||||
cosh(x: number): number;
|
||||
|
||||
/**
|
||||
* Returns the hyperbolic sine of a number.
|
||||
* @param x A numeric expression that contains an angle measured in radians.
|
||||
*/
|
||||
sinh(x: number): number;
|
||||
|
||||
/**
|
||||
* Returns the hyperbolic tangent of a number.
|
||||
* @param x A numeric expression that contains an angle measured in radians.
|
||||
*/
|
||||
tanh(x: number): number;
|
||||
|
||||
/**
|
||||
* Returns the inverse hyperbolic cosine of a number.
|
||||
* @param x A numeric expression that contains an angle measured in radians.
|
||||
*/
|
||||
acosh(x: number): number;
|
||||
|
||||
/**
|
||||
* Returns the inverse hyperbolic sine of a number.
|
||||
* @param x A numeric expression that contains an angle measured in radians.
|
||||
*/
|
||||
asinh(x: number): number;
|
||||
|
||||
/**
|
||||
* Returns the inverse hyperbolic tangent of a number.
|
||||
* @param x A numeric expression that contains an angle measured in radians.
|
||||
*/
|
||||
atanh(x: number): number;
|
||||
|
||||
/**
|
||||
* Returns the square root of the sum of squares of its arguments.
|
||||
* @param values Values to compute the square root for.
|
||||
* If no arguments are passed, the result is +0.
|
||||
* If there is only one argument, the result is the absolute value.
|
||||
* If any argument is +Infinity or -Infinity, the result is +Infinity.
|
||||
* If any argument is NaN, the result is NaN.
|
||||
* If all arguments are either +0 or −0, the result is +0.
|
||||
*/
|
||||
hypot(...values: number[] ): number;
|
||||
|
||||
/**
|
||||
* Returns the integral part of the a numeric expression, x, removing any fractional digits.
|
||||
* If x is already an integer, the result is x.
|
||||
* @param x A numeric expression.
|
||||
*/
|
||||
trunc(x: number): number;
|
||||
|
||||
/**
|
||||
* Returns the nearest single precision float representation of a number.
|
||||
* @param x A numeric expression.
|
||||
*/
|
||||
fround(x: number): number;
|
||||
|
||||
/**
|
||||
* Returns an implementation-dependent approximation to the cube root of number.
|
||||
* @param x A numeric expression.
|
||||
*/
|
||||
cbrt(x: number): number;
|
||||
}
|
||||
|
||||
interface NumberConstructor {
|
||||
/**
|
||||
* The value of Number.EPSILON is the difference between 1 and the smallest value greater than 1
|
||||
* that is representable as a Number value, which is approximately:
|
||||
* 2.2204460492503130808472633361816 x 10−16.
|
||||
*/
|
||||
readonly EPSILON: number;
|
||||
|
||||
/**
|
||||
* Returns true if passed value is finite.
|
||||
* Unlike the global isFininte, Number.isFinite doesn't forcibly convert the parameter to a
|
||||
* number. Only finite values of the type number, result in true.
|
||||
* @param number A numeric value.
|
||||
*/
|
||||
isFinite(number: number): boolean;
|
||||
|
||||
/**
|
||||
* Returns true if the value passed is an integer, false otherwise.
|
||||
* @param number A numeric value.
|
||||
*/
|
||||
isInteger(number: number): boolean;
|
||||
|
||||
/**
|
||||
* Returns a Boolean value that indicates whether a value is the reserved value NaN (not a
|
||||
* number). Unlike the global isNaN(), Number.isNaN() doesn't forcefully convert the parameter
|
||||
* to a number. Only values of the type number, that are also NaN, result in true.
|
||||
* @param number A numeric value.
|
||||
*/
|
||||
isNaN(number: number): boolean;
|
||||
|
||||
/**
|
||||
* Returns true if the value passed is a safe integer.
|
||||
* @param number A numeric value.
|
||||
*/
|
||||
isSafeInteger(number: number): boolean;
|
||||
|
||||
/**
|
||||
* The value of the largest integer n such that n and n + 1 are both exactly representable as
|
||||
* a Number value.
|
||||
* The value of Number.MIN_SAFE_INTEGER is 9007199254740991 2^53 − 1.
|
||||
*/
|
||||
readonly MAX_SAFE_INTEGER: number;
|
||||
|
||||
/**
|
||||
* The value of the smallest integer n such that n and n − 1 are both exactly representable as
|
||||
* a Number value.
|
||||
* The value of Number.MIN_SAFE_INTEGER is −9007199254740991 (−(2^53 − 1)).
|
||||
*/
|
||||
readonly MIN_SAFE_INTEGER: number;
|
||||
|
||||
/**
|
||||
* Converts a string to a floating-point number.
|
||||
* @param string A string that contains a floating-point number.
|
||||
*/
|
||||
parseFloat(string: string): number;
|
||||
|
||||
/**
|
||||
* Converts A string to an integer.
|
||||
* @param s A string to convert into a number.
|
||||
* @param radix A value between 2 and 36 that specifies the base of the number in numString.
|
||||
* If this argument is not supplied, strings with a prefix of '0x' are considered hexadecimal.
|
||||
* All other strings are considered decimal.
|
||||
*/
|
||||
parseInt(string: string, radix?: number): number;
|
||||
}
|
||||
|
||||
interface Object {
|
||||
/**
|
||||
* Determines whether an object has a property with the specified name.
|
||||
* @param v A property name.
|
||||
*/
|
||||
hasOwnProperty(v: PropertyKey): boolean
|
||||
|
||||
/**
|
||||
* Determines whether a specified property is enumerable.
|
||||
* @param v A property name.
|
||||
*/
|
||||
propertyIsEnumerable(v: PropertyKey): boolean;
|
||||
}
|
||||
|
||||
interface ObjectConstructor {
|
||||
/**
|
||||
* Copy the values of all of the enumerable own properties from one or more source objects to a
|
||||
* target object. Returns the target object.
|
||||
* @param target The target object to copy to.
|
||||
* @param source The source object from which to copy properties.
|
||||
*/
|
||||
assign<T, U>(target: T, source: U): T & U;
|
||||
|
||||
/**
|
||||
* Copy the values of all of the enumerable own properties from one or more source objects to a
|
||||
* target object. Returns the target object.
|
||||
* @param target The target object to copy to.
|
||||
* @param source1 The first source object from which to copy properties.
|
||||
* @param source2 The second source object from which to copy properties.
|
||||
*/
|
||||
assign<T, U, V>(target: T, source1: U, source2: V): T & U & V;
|
||||
|
||||
/**
|
||||
* Copy the values of all of the enumerable own properties from one or more source objects to a
|
||||
* target object. Returns the target object.
|
||||
* @param target The target object to copy to.
|
||||
* @param source1 The first source object from which to copy properties.
|
||||
* @param source2 The second source object from which to copy properties.
|
||||
* @param source3 The third source object from which to copy properties.
|
||||
*/
|
||||
assign<T, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W;
|
||||
|
||||
/**
|
||||
* Copy the values of all of the enumerable own properties from one or more source objects to a
|
||||
* target object. Returns the target object.
|
||||
* @param target The target object to copy to.
|
||||
* @param sources One or more source objects from which to copy properties
|
||||
*/
|
||||
assign(target: any, ...sources: any[]): any;
|
||||
|
||||
/**
|
||||
* Returns an array of all symbol properties found directly on object o.
|
||||
* @param o Object to retrieve the symbols from.
|
||||
*/
|
||||
getOwnPropertySymbols(o: any): symbol[];
|
||||
|
||||
/**
|
||||
* Returns true if the values are the same value, false otherwise.
|
||||
* @param value1 The first value.
|
||||
* @param value2 The second value.
|
||||
*/
|
||||
is(value1: any, value2: any): boolean;
|
||||
|
||||
/**
|
||||
* Sets the prototype of a specified object o to object proto or null. Returns the object o.
|
||||
* @param o The object to change its prototype.
|
||||
* @param proto The value of the new prototype or null.
|
||||
*/
|
||||
setPrototypeOf(o: any, proto: any): any;
|
||||
|
||||
/**
|
||||
* Gets the own property descriptor of the specified object.
|
||||
* An own property descriptor is one that is defined directly on the object and is not
|
||||
* inherited from the object's prototype.
|
||||
* @param o Object that contains the property.
|
||||
* @param p Name of the property.
|
||||
*/
|
||||
getOwnPropertyDescriptor(o: any, propertyKey: PropertyKey): PropertyDescriptor;
|
||||
|
||||
/**
|
||||
* Adds a property to an object, or modifies attributes of an existing property.
|
||||
* @param o Object on which to add or modify the property. This can be a native JavaScript
|
||||
* object (that is, a user-defined object or a built in object) or a DOM object.
|
||||
* @param p The property name.
|
||||
* @param attributes Descriptor for the property. It can be for a data property or an accessor
|
||||
* property.
|
||||
*/
|
||||
defineProperty(o: any, propertyKey: PropertyKey, attributes: PropertyDescriptor): any;
|
||||
}
|
||||
|
||||
interface RegExp {
|
||||
/**
|
||||
* Returns a string indicating the flags of the regular expression in question. This field is read-only.
|
||||
* The characters in this string are sequenced and concatenated in the following order:
|
||||
*
|
||||
* - "g" for global
|
||||
* - "i" for ignoreCase
|
||||
* - "m" for multiline
|
||||
* - "u" for unicode
|
||||
* - "y" for sticky
|
||||
*
|
||||
* If no flags are set, the value is the empty string.
|
||||
*/
|
||||
readonly flags: string;
|
||||
|
||||
/**
|
||||
* Returns a Boolean value indicating the state of the sticky flag (y) used with a regular
|
||||
* expression. Default is false. Read-only.
|
||||
*/
|
||||
readonly sticky: boolean;
|
||||
|
||||
/**
|
||||
* Returns a Boolean value indicating the state of the Unicode flag (u) used with a regular
|
||||
* expression. Default is false. Read-only.
|
||||
*/
|
||||
readonly unicode: boolean;
|
||||
}
|
||||
|
||||
interface RegExpConstructor {
|
||||
new (pattern: RegExp, flags?: string): RegExp;
|
||||
(pattern: RegExp, flags?: string): RegExp;
|
||||
}
|
||||
|
||||
interface String {
|
||||
/**
|
||||
* Returns a nonnegative integer Number less than 1114112 (0x110000) that is the code point
|
||||
* value of the UTF-16 encoded code point starting at the string element at position pos in
|
||||
* the String resulting from converting this object to a String.
|
||||
* If there is no element at that position, the result is undefined.
|
||||
* If a valid UTF-16 surrogate pair does not begin at pos, the result is the code unit at pos.
|
||||
*/
|
||||
codePointAt(pos: number): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns true if searchString appears as a substring of the result of converting this
|
||||
* object to a String, at one or more positions that are
|
||||
* greater than or equal to position; otherwise, returns false.
|
||||
* @param searchString search string
|
||||
* @param position If position is undefined, 0 is assumed, so as to search all of the String.
|
||||
*/
|
||||
includes(searchString: string, position?: number): boolean;
|
||||
|
||||
/**
|
||||
* Returns true if the sequence of elements of searchString converted to a String is the
|
||||
* same as the corresponding elements of this object (converted to a String) starting at
|
||||
* endPosition – length(this). Otherwise returns false.
|
||||
*/
|
||||
endsWith(searchString: string, endPosition?: number): boolean;
|
||||
|
||||
/**
|
||||
* Returns the String value result of normalizing the string into the normalization form
|
||||
* named by form as specified in Unicode Standard Annex #15, Unicode Normalization Forms.
|
||||
* @param form Applicable values: "NFC", "NFD", "NFKC", or "NFKD", If not specified default
|
||||
* is "NFC"
|
||||
*/
|
||||
normalize(form: "NFC" | "NFD" | "NFKC" | "NFKD"): string;
|
||||
|
||||
/**
|
||||
* Returns the String value result of normalizing the string into the normalization form
|
||||
* named by form as specified in Unicode Standard Annex #15, Unicode Normalization Forms.
|
||||
* @param form Applicable values: "NFC", "NFD", "NFKC", or "NFKD", If not specified default
|
||||
* is "NFC"
|
||||
*/
|
||||
normalize(form?: string): string;
|
||||
|
||||
/**
|
||||
* Returns a String value that is made from count copies appended together. If count is 0,
|
||||
* T is the empty String is returned.
|
||||
* @param count number of copies to append
|
||||
*/
|
||||
repeat(count: number): string;
|
||||
|
||||
/**
|
||||
* Returns true if the sequence of elements of searchString converted to a String is the
|
||||
* same as the corresponding elements of this object (converted to a String) starting at
|
||||
* position. Otherwise returns false.
|
||||
*/
|
||||
startsWith(searchString: string, position?: number): boolean;
|
||||
|
||||
/**
|
||||
* Returns an <a> HTML anchor element and sets the name attribute to the text value
|
||||
* @param name
|
||||
*/
|
||||
anchor(name: string): string;
|
||||
|
||||
/** Returns a <big> HTML element */
|
||||
big(): string;
|
||||
|
||||
/** Returns a <blink> HTML element */
|
||||
blink(): string;
|
||||
|
||||
/** Returns a <b> HTML element */
|
||||
bold(): string;
|
||||
|
||||
/** Returns a <tt> HTML element */
|
||||
fixed(): string
|
||||
|
||||
/** Returns a <font> HTML element and sets the color attribute value */
|
||||
fontcolor(color: string): string
|
||||
|
||||
/** Returns a <font> HTML element and sets the size attribute value */
|
||||
fontsize(size: number): string;
|
||||
|
||||
/** Returns a <font> HTML element and sets the size attribute value */
|
||||
fontsize(size: string): string;
|
||||
|
||||
/** Returns an <i> HTML element */
|
||||
italics(): string;
|
||||
|
||||
/** Returns an <a> HTML element and sets the href attribute value */
|
||||
link(url: string): string;
|
||||
|
||||
/** Returns a <small> HTML element */
|
||||
small(): string;
|
||||
|
||||
/** Returns a <strike> HTML element */
|
||||
strike(): string;
|
||||
|
||||
/** Returns a <sub> HTML element */
|
||||
sub(): string;
|
||||
|
||||
/** Returns a <sup> HTML element */
|
||||
sup(): string;
|
||||
}
|
||||
|
||||
interface StringConstructor {
|
||||
/**
|
||||
* Return the String value whose elements are, in order, the elements in the List elements.
|
||||
* If length is 0, the empty string is returned.
|
||||
*/
|
||||
fromCodePoint(...codePoints: number[]): string;
|
||||
|
||||
/**
|
||||
* String.raw is intended for use as a tag function of a Tagged Template String. When called
|
||||
* as such the first argument will be a well formed template call site object and the rest
|
||||
* parameter will contain the substitution values.
|
||||
* @param template A well-formed template string call site representation.
|
||||
* @param substitutions A set of substitution values.
|
||||
*/
|
||||
raw(template: TemplateStringsArray, ...substitutions: any[]): string;
|
||||
}
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
/*! *****************************************************************************
|
||||
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
|
||||
|
||||
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.
|
||||
***************************************************************************** */
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
/// <reference path="lib.es2015.core.d.ts" />
|
||||
/// <reference path="lib.es2015.collection.d.ts" />
|
||||
/// <reference path="lib.es2015.generator.d.ts" />
|
||||
/// <reference path="lib.es2015.iterable.d.ts" />
|
||||
/// <reference path="lib.es2015.promise.d.ts" />
|
||||
/// <reference path="lib.es2015.proxy.d.ts" />
|
||||
/// <reference path="lib.es2015.reflect.d.ts" />
|
||||
/// <reference path="lib.es2015.symbol.d.ts" />
|
||||
/// <reference path="lib.es2015.symbol.wellknown.d.ts" />
|
||||
/// <reference path="lib.es5.d.ts" />
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
/*! *****************************************************************************
|
||||
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
|
||||
|
||||
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.
|
||||
***************************************************************************** */
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
interface GeneratorFunction extends Function { }
|
||||
|
||||
interface GeneratorFunctionConstructor {
|
||||
/**
|
||||
* Creates a new Generator function.
|
||||
* @param args A list of arguments the function accepts.
|
||||
*/
|
||||
new (...args: string[]): GeneratorFunction;
|
||||
(...args: string[]): GeneratorFunction;
|
||||
readonly prototype: GeneratorFunction;
|
||||
}
|
||||
declare var GeneratorFunction: GeneratorFunctionConstructor;
|
||||
Vendored
+441
@@ -0,0 +1,441 @@
|
||||
/*! *****************************************************************************
|
||||
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
|
||||
|
||||
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.
|
||||
***************************************************************************** */
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
/// <reference path="lib.es2015.symbol.d.ts" />
|
||||
|
||||
interface SymbolConstructor {
|
||||
/**
|
||||
* A method that returns the default iterator for an object. Called by the semantics of the
|
||||
* for-of statement.
|
||||
*/
|
||||
readonly iterator: symbol;
|
||||
}
|
||||
|
||||
interface IteratorResult<T> {
|
||||
done: boolean;
|
||||
value: T;
|
||||
}
|
||||
|
||||
interface Iterator<T> {
|
||||
next(value?: any): IteratorResult<T>;
|
||||
return?(value?: any): IteratorResult<T>;
|
||||
throw?(e?: any): IteratorResult<T>;
|
||||
}
|
||||
|
||||
interface Iterable<T> {
|
||||
[Symbol.iterator](): Iterator<T>;
|
||||
}
|
||||
|
||||
interface IterableIterator<T> extends Iterator<T> {
|
||||
[Symbol.iterator](): IterableIterator<T>;
|
||||
}
|
||||
|
||||
interface Array<T> {
|
||||
/** Iterator */
|
||||
[Symbol.iterator](): IterableIterator<T>;
|
||||
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
entries(): IterableIterator<[number, T]>;
|
||||
|
||||
/**
|
||||
* Returns an list of keys in the array
|
||||
*/
|
||||
keys(): IterableIterator<number>;
|
||||
|
||||
/**
|
||||
* Returns an list of values in the array
|
||||
*/
|
||||
values(): IterableIterator<T>;
|
||||
}
|
||||
|
||||
interface ArrayConstructor {
|
||||
/**
|
||||
* Creates an array from an iterable object.
|
||||
* @param iterable An iterable object to convert to an array.
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from<T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): Array<U>;
|
||||
|
||||
/**
|
||||
* Creates an array from an iterable object.
|
||||
* @param iterable An iterable object to convert to an array.
|
||||
*/
|
||||
from<T>(iterable: Iterable<T>): Array<T>;
|
||||
}
|
||||
|
||||
interface IArguments {
|
||||
/** Iterator */
|
||||
[Symbol.iterator](): IterableIterator<any>;
|
||||
}
|
||||
|
||||
interface Map<K, V> {
|
||||
[Symbol.iterator](): IterableIterator<[K,V]>;
|
||||
entries(): IterableIterator<[K, V]>;
|
||||
keys(): IterableIterator<K>;
|
||||
values(): IterableIterator<V>;
|
||||
}
|
||||
|
||||
interface MapConstructor {
|
||||
new <K, V>(iterable: Iterable<[K, V]>): Map<K, V>;
|
||||
}
|
||||
|
||||
interface WeakMap<K, V> { }
|
||||
|
||||
interface WeakMapConstructor {
|
||||
new <K, V>(iterable: Iterable<[K, V]>): WeakMap<K, V>;
|
||||
}
|
||||
|
||||
interface Set<T> {
|
||||
[Symbol.iterator](): IterableIterator<T>;
|
||||
entries(): IterableIterator<[T, T]>;
|
||||
keys(): IterableIterator<T>;
|
||||
values(): IterableIterator<T>;
|
||||
}
|
||||
|
||||
interface SetConstructor {
|
||||
new <T>(iterable: Iterable<T>): Set<T>;
|
||||
}
|
||||
|
||||
interface WeakSet<T> { }
|
||||
|
||||
interface WeakSetConstructor {
|
||||
new <T>(iterable: Iterable<T>): WeakSet<T>;
|
||||
}
|
||||
|
||||
interface Promise<T> { }
|
||||
|
||||
interface PromiseConstructor {
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<TAll>(values: Iterable<TAll | PromiseLike<TAll>>): Promise<TAll[]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved or rejected when any of the provided Promises are resolved
|
||||
* or rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
race<T>(values: Iterable<T | PromiseLike<T>>): Promise<T>;
|
||||
}
|
||||
|
||||
declare namespace Reflect {
|
||||
function enumerate(target: any): IterableIterator<any>;
|
||||
}
|
||||
|
||||
interface String {
|
||||
/** Iterator */
|
||||
[Symbol.iterator](): IterableIterator<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit integer values. The contents are initialized to 0. If the requested
|
||||
* number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int8Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
entries(): IterableIterator<[number, number]>;
|
||||
/**
|
||||
* Returns an list of keys in the array
|
||||
*/
|
||||
keys(): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an list of values in the array
|
||||
*/
|
||||
values(): IterableIterator<number>;
|
||||
}
|
||||
|
||||
interface Int8ArrayConstructor {
|
||||
new (elements: Iterable<number>): Int8Array;
|
||||
|
||||
/**
|
||||
* Creates an array from an array-like or iterable object.
|
||||
* @param arrayLike An array-like or iterable object to convert to an array.
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Int8Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint8Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
entries(): IterableIterator<[number, number]>;
|
||||
/**
|
||||
* Returns an list of keys in the array
|
||||
*/
|
||||
keys(): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an list of values in the array
|
||||
*/
|
||||
values(): IterableIterator<number>;
|
||||
}
|
||||
|
||||
interface Uint8ArrayConstructor {
|
||||
new (elements: Iterable<number>): Uint8Array;
|
||||
|
||||
/**
|
||||
* Creates an array from an array-like or iterable object.
|
||||
* @param arrayLike An array-like or iterable object to convert to an array.
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Uint8Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit unsigned integer (clamped) values. The contents are initialized to 0.
|
||||
* If the requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint8ClampedArray {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
entries(): IterableIterator<[number, number]>;
|
||||
|
||||
/**
|
||||
* Returns an list of keys in the array
|
||||
*/
|
||||
keys(): IterableIterator<number>;
|
||||
|
||||
/**
|
||||
* Returns an list of values in the array
|
||||
*/
|
||||
values(): IterableIterator<number>;
|
||||
}
|
||||
|
||||
interface Uint8ClampedArrayConstructor {
|
||||
new (elements: Iterable<number>): Uint8ClampedArray;
|
||||
|
||||
|
||||
/**
|
||||
* Creates an array from an array-like or iterable object.
|
||||
* @param arrayLike An array-like or iterable object to convert to an array.
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Uint8ClampedArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 16-bit signed integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int16Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
entries(): IterableIterator<[number, number]>;
|
||||
|
||||
/**
|
||||
* Returns an list of keys in the array
|
||||
*/
|
||||
keys(): IterableIterator<number>;
|
||||
|
||||
/**
|
||||
* Returns an list of values in the array
|
||||
*/
|
||||
values(): IterableIterator<number>;
|
||||
}
|
||||
|
||||
interface Int16ArrayConstructor {
|
||||
new (elements: Iterable<number>): Int16Array;
|
||||
|
||||
/**
|
||||
* Creates an array from an array-like or iterable object.
|
||||
* @param arrayLike An array-like or iterable object to convert to an array.
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Int16Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 16-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint16Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
entries(): IterableIterator<[number, number]>;
|
||||
/**
|
||||
* Returns an list of keys in the array
|
||||
*/
|
||||
keys(): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an list of values in the array
|
||||
*/
|
||||
values(): IterableIterator<number>;
|
||||
}
|
||||
|
||||
interface Uint16ArrayConstructor {
|
||||
new (elements: Iterable<number>): Uint16Array;
|
||||
|
||||
/**
|
||||
* Creates an array from an array-like or iterable object.
|
||||
* @param arrayLike An array-like or iterable object to convert to an array.
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Uint16Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit signed integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int32Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
entries(): IterableIterator<[number, number]>;
|
||||
/**
|
||||
* Returns an list of keys in the array
|
||||
*/
|
||||
keys(): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an list of values in the array
|
||||
*/
|
||||
values(): IterableIterator<number>;
|
||||
}
|
||||
|
||||
interface Int32ArrayConstructor {
|
||||
new (elements: Iterable<number>): Int32Array;
|
||||
|
||||
/**
|
||||
* Creates an array from an array-like or iterable object.
|
||||
* @param arrayLike An array-like or iterable object to convert to an array.
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Int32Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint32Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
entries(): IterableIterator<[number, number]>;
|
||||
/**
|
||||
* Returns an list of keys in the array
|
||||
*/
|
||||
keys(): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an list of values in the array
|
||||
*/
|
||||
values(): IterableIterator<number>;
|
||||
}
|
||||
|
||||
interface Uint32ArrayConstructor {
|
||||
new (elements: Iterable<number>): Uint32Array;
|
||||
|
||||
/**
|
||||
* Creates an array from an array-like or iterable object.
|
||||
* @param arrayLike An array-like or iterable object to convert to an array.
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Uint32Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit float values. The contents are initialized to 0. If the requested number
|
||||
* of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Float32Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
entries(): IterableIterator<[number, number]>;
|
||||
/**
|
||||
* Returns an list of keys in the array
|
||||
*/
|
||||
keys(): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an list of values in the array
|
||||
*/
|
||||
values(): IterableIterator<number>;
|
||||
}
|
||||
|
||||
interface Float32ArrayConstructor {
|
||||
new (elements: Iterable<number>): Float32Array;
|
||||
|
||||
/**
|
||||
* Creates an array from an array-like or iterable object.
|
||||
* @param arrayLike An array-like or iterable object to convert to an array.
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Float32Array;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 64-bit float values. The contents are initialized to 0. If the requested
|
||||
* number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Float64Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
entries(): IterableIterator<[number, number]>;
|
||||
/**
|
||||
* Returns an list of keys in the array
|
||||
*/
|
||||
keys(): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an list of values in the array
|
||||
*/
|
||||
values(): IterableIterator<number>;
|
||||
}
|
||||
|
||||
interface Float64ArrayConstructor {
|
||||
new (elements: Iterable<number>): Float64Array;
|
||||
|
||||
/**
|
||||
* Creates an array from an array-like or iterable object.
|
||||
* @param arrayLike An array-like or iterable object to convert to an array.
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Float64Array;
|
||||
}
|
||||
Vendored
+187
@@ -0,0 +1,187 @@
|
||||
/*! *****************************************************************************
|
||||
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
|
||||
|
||||
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.
|
||||
***************************************************************************** */
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
/**
|
||||
* Represents the completion of an asynchronous operation
|
||||
*/
|
||||
interface Promise<T> {
|
||||
/**
|
||||
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
||||
* @param onfulfilled The callback to execute when the Promise is resolved.
|
||||
* @param onrejected The callback to execute when the Promise is rejected.
|
||||
* @returns A Promise for the completion of which ever callback is executed.
|
||||
*/
|
||||
then<TResult1, TResult2>(onfulfilled: (value: T) => TResult1 | PromiseLike<TResult1>, onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>): Promise<TResult1 | TResult2>;
|
||||
|
||||
/**
|
||||
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
||||
* @param onfulfilled The callback to execute when the Promise is resolved.
|
||||
* @param onrejected The callback to execute when the Promise is rejected.
|
||||
* @returns A Promise for the completion of which ever callback is executed.
|
||||
*/
|
||||
then<TResult>(onfulfilled: (value: T) => TResult | PromiseLike<TResult>, onrejected: (reason: any) => TResult | PromiseLike<TResult>): Promise<TResult>;
|
||||
|
||||
/**
|
||||
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
||||
* @param onfulfilled The callback to execute when the Promise is resolved.
|
||||
* @returns A Promise for the completion of which ever callback is executed.
|
||||
*/
|
||||
then<TResult>(onfulfilled: (value: T) => TResult | PromiseLike<TResult>): Promise<TResult>;
|
||||
|
||||
/**
|
||||
* Creates a new Promise with the same internal state of this Promise.
|
||||
* @returns A Promise.
|
||||
*/
|
||||
then(): Promise<T>;
|
||||
|
||||
/**
|
||||
* Attaches a callback for only the rejection of the Promise.
|
||||
* @param onrejected The callback to execute when the Promise is rejected.
|
||||
* @returns A Promise for the completion of the callback.
|
||||
*/
|
||||
catch<TResult>(onrejected: (reason: any) => TResult | PromiseLike<TResult>): Promise<T | TResult>;
|
||||
|
||||
/**
|
||||
* Attaches a callback for only the rejection of the Promise.
|
||||
* @param onrejected The callback to execute when the Promise is rejected.
|
||||
* @returns A Promise for the completion of the callback.
|
||||
*/
|
||||
catch(onrejected: (reason: any) => T | PromiseLike<T>): Promise<T>;
|
||||
}
|
||||
|
||||
interface PromiseConstructor {
|
||||
/**
|
||||
* A reference to the prototype.
|
||||
*/
|
||||
readonly prototype: Promise<any>;
|
||||
|
||||
/**
|
||||
* Creates a new Promise.
|
||||
* @param executor A callback used to initialize the promise. This callback is passed two arguments:
|
||||
* a resolve callback used resolve the promise with a value or the result of another promise,
|
||||
* and a reject callback used to reject the promise with a provided reason or error.
|
||||
*/
|
||||
new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>, T10 | PromiseLike<T10>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2, T3, T4, T5, T6, T7, T8, T9>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2, T3, T4, T5, T6, T7, T8>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2, T3, T4, T5, T6, T7>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>]): Promise<[T1, T2, T3, T4, T5, T6, T7]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2, T3, T4, T5, T6>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>]): Promise<[T1, T2, T3, T4, T5, T6]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2, T3, T4, T5>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>]): Promise<[T1, T2, T3, T4, T5]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2, T3, T4>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>]): Promise<[T1, T2, T3, T4]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2, T3>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>]): Promise<[T1, T2, T3]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<[T1, T2]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T>(values: (T | PromiseLike<T>)[]): Promise<T[]>;
|
||||
|
||||
/**
|
||||
* Creates a new rejected promise for the provided reason.
|
||||
* @param reason The reason the promise was rejected.
|
||||
* @returns A new rejected Promise.
|
||||
*/
|
||||
reject(reason: any): Promise<never>;
|
||||
|
||||
/**
|
||||
* Creates a new rejected promise for the provided reason.
|
||||
* @param reason The reason the promise was rejected.
|
||||
* @returns A new rejected Promise.
|
||||
*/
|
||||
reject<T>(reason: any): Promise<T>;
|
||||
|
||||
/**
|
||||
* Creates a new resolved promise for the provided value.
|
||||
* @param value A promise.
|
||||
* @returns A promise whose internal state matches the provided promise.
|
||||
*/
|
||||
resolve<T>(value: T | PromiseLike<T>): Promise<T>;
|
||||
|
||||
/**
|
||||
* Creates a new resolved promise .
|
||||
* @returns A resolved promise.
|
||||
*/
|
||||
resolve(): Promise<void>;
|
||||
}
|
||||
|
||||
declare var Promise: PromiseConstructor;
|
||||
Vendored
+38
@@ -0,0 +1,38 @@
|
||||
/*! *****************************************************************************
|
||||
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
|
||||
|
||||
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.
|
||||
***************************************************************************** */
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
interface ProxyHandler<T> {
|
||||
getPrototypeOf? (target: T): any;
|
||||
setPrototypeOf? (target: T, v: any): boolean;
|
||||
isExtensible? (target: T): boolean;
|
||||
preventExtensions? (target: T): boolean;
|
||||
getOwnPropertyDescriptor? (target: T, p: PropertyKey): PropertyDescriptor;
|
||||
has? (target: T, p: PropertyKey): boolean;
|
||||
get? (target: T, p: PropertyKey, receiver: any): any;
|
||||
set? (target: T, p: PropertyKey, value: any, receiver: any): boolean;
|
||||
deleteProperty? (target: T, p: PropertyKey): boolean;
|
||||
defineProperty? (target: T, p: PropertyKey, attributes: PropertyDescriptor): boolean;
|
||||
enumerate? (target: T): PropertyKey[];
|
||||
ownKeys? (target: T): PropertyKey[];
|
||||
apply? (target: T, thisArg: any, argArray?: any): any;
|
||||
construct? (target: T, thisArg: any, argArray?: any): any;
|
||||
}
|
||||
|
||||
interface ProxyConstructor {
|
||||
revocable<T>(target: T, handler: ProxyHandler<T>): { proxy: T; revoke: () => void; };
|
||||
new <T>(target: T, handler: ProxyHandler<T>): T
|
||||
}
|
||||
declare var Proxy: ProxyConstructor;
|
||||
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
/*! *****************************************************************************
|
||||
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
|
||||
|
||||
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.
|
||||
***************************************************************************** */
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
declare namespace Reflect {
|
||||
function apply(target: Function, thisArgument: any, argumentsList: ArrayLike<any>): any;
|
||||
function construct(target: Function, argumentsList: ArrayLike<any>, newTarget?: any): any;
|
||||
function defineProperty(target: any, propertyKey: PropertyKey, attributes: PropertyDescriptor): boolean;
|
||||
function deleteProperty(target: any, propertyKey: PropertyKey): boolean;
|
||||
function get(target: any, propertyKey: PropertyKey, receiver?: any): any;
|
||||
function getOwnPropertyDescriptor(target: any, propertyKey: PropertyKey): PropertyDescriptor;
|
||||
function getPrototypeOf(target: any): any;
|
||||
function has(target: any, propertyKey: string): boolean;
|
||||
function has(target: any, propertyKey: symbol): boolean;
|
||||
function isExtensible(target: any): boolean;
|
||||
function ownKeys(target: any): Array<PropertyKey>;
|
||||
function preventExtensions(target: any): boolean;
|
||||
function set(target: any, propertyKey: PropertyKey, value: any, receiver?: any): boolean;
|
||||
function setPrototypeOf(target: any, proto: any): boolean;
|
||||
}
|
||||
Vendored
+52
@@ -0,0 +1,52 @@
|
||||
/*! *****************************************************************************
|
||||
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
|
||||
|
||||
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.
|
||||
***************************************************************************** */
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
interface Symbol {
|
||||
/** Returns a string representation of an object. */
|
||||
toString(): string;
|
||||
|
||||
/** Returns the primitive value of the specified object. */
|
||||
valueOf(): Object;
|
||||
}
|
||||
|
||||
interface SymbolConstructor {
|
||||
/**
|
||||
* A reference to the prototype.
|
||||
*/
|
||||
readonly prototype: Symbol;
|
||||
|
||||
/**
|
||||
* Returns a new unique Symbol value.
|
||||
* @param description Description of the new Symbol object.
|
||||
*/
|
||||
(description?: string|number): symbol;
|
||||
|
||||
/**
|
||||
* Returns a Symbol object from the global symbol registry matching the given key if found.
|
||||
* Otherwise, returns a new symbol with this key.
|
||||
* @param key key to search for.
|
||||
*/
|
||||
for(key: string): symbol;
|
||||
|
||||
/**
|
||||
* Returns a key from the global symbol registry matching the given Symbol if found.
|
||||
* Otherwise, returns a undefined.
|
||||
* @param sym Symbol to find the key for.
|
||||
*/
|
||||
keyFor(sym: symbol): string | undefined;
|
||||
}
|
||||
|
||||
declare var Symbol: SymbolConstructor;
|
||||
Vendored
+343
@@ -0,0 +1,343 @@
|
||||
/*! *****************************************************************************
|
||||
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
|
||||
|
||||
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.
|
||||
***************************************************************************** */
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
/// <reference path="lib.es2015.symbol.d.ts" />
|
||||
|
||||
interface SymbolConstructor {
|
||||
/**
|
||||
* A method that determines if a constructor object recognizes an object as one of the
|
||||
* constructor’s instances. Called by the semantics of the instanceof operator.
|
||||
*/
|
||||
readonly hasInstance: symbol;
|
||||
|
||||
/**
|
||||
* A Boolean value that if true indicates that an object should flatten to its array elements
|
||||
* by Array.prototype.concat.
|
||||
*/
|
||||
readonly isConcatSpreadable: symbol;
|
||||
|
||||
/**
|
||||
* A regular expression method that matches the regular expression against a string. Called
|
||||
* by the String.prototype.match method.
|
||||
*/
|
||||
readonly match: symbol;
|
||||
|
||||
/**
|
||||
* A regular expression method that replaces matched substrings of a string. Called by the
|
||||
* String.prototype.replace method.
|
||||
*/
|
||||
readonly replace: symbol;
|
||||
|
||||
/**
|
||||
* A regular expression method that returns the index within a string that matches the
|
||||
* regular expression. Called by the String.prototype.search method.
|
||||
*/
|
||||
readonly search: symbol;
|
||||
|
||||
/**
|
||||
* A function valued property that is the constructor function that is used to create
|
||||
* derived objects.
|
||||
*/
|
||||
readonly species: symbol;
|
||||
|
||||
/**
|
||||
* A regular expression method that splits a string at the indices that match the regular
|
||||
* expression. Called by the String.prototype.split method.
|
||||
*/
|
||||
readonly split: symbol;
|
||||
|
||||
/**
|
||||
* A method that converts an object to a corresponding primitive value.
|
||||
* Called by the ToPrimitive abstract operation.
|
||||
*/
|
||||
readonly toPrimitive: symbol;
|
||||
|
||||
/**
|
||||
* A String value that is used in the creation of the default string description of an object.
|
||||
* Called by the built-in method Object.prototype.toString.
|
||||
*/
|
||||
readonly toStringTag: symbol;
|
||||
|
||||
/**
|
||||
* An Object whose own property names are property names that are excluded from the 'with'
|
||||
* environment bindings of the associated objects.
|
||||
*/
|
||||
readonly unscopables: symbol;
|
||||
}
|
||||
|
||||
interface Symbol {
|
||||
readonly [Symbol.toStringTag]: "Symbol";
|
||||
}
|
||||
|
||||
interface Array<T> {
|
||||
/**
|
||||
* Returns an object whose properties have the value 'true'
|
||||
* when they will be absent when used in a 'with' statement.
|
||||
*/
|
||||
[Symbol.unscopables](): {
|
||||
copyWithin: boolean;
|
||||
entries: boolean;
|
||||
fill: boolean;
|
||||
find: boolean;
|
||||
findIndex: boolean;
|
||||
keys: boolean;
|
||||
values: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
interface Date {
|
||||
/**
|
||||
* Converts a Date object to a string.
|
||||
*/
|
||||
[Symbol.toPrimitive](hint: "default"): string;
|
||||
/**
|
||||
* Converts a Date object to a string.
|
||||
*/
|
||||
[Symbol.toPrimitive](hint: "string"): string;
|
||||
/**
|
||||
* Converts a Date object to a number.
|
||||
*/
|
||||
[Symbol.toPrimitive](hint: "number"): number;
|
||||
/**
|
||||
* Converts a Date object to a string or number.
|
||||
*
|
||||
* @param hint The strings "number", "string", or "default" to specify what primitive to return.
|
||||
*
|
||||
* @throws {TypeError} If 'hint' was given something other than "number", "string", or "default".
|
||||
* @returns A number if 'hint' was "number", a string if 'hint' was "string" or "default".
|
||||
*/
|
||||
[Symbol.toPrimitive](hint: string): string | number;
|
||||
}
|
||||
|
||||
interface Map<K, V> {
|
||||
readonly [Symbol.toStringTag]: "Map";
|
||||
}
|
||||
|
||||
interface WeakMap<K, V>{
|
||||
readonly [Symbol.toStringTag]: "WeakMap";
|
||||
}
|
||||
|
||||
interface Set<T> {
|
||||
readonly [Symbol.toStringTag]: "Set";
|
||||
}
|
||||
|
||||
interface WeakSet<T> {
|
||||
readonly [Symbol.toStringTag]: "WeakSet";
|
||||
}
|
||||
|
||||
interface JSON {
|
||||
readonly [Symbol.toStringTag]: "JSON";
|
||||
}
|
||||
|
||||
interface Function {
|
||||
/**
|
||||
* Determines whether the given value inherits from this function if this function was used
|
||||
* as a constructor function.
|
||||
*
|
||||
* A constructor function can control which objects are recognized as its instances by
|
||||
* 'instanceof' by overriding this method.
|
||||
*/
|
||||
[Symbol.hasInstance](value: any): boolean;
|
||||
}
|
||||
|
||||
interface GeneratorFunction extends Function {
|
||||
readonly [Symbol.toStringTag]: "GeneratorFunction";
|
||||
}
|
||||
|
||||
interface Math {
|
||||
readonly [Symbol.toStringTag]: "Math";
|
||||
}
|
||||
|
||||
interface Promise<T> {
|
||||
readonly [Symbol.toStringTag]: "Promise";
|
||||
}
|
||||
|
||||
interface PromiseConstructor {
|
||||
readonly [Symbol.species]: Function;
|
||||
}
|
||||
|
||||
interface RegExp {
|
||||
/**
|
||||
* Matches a string with this regular expression, and returns an array containing the results of
|
||||
* that search.
|
||||
* @param string A string to search within.
|
||||
*/
|
||||
[Symbol.match](string: string): RegExpMatchArray | null;
|
||||
|
||||
/**
|
||||
* Replaces text in a string, using this regular expression.
|
||||
* @param string A String object or string literal whose contents matching against
|
||||
* this regular expression will be replaced
|
||||
* @param replaceValue A String object or string literal containing the text to replace for every
|
||||
* successful match of this regular expression.
|
||||
*/
|
||||
[Symbol.replace](string: string, replaceValue: string): string;
|
||||
|
||||
/**
|
||||
* Replaces text in a string, using this regular expression.
|
||||
* @param string A String object or string literal whose contents matching against
|
||||
* this regular expression will be replaced
|
||||
* @param replacer A function that returns the replacement text.
|
||||
*/
|
||||
[Symbol.replace](string: string, replacer: (substring: string, ...args: any[]) => string): string;
|
||||
|
||||
/**
|
||||
* Finds the position beginning first substring match in a regular expression search
|
||||
* using this regular expression.
|
||||
*
|
||||
* @param string The string to search within.
|
||||
*/
|
||||
[Symbol.search](string: string): number;
|
||||
|
||||
/**
|
||||
* Returns an array of substrings that were delimited by strings in the original input that
|
||||
* match against this regular expression.
|
||||
*
|
||||
* If the regular expression contains capturing parentheses, then each time this
|
||||
* regular expression matches, the results (including any undefined results) of the
|
||||
* capturing parentheses are spliced.
|
||||
*
|
||||
* @param string string value to split
|
||||
* @param limit if not undefined, the output array is truncated so that it contains no more
|
||||
* than 'limit' elements.
|
||||
*/
|
||||
[Symbol.split](string: string, limit?: number): string[];
|
||||
}
|
||||
|
||||
interface RegExpConstructor {
|
||||
[Symbol.species](): RegExpConstructor;
|
||||
}
|
||||
|
||||
interface String {
|
||||
/**
|
||||
* Matches a string an object that supports being matched against, and returns an array containing the results of that search.
|
||||
* @param matcher An object that supports being matched against.
|
||||
*/
|
||||
match(matcher: { [Symbol.match](string: string): RegExpMatchArray | null; }): RegExpMatchArray | null;
|
||||
|
||||
/**
|
||||
* Replaces text in a string, using an object that supports replacement within a string.
|
||||
* @param searchValue A object can search for and replace matches within a string.
|
||||
* @param replaceValue A string containing the text to replace for every successful match of searchValue in this string.
|
||||
*/
|
||||
replace(searchValue: { [Symbol.replace](string: string, replaceValue: string): string; }, replaceValue: string): string;
|
||||
|
||||
/**
|
||||
* Replaces text in a string, using an object that supports replacement within a string.
|
||||
* @param searchValue A object can search for and replace matches within a string.
|
||||
* @param replacer A function that returns the replacement text.
|
||||
*/
|
||||
replace(searchValue: { [Symbol.replace](string: string, replacer: (substring: string, ...args: any[]) => string): string; }, replacer: (substring: string, ...args: any[]) => string): string;
|
||||
|
||||
/**
|
||||
* Finds the first substring match in a regular expression search.
|
||||
* @param searcher An object which supports searching within a string.
|
||||
*/
|
||||
search(searcher: { [Symbol.search](string: string): number; }): number;
|
||||
|
||||
/**
|
||||
* Split a string into substrings using the specified separator and return them as an array.
|
||||
* @param splitter An object that can split a string.
|
||||
* @param limit A value used to limit the number of elements returned in the array.
|
||||
*/
|
||||
split(splitter: { [Symbol.split](string: string, limit?: number): string[]; }, limit?: number): string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a raw buffer of binary data, which is used to store data for the
|
||||
* different typed arrays. ArrayBuffers cannot be read from or written to directly,
|
||||
* but can be passed to a typed array or DataView Object to interpret the raw
|
||||
* buffer as needed.
|
||||
*/
|
||||
interface ArrayBuffer {
|
||||
readonly [Symbol.toStringTag]: "ArrayBuffer";
|
||||
}
|
||||
|
||||
interface DataView {
|
||||
readonly [Symbol.toStringTag]: "DataView";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit integer values. The contents are initialized to 0. If the requested
|
||||
* number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int8Array {
|
||||
readonly [Symbol.toStringTag]: "Int8Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint8Array {
|
||||
readonly [Symbol.toStringTag]: "UInt8Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit unsigned integer (clamped) values. The contents are initialized to 0.
|
||||
* If the requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint8ClampedArray {
|
||||
readonly [Symbol.toStringTag]: "Uint8ClampedArray";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 16-bit signed integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int16Array {
|
||||
readonly [Symbol.toStringTag]: "Int16Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 16-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint16Array {
|
||||
readonly [Symbol.toStringTag]: "Uint16Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit signed integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int32Array {
|
||||
readonly [Symbol.toStringTag]: "Int32Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint32Array {
|
||||
readonly [Symbol.toStringTag]: "Uint32Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit float values. The contents are initialized to 0. If the requested number
|
||||
* of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Float32Array {
|
||||
readonly [Symbol.toStringTag]: "Float32Array";
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 64-bit float values. The contents are initialized to 0. If the requested
|
||||
* number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Float64Array {
|
||||
readonly [Symbol.toStringTag]: "Float64Array";
|
||||
}
|
||||
Vendored
+105
@@ -0,0 +1,105 @@
|
||||
/*! *****************************************************************************
|
||||
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
|
||||
|
||||
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.
|
||||
***************************************************************************** */
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
interface Array<T> {
|
||||
/**
|
||||
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||
* @param searchElement The element to search for.
|
||||
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||
*/
|
||||
includes(searchElement: T, fromIndex?: number): boolean;
|
||||
}
|
||||
|
||||
interface Int8Array {
|
||||
/**
|
||||
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||
* @param searchElement The element to search for.
|
||||
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||
*/
|
||||
includes(searchElement: number, fromIndex?: number): boolean;
|
||||
}
|
||||
|
||||
interface Uint8Array {
|
||||
/**
|
||||
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||
* @param searchElement The element to search for.
|
||||
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||
*/
|
||||
includes(searchElement: number, fromIndex?: number): boolean;
|
||||
}
|
||||
|
||||
interface Uint8ClampedArray {
|
||||
/**
|
||||
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||
* @param searchElement The element to search for.
|
||||
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||
*/
|
||||
includes(searchElement: number, fromIndex?: number): boolean;
|
||||
}
|
||||
|
||||
interface Int16Array {
|
||||
/**
|
||||
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||
* @param searchElement The element to search for.
|
||||
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||
*/
|
||||
includes(searchElement: number, fromIndex?: number): boolean;
|
||||
}
|
||||
|
||||
interface Uint16Array {
|
||||
/**
|
||||
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||
* @param searchElement The element to search for.
|
||||
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||
*/
|
||||
includes(searchElement: number, fromIndex?: number): boolean;
|
||||
}
|
||||
|
||||
interface Int32Array {
|
||||
/**
|
||||
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||
* @param searchElement The element to search for.
|
||||
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||
*/
|
||||
includes(searchElement: number, fromIndex?: number): boolean;
|
||||
}
|
||||
|
||||
interface Uint32Array {
|
||||
/**
|
||||
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||
* @param searchElement The element to search for.
|
||||
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||
*/
|
||||
includes(searchElement: number, fromIndex?: number): boolean;
|
||||
}
|
||||
|
||||
interface Float32Array {
|
||||
/**
|
||||
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||
* @param searchElement The element to search for.
|
||||
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||
*/
|
||||
includes(searchElement: number, fromIndex?: number): boolean;
|
||||
}
|
||||
|
||||
interface Float64Array {
|
||||
/**
|
||||
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||
* @param searchElement The element to search for.
|
||||
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||
*/
|
||||
includes(searchElement: number, fromIndex?: number): boolean;
|
||||
}
|
||||
Vendored
+18
@@ -0,0 +1,18 @@
|
||||
/*! *****************************************************************************
|
||||
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
|
||||
|
||||
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.
|
||||
***************************************************************************** */
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
/// <reference path="lib.es2015.d.ts" />
|
||||
/// <reference path="lib.es2016.array.include.d.ts" />
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
/*! *****************************************************************************
|
||||
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
|
||||
|
||||
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.
|
||||
***************************************************************************** */
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
/// <reference path="lib.es2016.d.ts" />
|
||||
/// <reference path="lib.es2017.object.d.ts" />
|
||||
/// <reference path="lib.es2017.sharedmemory.d.ts" />
|
||||
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
/*! *****************************************************************************
|
||||
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
|
||||
|
||||
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.
|
||||
***************************************************************************** */
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
interface ObjectConstructor {
|
||||
/**
|
||||
* Returns an array of values of the enumerable properties of an object
|
||||
* @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
|
||||
*/
|
||||
values<T>(o: { [s: string]: T }): T[];
|
||||
values(o: any): any[];
|
||||
/**
|
||||
* Returns an array of key/values of the enumerable properties of an object
|
||||
* @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
|
||||
*/
|
||||
entries<T>(o: { [s: string]: T }): [string, T][];
|
||||
entries(o: any): [string, any][];
|
||||
}
|
||||
Vendored
+43
@@ -0,0 +1,43 @@
|
||||
/*! *****************************************************************************
|
||||
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
|
||||
|
||||
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.
|
||||
***************************************************************************** */
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
/// <reference path="lib.es2015.symbol.d.ts" />
|
||||
/// <reference path="lib.es2015.symbol.wellknown.d.ts" />
|
||||
|
||||
interface SharedArrayBuffer {
|
||||
/**
|
||||
* Read-only. The length of the ArrayBuffer (in bytes).
|
||||
*/
|
||||
readonly byteLength: number;
|
||||
|
||||
/*
|
||||
* The SharedArrayBuffer constructor's length property whose value is 1.
|
||||
*/
|
||||
length: number;
|
||||
/**
|
||||
* Returns a section of an SharedArrayBuffer.
|
||||
*/
|
||||
slice(begin:number, end?:number): SharedArrayBuffer;
|
||||
readonly [Symbol.species]: SharedArrayBuffer;
|
||||
readonly [Symbol.toStringTag]: "SharedArrayBuffer";
|
||||
}
|
||||
|
||||
interface SharedArrayBufferConstructor {
|
||||
readonly prototype: SharedArrayBuffer;
|
||||
new (byteLength: number): SharedArrayBuffer;
|
||||
}
|
||||
|
||||
declare var SharedArrayBuffer: SharedArrayBufferConstructor;
|
||||
Vendored
+1050
-830
File diff suppressed because it is too large
Load Diff
Vendored
+7474
-5632
File diff suppressed because it is too large
Load Diff
Vendored
-18829
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -13,7 +13,7 @@ See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
|
||||
/// <reference path="lib.core.d.ts" />
|
||||
/// <reference no-default-lib="true"/>
|
||||
|
||||
|
||||
/////////////////////////////
|
||||
Vendored
+489
-480
File diff suppressed because it is too large
Load Diff
+38742
-35251
File diff suppressed because one or more lines are too long
+53242
-48550
File diff suppressed because one or more lines are too long
Vendored
+8805
File diff suppressed because it is too large
Load Diff
+53023
File diff suppressed because one or more lines are too long
Vendored
+2545
-2331
File diff suppressed because it is too large
Load Diff
+59803
-54770
File diff suppressed because one or more lines are too long
Vendored
+2545
-2331
File diff suppressed because it is too large
Load Diff
+59803
-54770
File diff suppressed because one or more lines are too long
+40
-5
@@ -29,15 +29,48 @@
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jake": "latest",
|
||||
"mocha": "latest",
|
||||
"chai": "latest",
|
||||
"@types/browserify": "latest",
|
||||
"@types/del": "latest",
|
||||
"@types/glob": "latest",
|
||||
"@types/gulp": "latest",
|
||||
"@types/gulp-concat": "latest",
|
||||
"@types/gulp-help": "latest",
|
||||
"@types/gulp-newer": "latest",
|
||||
"@types/gulp-sourcemaps": "latest",
|
||||
"@types/gulp-typescript": "latest",
|
||||
"@types/merge2": "latest",
|
||||
"@types/minimatch": "latest",
|
||||
"@types/minimist": "latest",
|
||||
"@types/mkdirp": "latest",
|
||||
"@types/node": "latest",
|
||||
"@types/q": "latest",
|
||||
"@types/run-sequence": "latest",
|
||||
"@types/through2": "latest",
|
||||
"browserify": "latest",
|
||||
"chai": "latest",
|
||||
"del": "latest",
|
||||
"gulp": "latest",
|
||||
"gulp-clone": "latest",
|
||||
"gulp-concat": "latest",
|
||||
"gulp-help": "latest",
|
||||
"gulp-insert": "latest",
|
||||
"gulp-newer": "latest",
|
||||
"gulp-sourcemaps": "latest",
|
||||
"gulp-typescript": "latest",
|
||||
"into-stream": "latest",
|
||||
"istanbul": "latest",
|
||||
"jake": "latest",
|
||||
"merge2": "latest",
|
||||
"minimist": "latest",
|
||||
"mkdirp": "latest",
|
||||
"mocha": "latest",
|
||||
"mocha-fivemat-progress-reporter": "latest",
|
||||
"run-sequence": "latest",
|
||||
"through2": "latest",
|
||||
"ts-node": "latest",
|
||||
"tsd": "latest",
|
||||
"tslint": "next",
|
||||
"typescript": "next",
|
||||
"tsd": "latest"
|
||||
"typescript": "next"
|
||||
},
|
||||
"scripts": {
|
||||
"pretest": "jake tests",
|
||||
@@ -45,7 +78,9 @@
|
||||
"build": "npm run build:compiler && npm run build:tests",
|
||||
"build:compiler": "jake local",
|
||||
"build:tests": "jake tests",
|
||||
"start": "node lib/tsc",
|
||||
"clean": "jake clean",
|
||||
"gulp": "gulp",
|
||||
"jake": "jake",
|
||||
"lint": "jake lint",
|
||||
"setup-hooks": "node scripts/link-hooks.js"
|
||||
|
||||
@@ -67,7 +67,7 @@ function getNightlyVersionString(versionString: string): string {
|
||||
const now = new Date();
|
||||
const timeStr = now.toISOString().replace(/:|T|\.|-/g, "").slice(0, 8);
|
||||
|
||||
return `${versionString}-dev.${timeStr}`;
|
||||
return `${versionString}-dev.${timeStr}-1.0`;
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Base = require('mocha').reporters.Base;
|
||||
|
||||
/**
|
||||
* Expose `None`.
|
||||
*/
|
||||
|
||||
exports = module.exports = None;
|
||||
|
||||
/**
|
||||
* Initialize a new `None` test reporter.
|
||||
*
|
||||
* @api public
|
||||
* @param {Runner} runner
|
||||
*/
|
||||
function None(runner) {
|
||||
Base.call(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `Base.prototype`.
|
||||
*/
|
||||
None.prototype.__proto__ = Base.prototype;
|
||||
@@ -0,0 +1,366 @@
|
||||
var tty = require("tty")
|
||||
, readline = require("readline")
|
||||
, fs = require("fs")
|
||||
, path = require("path")
|
||||
, child_process = require("child_process")
|
||||
, os = require("os")
|
||||
, mocha = require("mocha")
|
||||
, Base = mocha.reporters.Base
|
||||
, color = Base.color
|
||||
, cursor = Base.cursor
|
||||
, ms = require("mocha/lib/ms");
|
||||
|
||||
var isatty = tty.isatty(1) && tty.isatty(2);
|
||||
var tapRangePattern = /^(\d+)\.\.(\d+)(?:$|\r\n?|\n)/;
|
||||
var tapTestPattern = /^(not\sok|ok)\s+(\d+)\s+(?:-\s+)?(.*)$/;
|
||||
var tapCommentPattern = /^#(?: (tests|pass|fail) (\d+)$)?/;
|
||||
|
||||
exports.runTestsInParallel = runTestsInParallel;
|
||||
exports.ProgressBars = ProgressBars;
|
||||
|
||||
function runTestsInParallel(taskConfigsFolder, run, options, cb) {
|
||||
if (options === undefined) options = { };
|
||||
|
||||
return discoverTests(run, options, function (error) {
|
||||
if (error) {
|
||||
return cb(error);
|
||||
}
|
||||
|
||||
return runTests(taskConfigsFolder, run, options, cb);
|
||||
});
|
||||
}
|
||||
|
||||
function discoverTests(run, options, cb) {
|
||||
console.log("Discovering tests...");
|
||||
|
||||
var cmd = "mocha -R " + require.resolve("./mocha-none-reporter.js") + " " + run;
|
||||
var p = spawnProcess(cmd);
|
||||
p.on("exit", function (status) {
|
||||
if (status) {
|
||||
cb(new Error("Process exited with code " + status));
|
||||
}
|
||||
else {
|
||||
cb();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function runTests(taskConfigsFolder, run, options, cb) {
|
||||
var configFiles = fs.readdirSync(taskConfigsFolder);
|
||||
var numPartitions = configFiles.length;
|
||||
if (numPartitions <= 0) {
|
||||
cb();
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Running tests on " + numPartitions + " threads...");
|
||||
|
||||
var partitions = Array(numPartitions);
|
||||
var progressBars = new ProgressBars();
|
||||
progressBars.enable();
|
||||
|
||||
var counter = numPartitions;
|
||||
configFiles.forEach(runTestsInPartition);
|
||||
|
||||
function runTestsInPartition(file, index) {
|
||||
var partition = {
|
||||
file: path.join(taskConfigsFolder, file),
|
||||
tests: 0,
|
||||
passed: 0,
|
||||
failed: 0,
|
||||
completed: 0,
|
||||
current: undefined,
|
||||
start: undefined,
|
||||
end: undefined,
|
||||
failures: []
|
||||
};
|
||||
partitions[index] = partition;
|
||||
|
||||
// Set up the progress bar.
|
||||
updateProgress(0);
|
||||
|
||||
// Start the background process.
|
||||
var cmd = "mocha -t " + (options.testTimeout || 20000) + " -R tap --no-colors " + run + " --config='" + partition.file + "'";
|
||||
var p = spawnProcess(cmd);
|
||||
var rl = readline.createInterface({
|
||||
input: p.stdout,
|
||||
terminal: false
|
||||
});
|
||||
rl.on("line", onmessage);
|
||||
p.on("exit", onexit)
|
||||
|
||||
function onmessage(line) {
|
||||
if (partition.start === undefined) {
|
||||
partition.start = Date.now();
|
||||
}
|
||||
|
||||
var rangeMatch = tapRangePattern.exec(line);
|
||||
if (rangeMatch) {
|
||||
partition.tests = parseInt(rangeMatch[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
var testMatch = tapTestPattern.exec(line);
|
||||
if (testMatch) {
|
||||
var test = {
|
||||
result: testMatch[1],
|
||||
id: parseInt(testMatch[2]),
|
||||
name: testMatch[3],
|
||||
output: []
|
||||
};
|
||||
|
||||
partition.current = test;
|
||||
partition.completed++;
|
||||
|
||||
if (test.result === "ok") {
|
||||
partition.passed++;
|
||||
}
|
||||
else {
|
||||
partition.failed++;
|
||||
partition.failures.push(test);
|
||||
}
|
||||
|
||||
var progress = partition.completed / partition.tests;
|
||||
if (progress < 1) {
|
||||
updateProgress(progress);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var commentMatch = tapCommentPattern.exec(line);
|
||||
if (commentMatch) {
|
||||
switch (commentMatch[1]) {
|
||||
case "tests":
|
||||
partition.current = undefined;
|
||||
partition.tests = parseInt(commentMatch[2]);
|
||||
break;
|
||||
|
||||
case "pass":
|
||||
partition.passed = parseInt(commentMatch[2]);
|
||||
break;
|
||||
|
||||
case "fail":
|
||||
partition.failed = parseInt(commentMatch[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (partition.current) {
|
||||
partition.current.output.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
function onexit() {
|
||||
if (partition.end === undefined) {
|
||||
partition.end = Date.now();
|
||||
}
|
||||
|
||||
partition.duration = partition.end - partition.start;
|
||||
var summaryColor = partition.failed ? "fail" : "green";
|
||||
var summarySymbol = partition.failed ? Base.symbols.err : Base.symbols.ok;
|
||||
var summaryTests = (partition.passed === partition.tests ? partition.passed : partition.passed + "/" + partition.tests) + " passing";
|
||||
var summaryDuration = "(" + ms(partition.duration) + ")";
|
||||
var savedUseColors = Base.useColors;
|
||||
Base.useColors = !options.noColors;
|
||||
|
||||
var summary = color(summaryColor, summarySymbol + " " + summaryTests) + " " + color("light", summaryDuration);
|
||||
Base.useColors = savedUseColors;
|
||||
|
||||
updateProgress(1, summary);
|
||||
|
||||
signal();
|
||||
}
|
||||
|
||||
function updateProgress(percentComplete, title) {
|
||||
var progressColor = "pending";
|
||||
if (partition.failed) {
|
||||
progressColor = "fail";
|
||||
}
|
||||
|
||||
progressBars.update(
|
||||
index,
|
||||
percentComplete,
|
||||
progressColor,
|
||||
title
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function signal() {
|
||||
counter--;
|
||||
|
||||
if (counter <= 0) {
|
||||
var reporter = new Base(),
|
||||
stats = reporter.stats,
|
||||
failures = reporter.failures;
|
||||
|
||||
var duration = 0;
|
||||
for (var i = 0; i < numPartitions; i++) {
|
||||
var partition = partitions[i];
|
||||
stats.passes += partition.passed;
|
||||
stats.failures += partition.failed;
|
||||
stats.tests += partition.tests;
|
||||
duration += partition.duration;
|
||||
for (var j = 0; j < partition.failures.length; j++) {
|
||||
var failure = partition.failures[j];
|
||||
failures.push(makeMochaTest(failure));
|
||||
}
|
||||
}
|
||||
|
||||
stats.duration = duration;
|
||||
progressBars.disable();
|
||||
|
||||
if (options.noColors) {
|
||||
var savedUseColors = Base.useColors;
|
||||
Base.useColors = false;
|
||||
reporter.epilogue();
|
||||
Base.useColors = savedUseColors;
|
||||
}
|
||||
else {
|
||||
reporter.epilogue();
|
||||
}
|
||||
|
||||
if (stats.failures) {
|
||||
return cb(new Error("Test failures reported: " + stats.failures));
|
||||
}
|
||||
else {
|
||||
return cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function makeMochaTest(test) {
|
||||
return {
|
||||
fullTitle: function() {
|
||||
return test.name;
|
||||
},
|
||||
err: {
|
||||
message: test.output[0],
|
||||
stack: test.output.join(os.EOL)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var nodeModulesPathPrefix = path.resolve("./node_modules/.bin/") + path.delimiter;
|
||||
if (process.env.path !== undefined) {
|
||||
process.env.path = nodeModulesPathPrefix + process.env.path;
|
||||
} else if (process.env.PATH !== undefined) {
|
||||
process.env.PATH = nodeModulesPathPrefix + process.env.PATH;
|
||||
}
|
||||
|
||||
function spawnProcess(cmd, options) {
|
||||
var shell = process.platform === "win32" ? "cmd" : "/bin/sh";
|
||||
var prefix = process.platform === "win32" ? "/c" : "-c";
|
||||
return child_process.spawn(shell, [prefix, cmd], { windowsVerbatimArguments: true });
|
||||
}
|
||||
|
||||
function ProgressBars(options) {
|
||||
if (!options) options = {};
|
||||
var open = options.open || '[';
|
||||
var close = options.close || ']';
|
||||
var complete = options.complete || '▬';
|
||||
var incomplete = options.incomplete || Base.symbols.dot;
|
||||
var maxWidth = Math.floor(Base.window.width * .30) - open.length - close.length - 2;
|
||||
var width = minMax(options.width || maxWidth, 10, maxWidth);
|
||||
this._options = {
|
||||
open: open,
|
||||
complete: complete,
|
||||
incomplete: incomplete,
|
||||
close: close,
|
||||
width: width
|
||||
};
|
||||
|
||||
this._progressBars = [];
|
||||
this._lineCount = 0;
|
||||
this._enabled = false;
|
||||
}
|
||||
ProgressBars.prototype = {
|
||||
enable: function () {
|
||||
if (!this._enabled) {
|
||||
process.stdout.write(os.EOL);
|
||||
this._enabled = true;
|
||||
}
|
||||
},
|
||||
disable: function () {
|
||||
if (this._enabled) {
|
||||
process.stdout.write(os.EOL);
|
||||
this._enabled = false;
|
||||
}
|
||||
},
|
||||
update: function (index, percentComplete, color, title) {
|
||||
percentComplete = minMax(percentComplete, 0, 1);
|
||||
|
||||
var progressBar = this._progressBars[index] || (this._progressBars[index] = { });
|
||||
var width = this._options.width;
|
||||
var n = Math.floor(width * percentComplete);
|
||||
var i = width - n;
|
||||
if (n === progressBar.lastN && title === progressBar.title && color === progressBar.progressColor) {
|
||||
return;
|
||||
}
|
||||
|
||||
progressBar.lastN = n;
|
||||
progressBar.title = title;
|
||||
progressBar.progressColor = color;
|
||||
|
||||
var progress = " ";
|
||||
progress += this._color('progress', this._options.open);
|
||||
progress += this._color(color, fill(this._options.complete, n));
|
||||
progress += this._color('progress', fill(this._options.incomplete, i));
|
||||
progress += this._color('progress', this._options.close);
|
||||
|
||||
if (title) {
|
||||
progress += this._color('progress', ' ' + title);
|
||||
}
|
||||
|
||||
if (progressBar.text !== progress) {
|
||||
progressBar.text = progress;
|
||||
this._render(index);
|
||||
}
|
||||
},
|
||||
_render: function (index) {
|
||||
if (!this._enabled || !isatty) {
|
||||
return;
|
||||
}
|
||||
|
||||
cursor.hide();
|
||||
readline.moveCursor(process.stdout, -process.stdout.columns, -this._lineCount);
|
||||
var lineCount = 0;
|
||||
var numProgressBars = this._progressBars.length;
|
||||
for (var i = 0; i < numProgressBars; i++) {
|
||||
if (i === index) {
|
||||
readline.clearLine(process.stdout, 1);
|
||||
process.stdout.write(this._progressBars[i].text + os.EOL);
|
||||
}
|
||||
else {
|
||||
readline.moveCursor(process.stdout, -process.stdout.columns, +1);
|
||||
}
|
||||
|
||||
lineCount++;
|
||||
}
|
||||
|
||||
this._lineCount = lineCount;
|
||||
cursor.show();
|
||||
},
|
||||
_color: function (type, text) {
|
||||
return type && !this._options.noColors ? color(type, text) : text;
|
||||
}
|
||||
};
|
||||
|
||||
function fill(ch, size) {
|
||||
var s = "";
|
||||
while (s.length < size) {
|
||||
s += ch;
|
||||
}
|
||||
|
||||
return s.length > size ? s.substr(0, size) : s;
|
||||
}
|
||||
|
||||
function minMax(value, min, max) {
|
||||
if (value < min) return min;
|
||||
if (value > max) return max;
|
||||
return value;
|
||||
}
|
||||
@@ -18,7 +18,7 @@ class BooleanTriviaWalker extends Lint.RuleWalker {
|
||||
|
||||
visitCallExpression(node: ts.CallExpression) {
|
||||
super.visitCallExpression(node);
|
||||
if (node.arguments) {
|
||||
if (node.arguments && node.arguments.some(arg => arg.kind === ts.SyntaxKind.TrueKeyword || arg.kind === ts.SyntaxKind.FalseKeyword)) {
|
||||
const targetCallSignature = this.checker.getResolvedSignature(node);
|
||||
if (!!targetCallSignature) {
|
||||
const targetParameters = targetCallSignature.getParameters();
|
||||
|
||||
@@ -28,8 +28,15 @@ class IncrementDecrementWalker extends Lint.RuleWalker {
|
||||
}
|
||||
|
||||
visitIncrementDecrement(node: ts.UnaryExpression) {
|
||||
if (node.parent && (node.parent.kind === ts.SyntaxKind.ExpressionStatement ||
|
||||
node.parent.kind === ts.SyntaxKind.ForStatement)) {
|
||||
if (node.parent && (
|
||||
// Can be a statement
|
||||
node.parent.kind === ts.SyntaxKind.ExpressionStatement ||
|
||||
// Can be directly in a for-statement
|
||||
node.parent.kind === ts.SyntaxKind.ForStatement ||
|
||||
// Can be in a comma operator in a for statement (`for (let a = 0, b = 10; a < b; a++, b--)`)
|
||||
node.parent.kind === ts.SyntaxKind.BinaryExpression &&
|
||||
(<ts.BinaryExpression>node.parent).operatorToken.kind === ts.SyntaxKind.CommaToken &&
|
||||
node.parent.parent.kind === ts.SyntaxKind.ForStatement)) {
|
||||
return;
|
||||
}
|
||||
this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.POSTFIX_FAILURE_STRING));
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import * as Lint from "tslint/lib/lint";
|
||||
import * as ts from "typescript";
|
||||
|
||||
|
||||
export class Rule extends Lint.Rules.AbstractRule {
|
||||
public static FAILURE_STRING = "Don't use the 'null' keyword - use 'undefined' for missing values instead";
|
||||
|
||||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
||||
return this.applyWithWalker(new NullWalker(sourceFile, this.getOptions()));
|
||||
}
|
||||
}
|
||||
|
||||
class NullWalker extends Lint.RuleWalker {
|
||||
visitNode(node: ts.Node) {
|
||||
super.visitNode(node);
|
||||
if (node.kind === ts.SyntaxKind.NullKeyword) {
|
||||
this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import * as Lint from "tslint/lib/lint";
|
||||
import * as ts from "typescript";
|
||||
|
||||
|
||||
export class Rule extends Lint.Rules.AbstractRule {
|
||||
public static LEADING_FAILURE_STRING = "No leading whitespace found on single-line object literal.";
|
||||
public static TRAILING_FAILURE_STRING = "No trailing whitespace found on single-line object literal.";
|
||||
public static LEADING_EXCESS_FAILURE_STRING = "Excess leading whitespace found on single-line object literal.";
|
||||
public static TRAILING_EXCESS_FAILURE_STRING = "Excess trailing whitespace found on single-line object literal.";
|
||||
|
||||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
||||
return this.applyWithWalker(new ObjectLiteralSpaceWalker(sourceFile, this.getOptions()));
|
||||
}
|
||||
}
|
||||
|
||||
class ObjectLiteralSpaceWalker extends Lint.RuleWalker {
|
||||
public visitNode(node: ts.Node) {
|
||||
if (node.kind === ts.SyntaxKind.ObjectLiteralExpression) {
|
||||
const literal = node as ts.ObjectLiteralExpression;
|
||||
const text = literal.getText();
|
||||
if (text.match(/^{[^\n]+}$/g)) {
|
||||
if (text.charAt(1) !== " ") {
|
||||
const failure = this.createFailure(node.pos, node.getWidth(), Rule.LEADING_FAILURE_STRING);
|
||||
this.addFailure(failure);
|
||||
}
|
||||
if (text.charAt(2) === " ") {
|
||||
const failure = this.createFailure(node.pos + 2, 1, Rule.LEADING_EXCESS_FAILURE_STRING);
|
||||
this.addFailure(failure);
|
||||
}
|
||||
if (text.charAt(text.length - 2) !== " ") {
|
||||
const failure = this.createFailure(node.pos, node.getWidth(), Rule.TRAILING_FAILURE_STRING);
|
||||
this.addFailure(failure);
|
||||
}
|
||||
if (text.charAt(text.length - 3) === " ") {
|
||||
const failure = this.createFailure(node.pos + node.getWidth() - 3, 1, Rule.TRAILING_EXCESS_FAILURE_STRING);
|
||||
this.addFailure(failure);
|
||||
}
|
||||
}
|
||||
}
|
||||
super.visitNode(node);
|
||||
}
|
||||
}
|
||||
Vendored
+22
@@ -0,0 +1,22 @@
|
||||
declare module "gulp-clone" {
|
||||
function Clone(): NodeJS.ReadWriteStream;
|
||||
namespace Clone {
|
||||
export function sink() : NodeJS.ReadWriteStream & {tap: () => NodeJS.ReadWriteStream};
|
||||
}
|
||||
export = Clone;
|
||||
}
|
||||
|
||||
declare module "gulp-insert" {
|
||||
export function append(text: string | Buffer): NodeJS.ReadWriteStream;
|
||||
export function prepend(text: string | Buffer): NodeJS.ReadWriteStream;
|
||||
export function wrap(text: string | Buffer, tail: string | Buffer): NodeJS.ReadWriteStream;
|
||||
export function transform(cb: (contents: string, file: {path: string}) => string): NodeJS.ReadWriteStream; // file is a vinyl file
|
||||
}
|
||||
|
||||
declare module "into-stream" {
|
||||
function IntoStream(content: string | Buffer | (string | Buffer)[]): NodeJS.ReadableStream;
|
||||
namespace IntoStream {
|
||||
export function obj(content: any): NodeJS.ReadableStream
|
||||
}
|
||||
export = IntoStream;
|
||||
}
|
||||
+888
-457
File diff suppressed because it is too large
Load Diff
+2275
-1204
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace ts {
|
||||
/* @internal */
|
||||
export let optionDeclarations: CommandLineOption[] = [
|
||||
export const optionDeclarations: CommandLineOption[] = [
|
||||
{
|
||||
name: "charset",
|
||||
type: "string",
|
||||
@@ -37,6 +37,11 @@ namespace ts {
|
||||
type: "boolean",
|
||||
description: Diagnostics.Print_this_message,
|
||||
},
|
||||
{
|
||||
name: "help",
|
||||
shortName: "?",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "init",
|
||||
type: "boolean",
|
||||
@@ -127,6 +132,16 @@ namespace ts {
|
||||
type: "boolean",
|
||||
description: Diagnostics.Raise_error_on_this_expressions_with_an_implied_any_type,
|
||||
},
|
||||
{
|
||||
name: "noUnusedLocals",
|
||||
type: "boolean",
|
||||
description: Diagnostics.Report_Errors_on_Unused_Locals,
|
||||
},
|
||||
{
|
||||
name: "noUnusedParameters",
|
||||
type: "boolean",
|
||||
description: Diagnostics.Report_Errors_on_Unused_Parameters
|
||||
},
|
||||
{
|
||||
name: "noLib",
|
||||
type: "boolean",
|
||||
@@ -139,11 +154,16 @@ namespace ts {
|
||||
name: "skipDefaultLibCheck",
|
||||
type: "boolean",
|
||||
},
|
||||
{
|
||||
name: "skipLibCheck",
|
||||
type: "boolean",
|
||||
description: Diagnostics.Skip_type_checking_of_declaration_files,
|
||||
},
|
||||
{
|
||||
name: "out",
|
||||
type: "string",
|
||||
isFilePath: false, // This is intentionally broken to support compatability with existing tsconfig files
|
||||
// for correct behaviour, please use outFile
|
||||
// for correct behaviour, please use outFile
|
||||
paramType: Diagnostics.FILE,
|
||||
},
|
||||
{
|
||||
@@ -327,8 +347,13 @@ namespace ts {
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "typesRoot",
|
||||
type: "string"
|
||||
name: "typeRoots",
|
||||
type: "list",
|
||||
element: {
|
||||
name: "typeRoots",
|
||||
type: "string",
|
||||
isFilePath: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "types",
|
||||
@@ -375,6 +400,7 @@ namespace ts {
|
||||
"es2015": "lib.es2015.d.ts",
|
||||
"es7": "lib.es2016.d.ts",
|
||||
"es2016": "lib.es2016.d.ts",
|
||||
"es2017": "lib.es2017.d.ts",
|
||||
// Host only
|
||||
"dom": "lib.dom.d.ts",
|
||||
"webworker": "lib.webworker.d.ts",
|
||||
@@ -389,11 +415,17 @@ namespace ts {
|
||||
"es2015.reflect": "lib.es2015.reflect.d.ts",
|
||||
"es2015.symbol": "lib.es2015.symbol.d.ts",
|
||||
"es2015.symbol.wellknown": "lib.es2015.symbol.wellknown.d.ts",
|
||||
"es2016.array.include": "lib.es2016.array.include.d.ts"
|
||||
"es2016.array.include": "lib.es2016.array.include.d.ts",
|
||||
"es2017.object": "lib.es2017.object.d.ts",
|
||||
"es2017.sharedmemory": "lib.es2017.sharedmemory.d.ts"
|
||||
},
|
||||
},
|
||||
description: Diagnostics.Specify_library_files_to_be_included_in_the_compilation_Colon
|
||||
},
|
||||
{
|
||||
name: "disableProjectSizeLimit",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "strictNullChecks",
|
||||
type: "boolean",
|
||||
@@ -464,7 +496,7 @@ namespace ts {
|
||||
|
||||
/* @internal */
|
||||
export function parseCustomTypeOption(opt: CommandLineOptionOfCustomType, value: string, errors: Diagnostic[]) {
|
||||
const key = (value || "").trim().toLowerCase();
|
||||
const key = trimString((value || "")).toLowerCase();
|
||||
const map = opt.type;
|
||||
if (hasProperty(map, key)) {
|
||||
return map[key];
|
||||
@@ -475,13 +507,20 @@ namespace ts {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function parseListTypeOption(opt: CommandLineOptionOfListType, value: string, errors: Diagnostic[]): (string | number)[] {
|
||||
const values = (value || "").trim().split(",");
|
||||
export function parseListTypeOption(opt: CommandLineOptionOfListType, value = "", errors: Diagnostic[]): (string | number)[] | undefined {
|
||||
value = trimString(value);
|
||||
if (startsWith(value, "-")) {
|
||||
return undefined;
|
||||
}
|
||||
if (value === "") {
|
||||
return [];
|
||||
}
|
||||
const values = value.split(",");
|
||||
switch (opt.element.type) {
|
||||
case "number":
|
||||
return ts.map(values, parseInt);
|
||||
return map(values, parseInt);
|
||||
case "string":
|
||||
return ts.map(values, v => v || "");
|
||||
return map(values, v => v || "");
|
||||
default:
|
||||
return filter(map(values, v => parseCustomTypeOption(<CommandLineOptionOfCustomType>opt.element, v, errors)), v => !!v);
|
||||
}
|
||||
@@ -542,8 +581,11 @@ namespace ts {
|
||||
i++;
|
||||
break;
|
||||
case "list":
|
||||
options[opt.name] = parseListTypeOption(<CommandLineOptionOfListType>opt, args[i], errors);
|
||||
i++;
|
||||
const result = parseListTypeOption(<CommandLineOptionOfListType>opt, args[i], errors);
|
||||
options[opt.name] = result || [];
|
||||
if (result) {
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
// If not a primitive, the possible types are specified in what is effectively a map of options.
|
||||
default:
|
||||
@@ -601,7 +643,7 @@ namespace ts {
|
||||
* Read tsconfig.json file
|
||||
* @param fileName The path to the config file
|
||||
*/
|
||||
export function readConfigFile(fileName: string, readFile: (path: string) => string): { config?: any; error?: Diagnostic } {
|
||||
export function readConfigFile(fileName: string, readFile: (path: string) => string): { config?: any; error?: Diagnostic } {
|
||||
let text = "";
|
||||
try {
|
||||
text = readFile(fileName);
|
||||
@@ -652,6 +694,9 @@ namespace ts {
|
||||
return output;
|
||||
}
|
||||
|
||||
// Skip over any minified JavaScript files (ending in ".min.js")
|
||||
// Skip over dotted files and folders as well
|
||||
const ignoreFileNamePattern = /(\.min\.js$)|([\\/]\.[\w.])/;
|
||||
/**
|
||||
* Parse the contents of a config file (tsconfig.json).
|
||||
* @param json The contents of the config file to parse
|
||||
@@ -664,80 +709,69 @@ namespace ts {
|
||||
const compilerOptions: CompilerOptions = convertCompilerOptionsFromJsonWorker(json["compilerOptions"], basePath, errors, configFileName);
|
||||
const options = extend(existingOptions, compilerOptions);
|
||||
const typingOptions: TypingOptions = convertTypingOptionsFromJsonWorker(json["typingOptions"], basePath, errors, configFileName);
|
||||
|
||||
options.configFilePath = configFileName;
|
||||
|
||||
const fileNames = getFileNames(errors);
|
||||
const { fileNames, wildcardDirectories } = getFileNames(errors);
|
||||
|
||||
return {
|
||||
options,
|
||||
fileNames,
|
||||
typingOptions,
|
||||
errors
|
||||
raw: json,
|
||||
errors,
|
||||
wildcardDirectories
|
||||
};
|
||||
|
||||
function getFileNames(errors: Diagnostic[]): string[] {
|
||||
let fileNames: string[] = [];
|
||||
function getFileNames(errors: Diagnostic[]): ExpandResult {
|
||||
let fileNames: string[];
|
||||
if (hasProperty(json, "files")) {
|
||||
if (isArray(json["files"])) {
|
||||
fileNames = map(<string[]>json["files"], s => combinePaths(basePath, s));
|
||||
fileNames = <string[]>json["files"];
|
||||
}
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "files", "Array"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
const filesSeen: Map<boolean> = {};
|
||||
|
||||
let exclude: string[] = [];
|
||||
if (isArray(json["exclude"])) {
|
||||
exclude = json["exclude"];
|
||||
let includeSpecs: string[];
|
||||
if (hasProperty(json, "include")) {
|
||||
if (isArray(json["include"])) {
|
||||
includeSpecs = <string[]>json["include"];
|
||||
}
|
||||
else {
|
||||
// by default exclude node_modules, and any specificied output directory
|
||||
exclude = ["node_modules"];
|
||||
const outDir = json["compilerOptions"] && json["compilerOptions"]["outDir"];
|
||||
if (outDir) {
|
||||
exclude.push(outDir);
|
||||
}
|
||||
}
|
||||
exclude = map(exclude, normalizeSlashes);
|
||||
|
||||
const supportedExtensions = getSupportedExtensions(options);
|
||||
Debug.assert(indexOf(supportedExtensions, ".ts") < indexOf(supportedExtensions, ".d.ts"), "Changed priority of extensions to pick");
|
||||
|
||||
// Get files of supported extensions in their order of resolution
|
||||
for (const extension of supportedExtensions) {
|
||||
const filesInDirWithExtension = host.readDirectory(basePath, extension, exclude);
|
||||
for (const fileName of filesInDirWithExtension) {
|
||||
// .ts extension would read the .d.ts extension files too but since .d.ts is lower priority extension,
|
||||
// lets pick them when its turn comes up
|
||||
if (extension === ".ts" && fileExtensionIs(fileName, ".d.ts")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip over any minified JavaScript files (ending in ".min.js")
|
||||
if (/\.min\.js$/.test(fileName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this is one of the output extension (which would be .d.ts and .js if we are allowing compilation of js files)
|
||||
// do not include this file if we included .ts or .tsx file with same base name as it could be output of the earlier compilation
|
||||
if (extension === ".d.ts" || (options.allowJs && contains(supportedJavascriptExtensions, extension))) {
|
||||
const baseName = fileName.substr(0, fileName.length - extension.length);
|
||||
if (hasProperty(filesSeen, baseName + ".ts") || hasProperty(filesSeen, baseName + ".tsx")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
filesSeen[fileName] = true;
|
||||
fileNames.push(fileName);
|
||||
}
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "include", "Array"));
|
||||
}
|
||||
}
|
||||
if (hasProperty(json, "excludes") && !hasProperty(json, "exclude")) {
|
||||
|
||||
let excludeSpecs: string[];
|
||||
if (hasProperty(json, "exclude")) {
|
||||
if (isArray(json["exclude"])) {
|
||||
excludeSpecs = <string[]>json["exclude"];
|
||||
}
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "exclude", "Array"));
|
||||
}
|
||||
}
|
||||
else if (hasProperty(json, "excludes")) {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_option_excludes_Did_you_mean_exclude));
|
||||
}
|
||||
return fileNames;
|
||||
else {
|
||||
// By default, exclude common package folders
|
||||
excludeSpecs = ["node_modules", "bower_components", "jspm_packages"];
|
||||
}
|
||||
|
||||
// Always exclude the output directory unless explicitly included
|
||||
const outDir = json["compilerOptions"] && json["compilerOptions"]["outDir"];
|
||||
if (outDir) {
|
||||
excludeSpecs.push(outDir);
|
||||
}
|
||||
|
||||
if (fileNames === undefined && includeSpecs === undefined) {
|
||||
includeSpecs = ["**/*"];
|
||||
}
|
||||
|
||||
return matchFileNames(fileNames, includeSpecs, excludeSpecs, basePath, options, host, errors);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -775,7 +809,7 @@ namespace ts {
|
||||
defaultOptions: CompilerOptions | TypingOptions, diagnosticMessage: DiagnosticMessage, errors: Diagnostic[]) {
|
||||
|
||||
if (!jsonOptions) {
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
|
||||
const optionNameMap = arrayToMap(optionDeclarations, opt => opt.name);
|
||||
@@ -829,4 +863,300 @@ namespace ts {
|
||||
function convertJsonOptionOfListType(option: CommandLineOptionOfListType, values: any[], basePath: string, errors: Diagnostic[]): any[] {
|
||||
return filter(map(values, v => convertJsonOption(option.element, v, basePath, errors)), v => !!v);
|
||||
}
|
||||
|
||||
function trimString(s: string) {
|
||||
return typeof s.trim === "function" ? s.trim() : s.replace(/^[\s]+|[\s]+$/g, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for a path that ends in a recursive directory wildcard.
|
||||
* Matches **, \**, **\, and \**\, but not a**b.
|
||||
*
|
||||
* NOTE: used \ in place of / above to avoid issues with multiline comments.
|
||||
*
|
||||
* Breakdown:
|
||||
* (^|\/) # matches either the beginning of the string or a directory separator.
|
||||
* \*\* # matches the recursive directory wildcard "**".
|
||||
* \/?$ # matches an optional trailing directory separator at the end of the string.
|
||||
*/
|
||||
const invalidTrailingRecursionPattern = /(^|\/)\*\*\/?$/;
|
||||
|
||||
/**
|
||||
* Tests for a path with multiple recursive directory wildcards.
|
||||
* Matches **\** and **\a\**, but not **\a**b.
|
||||
*
|
||||
* NOTE: used \ in place of / above to avoid issues with multiline comments.
|
||||
*
|
||||
* Breakdown:
|
||||
* (^|\/) # matches either the beginning of the string or a directory separator.
|
||||
* \*\*\/ # matches a recursive directory wildcard "**" followed by a directory separator.
|
||||
* (.*\/)? # optionally matches any number of characters followed by a directory separator.
|
||||
* \*\* # matches a recursive directory wildcard "**"
|
||||
* ($|\/) # matches either the end of the string or a directory separator.
|
||||
*/
|
||||
const invalidMultipleRecursionPatterns = /(^|\/)\*\*\/(.*\/)?\*\*($|\/)/;
|
||||
|
||||
/**
|
||||
* Tests for a path containing a wildcard character in a directory component of the path.
|
||||
* Matches \*\, \?\, and \a*b\, but not \a\ or \a\*.
|
||||
*
|
||||
* NOTE: used \ in place of / above to avoid issues with multiline comments.
|
||||
*
|
||||
* Breakdown:
|
||||
* \/ # matches a directory separator.
|
||||
* [^/]*? # matches any number of characters excluding directory separators (non-greedy).
|
||||
* [*?] # matches either a wildcard character (* or ?)
|
||||
* [^/]* # matches any number of characters excluding directory separators (greedy).
|
||||
* \/ # matches a directory separator.
|
||||
*/
|
||||
const watchRecursivePattern = /\/[^/]*?[*?][^/]*\//;
|
||||
|
||||
/**
|
||||
* Matches the portion of a wildcard path that does not contain wildcards.
|
||||
* Matches \a of \a\*, or \a\b\c of \a\b\c\?\d.
|
||||
*
|
||||
* NOTE: used \ in place of / above to avoid issues with multiline comments.
|
||||
*
|
||||
* Breakdown:
|
||||
* ^ # matches the beginning of the string
|
||||
* [^*?]* # matches any number of non-wildcard characters
|
||||
* (?=\/[^/]*[*?]) # lookahead that matches a directory separator followed by
|
||||
* # a path component that contains at least one wildcard character (* or ?).
|
||||
*/
|
||||
const wildcardDirectoryPattern = /^[^*?]*(?=\/[^/]*[*?])/;
|
||||
|
||||
/**
|
||||
* Expands an array of file specifications.
|
||||
*
|
||||
* @param fileNames The literal file names to include.
|
||||
* @param include The wildcard file specifications to include.
|
||||
* @param exclude The wildcard file specifications to exclude.
|
||||
* @param basePath The base path for any relative file specifications.
|
||||
* @param options Compiler options.
|
||||
* @param host The host used to resolve files and directories.
|
||||
* @param errors An array for diagnostic reporting.
|
||||
*/
|
||||
function matchFileNames(fileNames: string[], include: string[], exclude: string[], basePath: string, options: CompilerOptions, host: ParseConfigHost, errors: Diagnostic[]): ExpandResult {
|
||||
basePath = normalizePath(basePath);
|
||||
|
||||
// The exclude spec list is converted into a regular expression, which allows us to quickly
|
||||
// test whether a file or directory should be excluded before recursively traversing the
|
||||
// file system.
|
||||
const keyMapper = host.useCaseSensitiveFileNames ? caseSensitiveKeyMapper : caseInsensitiveKeyMapper;
|
||||
|
||||
// Literal file names (provided via the "files" array in tsconfig.json) are stored in a
|
||||
// file map with a possibly case insensitive key. We use this map later when when including
|
||||
// wildcard paths.
|
||||
const literalFileMap: Map<string> = {};
|
||||
|
||||
// Wildcard paths (provided via the "includes" array in tsconfig.json) are stored in a
|
||||
// file map with a possibly case insensitive key. We use this map to store paths matched
|
||||
// via wildcard, and to handle extension priority.
|
||||
const wildcardFileMap: Map<string> = {};
|
||||
|
||||
if (include) {
|
||||
include = validateSpecs(include, errors, /*allowTrailingRecursion*/ false);
|
||||
}
|
||||
|
||||
if (exclude) {
|
||||
exclude = validateSpecs(exclude, errors, /*allowTrailingRecursion*/ true);
|
||||
}
|
||||
|
||||
// Wildcard directories (provided as part of a wildcard path) are stored in a
|
||||
// file map that marks whether it was a regular wildcard match (with a `*` or `?` token),
|
||||
// or a recursive directory. This information is used by filesystem watchers to monitor for
|
||||
// new entries in these paths.
|
||||
const wildcardDirectories: Map<WatchDirectoryFlags> = getWildcardDirectories(include, exclude, basePath, host.useCaseSensitiveFileNames);
|
||||
|
||||
// Rather than requery this for each file and filespec, we query the supported extensions
|
||||
// once and store it on the expansion context.
|
||||
const supportedExtensions = getSupportedExtensions(options);
|
||||
|
||||
// Literal files are always included verbatim. An "include" or "exclude" specification cannot
|
||||
// remove a literal file.
|
||||
if (fileNames) {
|
||||
for (const fileName of fileNames) {
|
||||
const file = combinePaths(basePath, fileName);
|
||||
literalFileMap[keyMapper(file)] = file;
|
||||
}
|
||||
}
|
||||
|
||||
if (include && include.length > 0) {
|
||||
for (const file of host.readDirectory(basePath, supportedExtensions, exclude, include)) {
|
||||
// If we have already included a literal or wildcard path with a
|
||||
// higher priority extension, we should skip this file.
|
||||
//
|
||||
// This handles cases where we may encounter both <file>.ts and
|
||||
// <file>.d.ts (or <file>.js if "allowJs" is enabled) in the same
|
||||
// directory when they are compilation outputs.
|
||||
if (hasFileWithHigherPriorityExtension(file, literalFileMap, wildcardFileMap, supportedExtensions, keyMapper)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ignoreFileNamePattern.test(file)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We may have included a wildcard path with a lower priority
|
||||
// extension due to the user-defined order of entries in the
|
||||
// "include" array. If there is a lower priority extension in the
|
||||
// same directory, we should remove it.
|
||||
removeWildcardFilesWithLowerPriorityExtension(file, wildcardFileMap, supportedExtensions, keyMapper);
|
||||
|
||||
const key = keyMapper(file);
|
||||
if (!hasProperty(literalFileMap, key) && !hasProperty(wildcardFileMap, key)) {
|
||||
wildcardFileMap[key] = file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const literalFiles = reduceProperties(literalFileMap, addFileToOutput, []);
|
||||
const wildcardFiles = reduceProperties(wildcardFileMap, addFileToOutput, []);
|
||||
wildcardFiles.sort(host.useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive);
|
||||
return {
|
||||
fileNames: literalFiles.concat(wildcardFiles),
|
||||
wildcardDirectories
|
||||
};
|
||||
}
|
||||
|
||||
function validateSpecs(specs: string[], errors: Diagnostic[], allowTrailingRecursion: boolean) {
|
||||
const validSpecs: string[] = [];
|
||||
for (const spec of specs) {
|
||||
if (!allowTrailingRecursion && invalidTrailingRecursionPattern.test(spec)) {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec));
|
||||
}
|
||||
else if (invalidMultipleRecursionPatterns.test(spec)) {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, spec));
|
||||
}
|
||||
else {
|
||||
validSpecs.push(spec);
|
||||
}
|
||||
}
|
||||
|
||||
return validSpecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets directories in a set of include patterns that should be watched for changes.
|
||||
*/
|
||||
function getWildcardDirectories(include: string[], exclude: string[], path: string, useCaseSensitiveFileNames: boolean) {
|
||||
// We watch a directory recursively if it contains a wildcard anywhere in a directory segment
|
||||
// of the pattern:
|
||||
//
|
||||
// /a/b/**/d - Watch /a/b recursively to catch changes to any d in any subfolder recursively
|
||||
// /a/b/*/d - Watch /a/b recursively to catch any d in any immediate subfolder, even if a new subfolder is added
|
||||
//
|
||||
// We watch a directory without recursion if it contains a wildcard in the file segment of
|
||||
// the pattern:
|
||||
//
|
||||
// /a/b/* - Watch /a/b directly to catch any new file
|
||||
// /a/b/a?z - Watch /a/b directly to catch any new file matching a?z
|
||||
const rawExcludeRegex = getRegularExpressionForWildcard(exclude, path, "exclude");
|
||||
const excludeRegex = rawExcludeRegex && new RegExp(rawExcludeRegex, useCaseSensitiveFileNames ? "" : "i");
|
||||
const wildcardDirectories: Map<WatchDirectoryFlags> = {};
|
||||
if (include !== undefined) {
|
||||
const recursiveKeys: string[] = [];
|
||||
for (const file of include) {
|
||||
const name = combinePaths(path, file);
|
||||
if (excludeRegex && excludeRegex.test(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const match = wildcardDirectoryPattern.exec(name);
|
||||
if (match) {
|
||||
const key = useCaseSensitiveFileNames ? match[0] : match[0].toLowerCase();
|
||||
const flags = watchRecursivePattern.test(name) ? WatchDirectoryFlags.Recursive : WatchDirectoryFlags.None;
|
||||
const existingFlags = getProperty(wildcardDirectories, key);
|
||||
if (existingFlags === undefined || existingFlags < flags) {
|
||||
wildcardDirectories[key] = flags;
|
||||
if (flags === WatchDirectoryFlags.Recursive) {
|
||||
recursiveKeys.push(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any subpaths under an existing recursively watched directory.
|
||||
for (const key in wildcardDirectories) {
|
||||
if (hasProperty(wildcardDirectories, key)) {
|
||||
for (const recursiveKey of recursiveKeys) {
|
||||
if (key !== recursiveKey && containsPath(recursiveKey, key, path, !useCaseSensitiveFileNames)) {
|
||||
delete wildcardDirectories[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return wildcardDirectories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a literal or wildcard file has already been included that has a higher
|
||||
* extension priority.
|
||||
*
|
||||
* @param file The path to the file.
|
||||
* @param extensionPriority The priority of the extension.
|
||||
* @param context The expansion context.
|
||||
*/
|
||||
function hasFileWithHigherPriorityExtension(file: string, literalFiles: Map<string>, wildcardFiles: Map<string>, extensions: string[], keyMapper: (value: string) => string) {
|
||||
const extensionPriority = getExtensionPriority(file, extensions);
|
||||
const adjustedExtensionPriority = adjustExtensionPriority(extensionPriority);
|
||||
for (let i = ExtensionPriority.Highest; i < adjustedExtensionPriority; i++) {
|
||||
const higherPriorityExtension = extensions[i];
|
||||
const higherPriorityPath = keyMapper(changeExtension(file, higherPriorityExtension));
|
||||
if (hasProperty(literalFiles, higherPriorityPath) || hasProperty(wildcardFiles, higherPriorityPath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes files included via wildcard expansion with a lower extension priority that have
|
||||
* already been included.
|
||||
*
|
||||
* @param file The path to the file.
|
||||
* @param extensionPriority The priority of the extension.
|
||||
* @param context The expansion context.
|
||||
*/
|
||||
function removeWildcardFilesWithLowerPriorityExtension(file: string, wildcardFiles: Map<string>, extensions: string[], keyMapper: (value: string) => string) {
|
||||
const extensionPriority = getExtensionPriority(file, extensions);
|
||||
const nextExtensionPriority = getNextLowestExtensionPriority(extensionPriority);
|
||||
for (let i = nextExtensionPriority; i < extensions.length; i++) {
|
||||
const lowerPriorityExtension = extensions[i];
|
||||
const lowerPriorityPath = keyMapper(changeExtension(file, lowerPriorityExtension));
|
||||
delete wildcardFiles[lowerPriorityPath];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file to an array of files.
|
||||
*
|
||||
* @param output The output array.
|
||||
* @param file The file path.
|
||||
*/
|
||||
function addFileToOutput(output: string[], file: string) {
|
||||
output.push(file);
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a case sensitive key.
|
||||
*
|
||||
* @param key The original key.
|
||||
*/
|
||||
function caseSensitiveKeyMapper(key: string) {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a case insensitive key.
|
||||
*
|
||||
* @param key The original key.
|
||||
*/
|
||||
function caseInsensitiveKeyMapper(key: string) {
|
||||
return key.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
+378
-7
@@ -25,7 +25,7 @@ namespace ts {
|
||||
contains,
|
||||
remove,
|
||||
forEachValue: forEachValueInMap,
|
||||
clear
|
||||
clear,
|
||||
};
|
||||
|
||||
function forEachValueInMap(f: (key: Path, value: T) => void) {
|
||||
@@ -91,10 +91,10 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function contains<T>(array: T[], value: T): boolean {
|
||||
export function contains<T>(array: T[], value: T, areEqual?: (a: T, b: T) => boolean): boolean {
|
||||
if (array) {
|
||||
for (const v of array) {
|
||||
if (v === value) {
|
||||
if (areEqual ? areEqual(v, value) : v === value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -113,6 +113,15 @@ namespace ts {
|
||||
return -1;
|
||||
}
|
||||
|
||||
export function indexOfAnyCharCode(text: string, charCodes: number[], start?: number): number {
|
||||
for (let i = start || 0, len = text.length; i < len; i++) {
|
||||
if (contains(charCodes, text.charCodeAt(i))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
export function countWhere<T>(array: T[], predicate: (x: T) => boolean): number {
|
||||
let count = 0;
|
||||
if (array) {
|
||||
@@ -138,6 +147,17 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
export function filterMutate<T>(array: T[], f: (x: T) => boolean): void {
|
||||
let outIndex = 0;
|
||||
for (const item of array) {
|
||||
if (f(item)) {
|
||||
array[outIndex] = item;
|
||||
outIndex++;
|
||||
}
|
||||
}
|
||||
array.length = outIndex;
|
||||
}
|
||||
|
||||
export function map<T, U>(array: T[], f: (x: T) => U): U[] {
|
||||
let result: U[];
|
||||
if (array) {
|
||||
@@ -156,12 +176,12 @@ namespace ts {
|
||||
return array1.concat(array2);
|
||||
}
|
||||
|
||||
export function deduplicate<T>(array: T[]): T[] {
|
||||
export function deduplicate<T>(array: T[], areEqual?: (a: T, b: T) => boolean): T[] {
|
||||
let result: T[];
|
||||
if (array) {
|
||||
result = [];
|
||||
for (const item of array) {
|
||||
if (!contains(result, item)) {
|
||||
if (!contains(result, item, areEqual)) {
|
||||
result.push(item);
|
||||
}
|
||||
}
|
||||
@@ -523,6 +543,28 @@ namespace ts {
|
||||
return a < b ? Comparison.LessThan : Comparison.GreaterThan;
|
||||
}
|
||||
|
||||
export function compareStrings(a: string, b: string, ignoreCase?: boolean): Comparison {
|
||||
if (a === b) return Comparison.EqualTo;
|
||||
if (a === undefined) return Comparison.LessThan;
|
||||
if (b === undefined) return Comparison.GreaterThan;
|
||||
if (ignoreCase) {
|
||||
if (String.prototype.localeCompare) {
|
||||
const result = a.localeCompare(b, /*locales*/ undefined, { usage: "sort", sensitivity: "accent" });
|
||||
return result < 0 ? Comparison.LessThan : result > 0 ? Comparison.GreaterThan : Comparison.EqualTo;
|
||||
}
|
||||
|
||||
a = a.toUpperCase();
|
||||
b = b.toUpperCase();
|
||||
if (a === b) return Comparison.EqualTo;
|
||||
}
|
||||
|
||||
return a < b ? Comparison.LessThan : Comparison.GreaterThan;
|
||||
}
|
||||
|
||||
export function compareStringsCaseInsensitive(a: string, b: string) {
|
||||
return compareStrings(a, b, /*ignoreCase*/ true);
|
||||
}
|
||||
|
||||
function getDiagnosticFileName(diagnostic: Diagnostic): string {
|
||||
return diagnostic.file ? diagnostic.file.fileName : undefined;
|
||||
}
|
||||
@@ -792,12 +834,275 @@ namespace ts {
|
||||
return path1 + directorySeparator + path2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a trailing directory separator from a path.
|
||||
* @param path The path.
|
||||
*/
|
||||
export function removeTrailingDirectorySeparator(path: string) {
|
||||
if (path.charAt(path.length - 1) === directorySeparator) {
|
||||
return path.substr(0, path.length - 1);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a trailing directory separator to a path, if it does not already have one.
|
||||
* @param path The path.
|
||||
*/
|
||||
export function ensureTrailingDirectorySeparator(path: string) {
|
||||
if (path.charAt(path.length - 1) !== directorySeparator) {
|
||||
return path + directorySeparator;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
export function comparePaths(a: string, b: string, currentDirectory: string, ignoreCase?: boolean) {
|
||||
if (a === b) return Comparison.EqualTo;
|
||||
if (a === undefined) return Comparison.LessThan;
|
||||
if (b === undefined) return Comparison.GreaterThan;
|
||||
a = removeTrailingDirectorySeparator(a);
|
||||
b = removeTrailingDirectorySeparator(b);
|
||||
const aComponents = getNormalizedPathComponents(a, currentDirectory);
|
||||
const bComponents = getNormalizedPathComponents(b, currentDirectory);
|
||||
const sharedLength = Math.min(aComponents.length, bComponents.length);
|
||||
for (let i = 0; i < sharedLength; i++) {
|
||||
const result = compareStrings(aComponents[i], bComponents[i], ignoreCase);
|
||||
if (result !== Comparison.EqualTo) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return compareValues(aComponents.length, bComponents.length);
|
||||
}
|
||||
|
||||
export function containsPath(parent: string, child: string, currentDirectory: string, ignoreCase?: boolean) {
|
||||
if (parent === undefined || child === undefined) return false;
|
||||
if (parent === child) return true;
|
||||
parent = removeTrailingDirectorySeparator(parent);
|
||||
child = removeTrailingDirectorySeparator(child);
|
||||
if (parent === child) return true;
|
||||
const parentComponents = getNormalizedPathComponents(parent, currentDirectory);
|
||||
const childComponents = getNormalizedPathComponents(child, currentDirectory);
|
||||
if (childComponents.length < parentComponents.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < parentComponents.length; i++) {
|
||||
const result = compareStrings(parentComponents[i], childComponents[i], ignoreCase);
|
||||
if (result !== Comparison.EqualTo) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function fileExtensionIs(path: string, extension: string): boolean {
|
||||
const pathLen = path.length;
|
||||
const extLen = extension.length;
|
||||
return pathLen > extLen && path.substr(pathLen - extLen, extLen) === extension;
|
||||
}
|
||||
|
||||
export function fileExtensionIsAny(path: string, extensions: string[]): boolean {
|
||||
for (const extension of extensions) {
|
||||
if (fileExtensionIs(path, extension)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Reserved characters, forces escaping of any non-word (or digit), non-whitespace character.
|
||||
// It may be inefficient (we could just match (/[-[\]{}()*+?.,\\^$|#\s]/g), but this is future
|
||||
// proof.
|
||||
const reservedCharacterPattern = /[^\w\s\/]/g;
|
||||
const wildcardCharCodes = [CharacterCodes.asterisk, CharacterCodes.question];
|
||||
|
||||
export function getRegularExpressionForWildcard(specs: string[], basePath: string, usage: "files" | "directories" | "exclude") {
|
||||
if (specs === undefined || specs.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let pattern = "";
|
||||
let hasWrittenSubpattern = false;
|
||||
spec: for (const spec of specs) {
|
||||
if (!spec) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let subpattern = "";
|
||||
let hasRecursiveDirectoryWildcard = false;
|
||||
let hasWrittenComponent = false;
|
||||
const components = getNormalizedPathComponents(spec, basePath);
|
||||
if (usage !== "exclude" && components[components.length - 1] === "**") {
|
||||
continue spec;
|
||||
}
|
||||
|
||||
// getNormalizedPathComponents includes the separator for the root component.
|
||||
// We need to remove to create our regex correctly.
|
||||
components[0] = removeTrailingDirectorySeparator(components[0]);
|
||||
|
||||
let optionalCount = 0;
|
||||
for (const component of components) {
|
||||
if (component === "**") {
|
||||
if (hasRecursiveDirectoryWildcard) {
|
||||
continue spec;
|
||||
}
|
||||
|
||||
subpattern += "(/.+?)?";
|
||||
hasRecursiveDirectoryWildcard = true;
|
||||
hasWrittenComponent = true;
|
||||
}
|
||||
else {
|
||||
if (usage === "directories") {
|
||||
subpattern += "(";
|
||||
optionalCount++;
|
||||
}
|
||||
|
||||
if (hasWrittenComponent) {
|
||||
subpattern += directorySeparator;
|
||||
}
|
||||
|
||||
subpattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter);
|
||||
hasWrittenComponent = true;
|
||||
}
|
||||
}
|
||||
|
||||
while (optionalCount > 0) {
|
||||
subpattern += ")?";
|
||||
optionalCount--;
|
||||
}
|
||||
|
||||
if (hasWrittenSubpattern) {
|
||||
pattern += "|";
|
||||
}
|
||||
|
||||
pattern += "(" + subpattern + ")";
|
||||
hasWrittenSubpattern = true;
|
||||
}
|
||||
|
||||
if (!pattern) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return "^(" + pattern + (usage === "exclude" ? ")($|/)" : ")$");
|
||||
}
|
||||
|
||||
function replaceWildcardCharacter(match: string) {
|
||||
return match === "*" ? "[^/]*" : match === "?" ? "[^/]" : "\\" + match;
|
||||
}
|
||||
|
||||
export interface FileSystemEntries {
|
||||
files: string[];
|
||||
directories: string[];
|
||||
}
|
||||
|
||||
export interface FileMatcherPatterns {
|
||||
includeFilePattern: string;
|
||||
includeDirectoryPattern: string;
|
||||
excludePattern: string;
|
||||
basePaths: string[];
|
||||
}
|
||||
|
||||
export function getFileMatcherPatterns(path: string, extensions: string[], excludes: string[], includes: string[], useCaseSensitiveFileNames: boolean, currentDirectory: string): FileMatcherPatterns {
|
||||
path = normalizePath(path);
|
||||
currentDirectory = normalizePath(currentDirectory);
|
||||
const absolutePath = combinePaths(currentDirectory, path);
|
||||
|
||||
return {
|
||||
includeFilePattern: getRegularExpressionForWildcard(includes, absolutePath, "files"),
|
||||
includeDirectoryPattern: getRegularExpressionForWildcard(includes, absolutePath, "directories"),
|
||||
excludePattern: getRegularExpressionForWildcard(excludes, absolutePath, "exclude"),
|
||||
basePaths: getBasePaths(path, includes, useCaseSensitiveFileNames)
|
||||
};
|
||||
}
|
||||
|
||||
export function matchFiles(path: string, extensions: string[], excludes: string[], includes: string[], useCaseSensitiveFileNames: boolean, currentDirectory: string, getFileSystemEntries: (path: string) => FileSystemEntries): string[] {
|
||||
path = normalizePath(path);
|
||||
currentDirectory = normalizePath(currentDirectory);
|
||||
|
||||
const patterns = getFileMatcherPatterns(path, extensions, excludes, includes, useCaseSensitiveFileNames, currentDirectory);
|
||||
|
||||
const regexFlag = useCaseSensitiveFileNames ? "" : "i";
|
||||
const includeFileRegex = patterns.includeFilePattern && new RegExp(patterns.includeFilePattern, regexFlag);
|
||||
const includeDirectoryRegex = patterns.includeDirectoryPattern && new RegExp(patterns.includeDirectoryPattern, regexFlag);
|
||||
const excludeRegex = patterns.excludePattern && new RegExp(patterns.excludePattern, regexFlag);
|
||||
|
||||
const result: string[] = [];
|
||||
for (const basePath of patterns.basePaths) {
|
||||
visitDirectory(basePath, combinePaths(currentDirectory, basePath));
|
||||
}
|
||||
return result;
|
||||
|
||||
function visitDirectory(path: string, absolutePath: string) {
|
||||
const { files, directories } = getFileSystemEntries(path);
|
||||
|
||||
for (const current of files) {
|
||||
const name = combinePaths(path, current);
|
||||
const absoluteName = combinePaths(absolutePath, current);
|
||||
if ((!extensions || fileExtensionIsAny(name, extensions)) &&
|
||||
(!includeFileRegex || includeFileRegex.test(absoluteName)) &&
|
||||
(!excludeRegex || !excludeRegex.test(absoluteName))) {
|
||||
result.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
for (const current of directories) {
|
||||
const name = combinePaths(path, current);
|
||||
const absoluteName = combinePaths(absolutePath, current);
|
||||
if ((!includeDirectoryRegex || includeDirectoryRegex.test(absoluteName)) &&
|
||||
(!excludeRegex || !excludeRegex.test(absoluteName))) {
|
||||
visitDirectory(name, absoluteName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the unique non-wildcard base paths amongst the provided include patterns.
|
||||
*/
|
||||
function getBasePaths(path: string, includes: string[], useCaseSensitiveFileNames: boolean) {
|
||||
// Storage for our results in the form of literal paths (e.g. the paths as written by the user).
|
||||
const basePaths: string[] = [path];
|
||||
if (includes) {
|
||||
// Storage for literal base paths amongst the include patterns.
|
||||
const includeBasePaths: string[] = [];
|
||||
for (const include of includes) {
|
||||
if (isRootedDiskPath(include)) {
|
||||
const wildcardOffset = indexOfAnyCharCode(include, wildcardCharCodes);
|
||||
const includeBasePath = wildcardOffset < 0
|
||||
? removeTrailingDirectorySeparator(getDirectoryPath(include))
|
||||
: include.substring(0, include.lastIndexOf(directorySeparator, wildcardOffset));
|
||||
|
||||
// Append the literal and canonical candidate base paths.
|
||||
includeBasePaths.push(includeBasePath);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the offsets array using either the literal or canonical path representations.
|
||||
includeBasePaths.sort(useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive);
|
||||
|
||||
// Iterate over each include base path and include unique base paths that are not a
|
||||
// subpath of an existing base path
|
||||
include: for (let i = 0; i < includeBasePaths.length; i++) {
|
||||
const includeBasePath = includeBasePaths[i];
|
||||
for (let j = 0; j < basePaths.length; j++) {
|
||||
if (containsPath(basePaths[j], includeBasePath, path, !useCaseSensitiveFileNames)) {
|
||||
continue include;
|
||||
}
|
||||
}
|
||||
|
||||
basePaths.push(includeBasePath);
|
||||
}
|
||||
}
|
||||
|
||||
return basePaths;
|
||||
}
|
||||
|
||||
export function ensureScriptKind(fileName: string, scriptKind?: ScriptKind): ScriptKind {
|
||||
// Using scriptKind as a condition handles both:
|
||||
// - 'scriptKind' is unspecified and thus it is `undefined`
|
||||
@@ -846,16 +1151,82 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension boundaries by priority. Lower numbers indicate higher priorities, and are
|
||||
* aligned to the offset of the highest priority extension in the
|
||||
* allSupportedExtensions array.
|
||||
*/
|
||||
export const enum ExtensionPriority {
|
||||
TypeScriptFiles = 0,
|
||||
DeclarationAndJavaScriptFiles = 2,
|
||||
Limit = 5,
|
||||
|
||||
Highest = TypeScriptFiles,
|
||||
Lowest = DeclarationAndJavaScriptFiles,
|
||||
}
|
||||
|
||||
export function getExtensionPriority(path: string, supportedExtensions: string[]): ExtensionPriority {
|
||||
for (let i = supportedExtensions.length - 1; i >= 0; i--) {
|
||||
if (fileExtensionIs(path, supportedExtensions[i])) {
|
||||
return adjustExtensionPriority(<ExtensionPriority>i);
|
||||
}
|
||||
}
|
||||
|
||||
// If its not in the list of supported extensions, this is likely a
|
||||
// TypeScript file with a non-ts extension
|
||||
return ExtensionPriority.Highest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts an extension priority to be the highest priority within the same range.
|
||||
*/
|
||||
export function adjustExtensionPriority(extensionPriority: ExtensionPriority): ExtensionPriority {
|
||||
if (extensionPriority < ExtensionPriority.DeclarationAndJavaScriptFiles) {
|
||||
return ExtensionPriority.TypeScriptFiles;
|
||||
}
|
||||
else if (extensionPriority < ExtensionPriority.Limit) {
|
||||
return ExtensionPriority.DeclarationAndJavaScriptFiles;
|
||||
}
|
||||
else {
|
||||
return ExtensionPriority.Limit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next lowest extension priority for a given priority.
|
||||
*/
|
||||
export function getNextLowestExtensionPriority(extensionPriority: ExtensionPriority): ExtensionPriority {
|
||||
if (extensionPriority < ExtensionPriority.DeclarationAndJavaScriptFiles) {
|
||||
return ExtensionPriority.DeclarationAndJavaScriptFiles;
|
||||
}
|
||||
else {
|
||||
return ExtensionPriority.Limit;
|
||||
}
|
||||
}
|
||||
|
||||
const extensionsToRemove = [".d.ts", ".ts", ".js", ".tsx", ".jsx"];
|
||||
export function removeFileExtension(path: string): string {
|
||||
for (const ext of extensionsToRemove) {
|
||||
if (fileExtensionIs(path, ext)) {
|
||||
return path.substr(0, path.length - ext.length);
|
||||
const extensionless = tryRemoveExtension(path, ext);
|
||||
if (extensionless !== undefined) {
|
||||
return extensionless;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
export function tryRemoveExtension(path: string, extension: string): string {
|
||||
return fileExtensionIs(path, extension) ? path.substring(0, path.length - extension.length) : undefined;
|
||||
}
|
||||
|
||||
export function isJsxOrTsxExtension(ext: string): boolean {
|
||||
return ext === ".jsx" || ext === ".tsx";
|
||||
}
|
||||
|
||||
export function changeExtension<T extends string | Path>(path: T, newExtension: string): T {
|
||||
return <T>(removeFileExtension(path) + newExtension);
|
||||
}
|
||||
|
||||
export interface ObjectAllocator {
|
||||
getNodeConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => Node;
|
||||
getSourceFileConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => SourceFile;
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace ts {
|
||||
reportedDeclarationError: boolean;
|
||||
moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[];
|
||||
synchronousDeclarationOutput: string;
|
||||
referencePathsOutput: string;
|
||||
referencesOutput: string;
|
||||
}
|
||||
|
||||
type GetSymbolAccessibilityDiagnostic = (symbolAccessibilityResult: SymbolAccessibilityResult) => SymbolAccessibilityDiagnostic;
|
||||
@@ -73,7 +73,9 @@ namespace ts {
|
||||
// Contains the reference paths that needs to go in the declaration file.
|
||||
// Collecting this separately because reference paths need to be first thing in the declaration file
|
||||
// and we could be collecting these paths from multiple files into single one with --out option
|
||||
let referencePathsOutput = "";
|
||||
let referencesOutput = "";
|
||||
|
||||
let usedTypeDirectiveReferences: Map<string>;
|
||||
|
||||
// Emit references corresponding to each file
|
||||
const emittedReferencedFiles: SourceFile[] = [];
|
||||
@@ -93,7 +95,7 @@ namespace ts {
|
||||
// Emit reference in dts, if the file reference was not already emitted
|
||||
if (referencedFile && !contains(emittedReferencedFiles, referencedFile)) {
|
||||
// Add a reference to generated dts file,
|
||||
// global file reference is added only
|
||||
// global file reference is added only
|
||||
// - if it is not bundled emit (because otherwise it would be self reference)
|
||||
// - and it is not already added
|
||||
if (writeReferencePath(referencedFile, !isBundledEmit && !addedGlobalFileReference)) {
|
||||
@@ -146,18 +148,26 @@ namespace ts {
|
||||
|
||||
if (!isBundledEmit && isExternalModule(sourceFile) && sourceFile.moduleAugmentations.length && !resultHasExternalModuleIndicator) {
|
||||
// if file was external module with augmentations - this fact should be preserved in .d.ts as well.
|
||||
// in case if we didn't write any external module specifiers in .d.ts we need to emit something
|
||||
// in case if we didn't write any external module specifiers in .d.ts we need to emit something
|
||||
// that will force compiler to think that this file is an external module - 'export {}' is a reasonable choice here.
|
||||
write("export {};");
|
||||
writeLine();
|
||||
}
|
||||
});
|
||||
|
||||
if (usedTypeDirectiveReferences) {
|
||||
for (const directive in usedTypeDirectiveReferences) {
|
||||
if (hasProperty(usedTypeDirectiveReferences, directive)) {
|
||||
referencesOutput += `/// <reference types="${directive}" />${newLine}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
reportedDeclarationError,
|
||||
moduleElementDeclarationEmitInfo: allSourcesModuleElementDeclarationEmitInfo,
|
||||
synchronousDeclarationOutput: writer.getText(),
|
||||
referencePathsOutput,
|
||||
referencesOutput,
|
||||
};
|
||||
|
||||
function hasInternalAnnotation(range: CommentRange) {
|
||||
@@ -253,6 +263,21 @@ namespace ts {
|
||||
setWriter(oldWriter);
|
||||
}
|
||||
|
||||
function recordTypeReferenceDirectivesIfNecessary(typeReferenceDirectives: string[]): void {
|
||||
if (!typeReferenceDirectives) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!usedTypeDirectiveReferences) {
|
||||
usedTypeDirectiveReferences = {};
|
||||
}
|
||||
for (const directive of typeReferenceDirectives) {
|
||||
if (!hasProperty(usedTypeDirectiveReferences, directive)) {
|
||||
usedTypeDirectiveReferences[directive] = directive;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleSymbolAccessibilityError(symbolAccessibilityResult: SymbolAccessibilityResult) {
|
||||
if (symbolAccessibilityResult.accessibility === SymbolAccessibility.Accessible) {
|
||||
// write the aliases
|
||||
@@ -284,6 +309,7 @@ namespace ts {
|
||||
|
||||
function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
|
||||
handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning));
|
||||
recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForSymbol(symbol, meaning));
|
||||
}
|
||||
|
||||
function reportInaccessibleThisError() {
|
||||
@@ -369,6 +395,7 @@ namespace ts {
|
||||
case SyntaxKind.VoidKeyword:
|
||||
case SyntaxKind.UndefinedKeyword:
|
||||
case SyntaxKind.NullKeyword:
|
||||
case SyntaxKind.NeverKeyword:
|
||||
case SyntaxKind.ThisType:
|
||||
case SyntaxKind.StringLiteralType:
|
||||
return writeTextOfNode(currentText, type);
|
||||
@@ -420,6 +447,7 @@ namespace ts {
|
||||
entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration ? entityName.parent : enclosingDeclaration);
|
||||
|
||||
handleSymbolAccessibilityError(visibilityResult);
|
||||
recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForEntityName(entityName));
|
||||
writeEntityName(entityName);
|
||||
}
|
||||
|
||||
@@ -738,7 +766,7 @@ namespace ts {
|
||||
|
||||
function emitExternalModuleSpecifier(parent: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration) {
|
||||
// emitExternalModuleSpecifier is usually called when we emit something in the.d.ts file that will make it an external module (i.e. import/export declarations).
|
||||
// the only case when it is not true is when we call it to emit correct name for module augmentation - d.ts files with just module augmentations are not considered
|
||||
// the only case when it is not true is when we call it to emit correct name for module augmentation - d.ts files with just module augmentations are not considered
|
||||
// external modules since they are indistinguishable from script files with ambient modules. To fix this in such d.ts files we'll emit top level 'export {}'
|
||||
// so compiler will treat them as external modules.
|
||||
resultHasExternalModuleIndicator = resultHasExternalModuleIndicator || parent.kind !== SyntaxKind.ModuleDeclaration;
|
||||
@@ -825,21 +853,26 @@ namespace ts {
|
||||
writeTextOfNode(currentText, node.name);
|
||||
}
|
||||
}
|
||||
while (node.body.kind !== SyntaxKind.ModuleBlock) {
|
||||
while (node.body && node.body.kind !== SyntaxKind.ModuleBlock) {
|
||||
node = <ModuleDeclaration>node.body;
|
||||
write(".");
|
||||
writeTextOfNode(currentText, node.name);
|
||||
}
|
||||
const prevEnclosingDeclaration = enclosingDeclaration;
|
||||
enclosingDeclaration = node;
|
||||
write(" {");
|
||||
writeLine();
|
||||
increaseIndent();
|
||||
emitLines((<ModuleBlock>node.body).statements);
|
||||
decreaseIndent();
|
||||
write("}");
|
||||
writeLine();
|
||||
enclosingDeclaration = prevEnclosingDeclaration;
|
||||
if (node.body) {
|
||||
enclosingDeclaration = node;
|
||||
write(" {");
|
||||
writeLine();
|
||||
increaseIndent();
|
||||
emitLines((<ModuleBlock>node.body).statements);
|
||||
decreaseIndent();
|
||||
write("}");
|
||||
writeLine();
|
||||
enclosingDeclaration = prevEnclosingDeclaration;
|
||||
}
|
||||
else {
|
||||
write(";");
|
||||
}
|
||||
}
|
||||
|
||||
function writeTypeAliasDeclaration(node: TypeAliasDeclaration) {
|
||||
@@ -1024,7 +1057,7 @@ namespace ts {
|
||||
function emitParameterProperties(constructorDeclaration: ConstructorDeclaration) {
|
||||
if (constructorDeclaration) {
|
||||
forEach(constructorDeclaration.parameters, param => {
|
||||
if (param.flags & NodeFlags.AccessibilityModifier) {
|
||||
if (param.flags & NodeFlags.ParameterPropertyModifier) {
|
||||
emitPropertyDeclaration(param);
|
||||
}
|
||||
});
|
||||
@@ -1102,7 +1135,7 @@ namespace ts {
|
||||
// what we want, namely the name expression enclosed in brackets.
|
||||
writeTextOfNode(currentText, node.name);
|
||||
// If optional property emit ?
|
||||
if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && hasQuestionToken(node)) {
|
||||
if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature || node.kind === SyntaxKind.Parameter) && hasQuestionToken(node)) {
|
||||
write("?");
|
||||
}
|
||||
if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && node.parent.kind === SyntaxKind.TypeLiteral) {
|
||||
@@ -1350,6 +1383,7 @@ namespace ts {
|
||||
function emitSignatureDeclaration(node: SignatureDeclaration) {
|
||||
const prevEnclosingDeclaration = enclosingDeclaration;
|
||||
enclosingDeclaration = node;
|
||||
let closeParenthesizedFunctionType = false;
|
||||
|
||||
if (node.kind === SyntaxKind.IndexSignature) {
|
||||
// Index signature can have readonly modifier
|
||||
@@ -1361,6 +1395,16 @@ namespace ts {
|
||||
if (node.kind === SyntaxKind.ConstructSignature || node.kind === SyntaxKind.ConstructorType) {
|
||||
write("new ");
|
||||
}
|
||||
else if (node.kind === SyntaxKind.FunctionType) {
|
||||
const currentOutput = writer.getText();
|
||||
// Do not generate incorrect type when function type with type parameters is type argument
|
||||
// This could happen if user used space between two '<' making it error free
|
||||
// e.g var x: A< <Tany>(a: Tany)=>Tany>;
|
||||
if (node.typeParameters && currentOutput.charAt(currentOutput.length - 1) === "<") {
|
||||
closeParenthesizedFunctionType = true;
|
||||
write("(");
|
||||
}
|
||||
}
|
||||
emitTypeParameters(node.typeParameters);
|
||||
write("(");
|
||||
}
|
||||
@@ -1394,6 +1438,9 @@ namespace ts {
|
||||
write(";");
|
||||
writeLine();
|
||||
}
|
||||
else if (closeParenthesizedFunctionType) {
|
||||
write(")");
|
||||
}
|
||||
|
||||
function getReturnTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic {
|
||||
let diagnosticMessage: DiagnosticMessage;
|
||||
@@ -1688,7 +1735,7 @@ namespace ts {
|
||||
host.getCanonicalFileName,
|
||||
/*isAbsolutePathAnUrl*/ false);
|
||||
|
||||
referencePathsOutput += '/// <reference path="' + declFileName + '" />' + newLine;
|
||||
referencesOutput += `/// <reference path="${declFileName}" />${newLine}`;
|
||||
}
|
||||
return addedBundledEmitReference;
|
||||
|
||||
@@ -1710,9 +1757,9 @@ namespace ts {
|
||||
const emitDeclarationResult = emitDeclarations(host, resolver, emitterDiagnostics, declarationFilePath, sourceFiles, isBundledEmit);
|
||||
const emitSkipped = emitDeclarationResult.reportedDeclarationError || host.isEmitBlocked(declarationFilePath) || host.getCompilerOptions().noEmit;
|
||||
if (!emitSkipped) {
|
||||
const declarationOutput = emitDeclarationResult.referencePathsOutput
|
||||
const declarationOutput = emitDeclarationResult.referencesOutput
|
||||
+ getDeclarationOutput(emitDeclarationResult.synchronousDeclarationOutput, emitDeclarationResult.moduleElementDeclarationEmitInfo);
|
||||
writeFile(host, emitterDiagnostics, declarationFilePath, declarationOutput, host.getCompilerOptions().emitBOM);
|
||||
writeFile(host, emitterDiagnostics, declarationFilePath, declarationOutput, host.getCompilerOptions().emitBOM, sourceFiles);
|
||||
}
|
||||
return emitSkipped;
|
||||
|
||||
|
||||
@@ -315,10 +315,6 @@
|
||||
"category": "Error",
|
||||
"code": 1110
|
||||
},
|
||||
"A class member cannot be declared optional.": {
|
||||
"category": "Error",
|
||||
"code": 1112
|
||||
},
|
||||
"A 'default' clause cannot appear more than once in a 'switch' statement.": {
|
||||
"category": "Error",
|
||||
"code": 1113
|
||||
@@ -447,7 +443,7 @@
|
||||
"category": "Error",
|
||||
"code": 1147
|
||||
},
|
||||
"Cannot compile modules unless the '--module' flag is provided with a valid module type. Consider setting the 'module' compiler option in a 'tsconfig.json' file.": {
|
||||
"Cannot use imports, exports, or module augmentations when '--module' is 'none'.": {
|
||||
"category": "Error",
|
||||
"code": 1148
|
||||
},
|
||||
@@ -575,7 +571,7 @@
|
||||
"category": "Error",
|
||||
"code": 1186
|
||||
},
|
||||
"A parameter property may not be a binding pattern.": {
|
||||
"A parameter property may not be declared using a binding pattern.": {
|
||||
"category": "Error",
|
||||
"code": 1187
|
||||
},
|
||||
@@ -631,18 +627,14 @@
|
||||
"category": "Error",
|
||||
"code": 1200
|
||||
},
|
||||
"Import assignment cannot be used when targeting ECMAScript 6 modules. Consider using 'import * as ns from \"mod\"', 'import {a} from \"mod\"', 'import d from \"mod\"', or another module format instead.": {
|
||||
"Import assignment cannot be used when targeting ECMAScript 2015 modules. Consider using 'import * as ns from \"mod\"', 'import {a} from \"mod\"', 'import d from \"mod\"', or another module format instead.": {
|
||||
"category": "Error",
|
||||
"code": 1202
|
||||
},
|
||||
"Export assignment cannot be used when targeting ECMAScript 6 modules. Consider using 'export default' or another module format instead.": {
|
||||
"Export assignment cannot be used when targeting ECMAScript 2015 modules. Consider using 'export default' or another module format instead.": {
|
||||
"category": "Error",
|
||||
"code": 1203
|
||||
},
|
||||
"Cannot compile modules into 'es2015' when targeting 'ES5' or lower.": {
|
||||
"category": "Error",
|
||||
"code": 1204
|
||||
},
|
||||
"Decorators are not valid here.": {
|
||||
"category": "Error",
|
||||
"code": 1206
|
||||
@@ -691,7 +683,7 @@
|
||||
"category": "Error",
|
||||
"code": 1219
|
||||
},
|
||||
"Generators are only available when targeting ECMAScript 6 or higher.": {
|
||||
"Generators are only available when targeting ECMAScript 2015 or higher.": {
|
||||
"category": "Error",
|
||||
"code": 1220
|
||||
},
|
||||
@@ -811,6 +803,22 @@
|
||||
"category": "Error",
|
||||
"code": 1249
|
||||
},
|
||||
"Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'.": {
|
||||
"category": "Error",
|
||||
"code": 1250
|
||||
},
|
||||
"Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'. Class definitions are automatically in strict mode.": {
|
||||
"category": "Error",
|
||||
"code": 1251
|
||||
},
|
||||
"Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'. Modules are automatically in strict mode.": {
|
||||
"category": "Error",
|
||||
"code": 1252
|
||||
},
|
||||
"'{0}' tag cannot be used independently as a top level JSDoc tag.": {
|
||||
"category": "Error",
|
||||
"code": 1253
|
||||
},
|
||||
"'with' statements are not allowed in an async function block.": {
|
||||
"category": "Error",
|
||||
"code": 1300
|
||||
@@ -819,7 +827,7 @@
|
||||
"category": "Error",
|
||||
"code": 1308
|
||||
},
|
||||
"Async functions are only available when targeting ECMAScript 6 and higher.": {
|
||||
"Async functions are only available when targeting ECMAScript 2015 or higher.": {
|
||||
"category": "Error",
|
||||
"code": 1311
|
||||
},
|
||||
@@ -843,6 +851,10 @@
|
||||
"category": "Error",
|
||||
"code": 1316
|
||||
},
|
||||
"A parameter property cannot be declared using a rest parameter.": {
|
||||
"category": "Error",
|
||||
"code": 1317
|
||||
},
|
||||
"Duplicate identifier '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 2300
|
||||
@@ -1727,10 +1739,22 @@
|
||||
"category": "Error",
|
||||
"code": 2530
|
||||
},
|
||||
"Object is possibly 'null' or 'undefined'.": {
|
||||
"Object is possibly 'null'.": {
|
||||
"category": "Error",
|
||||
"code": 2531
|
||||
},
|
||||
"Object is possibly 'undefined'.": {
|
||||
"category": "Error",
|
||||
"code": 2532
|
||||
},
|
||||
"Object is possibly 'null' or 'undefined'.": {
|
||||
"category": "Error",
|
||||
"code": 2533
|
||||
},
|
||||
"A function returning 'never' cannot have a reachable end point.": {
|
||||
"category": "Error",
|
||||
"code": 2534
|
||||
},
|
||||
"JSX element attributes type '{0}' may not be a union type.": {
|
||||
"category": "Error",
|
||||
"code": 2600
|
||||
@@ -1807,7 +1831,7 @@
|
||||
"category": "Error",
|
||||
"code": 2660
|
||||
},
|
||||
"Cannot re-export name that is not defined in the module.": {
|
||||
"Cannot export '{0}'. Only local declarations can be exported from a module.": {
|
||||
"category": "Error",
|
||||
"code": 2661
|
||||
},
|
||||
@@ -1823,10 +1847,6 @@
|
||||
"category": "Error",
|
||||
"code": 2664
|
||||
},
|
||||
"Module augmentation cannot introduce new names in the top level scope.": {
|
||||
"category": "Error",
|
||||
"code": 2665
|
||||
},
|
||||
"Exports and export assignments are not permitted in module augmentations.": {
|
||||
"category": "Error",
|
||||
"code": 2666
|
||||
@@ -1891,7 +1911,7 @@
|
||||
"category": "Error",
|
||||
"code": 2681
|
||||
},
|
||||
"A setter cannot have a 'this' parameter.": {
|
||||
"'get' and 'set' accessor must have the same 'this' type.": {
|
||||
"category": "Error",
|
||||
"code": 2682
|
||||
},
|
||||
@@ -1907,6 +1927,22 @@
|
||||
"category": "Error",
|
||||
"code": 2685
|
||||
},
|
||||
"Identifier '{0}' must be imported from a module": {
|
||||
"category": "Error",
|
||||
"code": 2686
|
||||
},
|
||||
"All declarations of '{0}' must have identical modifiers.": {
|
||||
"category": "Error",
|
||||
"code": 2687
|
||||
},
|
||||
"Cannot find type definition file for '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 2688
|
||||
},
|
||||
"Cannot extend an interface '{0}'. Did you mean 'implements'?": {
|
||||
"category": "Error",
|
||||
"code": 2689
|
||||
},
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
"code": 4000
|
||||
@@ -2200,6 +2236,14 @@
|
||||
"category": "Error",
|
||||
"code": 5009
|
||||
},
|
||||
"File specification cannot end in a recursive directory wildcard ('**'): '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 5010
|
||||
},
|
||||
"File specification cannot contain multiple recursive directory wildcards ('**'): '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 5011
|
||||
},
|
||||
"Cannot read file '{0}': {1}": {
|
||||
"category": "Error",
|
||||
"code": 5012
|
||||
@@ -2232,7 +2276,7 @@
|
||||
"category": "Error",
|
||||
"code": 5047
|
||||
},
|
||||
"Option 'inlineSources' can only be used when either option '--inlineSourceMap' or option '--sourceMap' is provided.": {
|
||||
"Option '{0} can only be used when either option '--inlineSourceMap' or option '--sourceMap' is provided.": {
|
||||
"category": "Error",
|
||||
"code": 5051
|
||||
},
|
||||
@@ -2280,7 +2324,14 @@
|
||||
"category": "Error",
|
||||
"code": 5062
|
||||
},
|
||||
|
||||
"Substitutions for pattern '{0}' should be an array.": {
|
||||
"category": "Error",
|
||||
"code": 5063
|
||||
},
|
||||
"Substitution '{0}' for pattern '{1}' has incorrect type, expected 'string', got '{2}'.": {
|
||||
"category": "Error",
|
||||
"code": 5064
|
||||
},
|
||||
"Concatenate and emit output to single file.": {
|
||||
"category": "Message",
|
||||
"code": 6001
|
||||
@@ -2325,6 +2376,10 @@
|
||||
"category": "Message",
|
||||
"code": 6011
|
||||
},
|
||||
"Skip type checking of declaration files.": {
|
||||
"category": "Message",
|
||||
"code": 6012
|
||||
},
|
||||
"Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES2015'": {
|
||||
"category": "Message",
|
||||
"code": 6015
|
||||
@@ -2721,6 +2776,35 @@
|
||||
"category": "Message",
|
||||
"code": 6128
|
||||
},
|
||||
"The config file '{0}' found doesn't contain any source files.": {
|
||||
"category": "Error",
|
||||
"code": 6129
|
||||
},
|
||||
"Resolving real path for '{0}', result '{1}'": {
|
||||
"category": "Message",
|
||||
"code": 6130
|
||||
},
|
||||
"Cannot compile modules using option '{0}' unless the '--module' flag is 'amd' or 'system'.": {
|
||||
"category": "Error",
|
||||
"code": 6131
|
||||
},
|
||||
"File name '{0}' has a '{1}' extension - stripping it": {
|
||||
"category": "Message",
|
||||
"code": 6132
|
||||
},
|
||||
"'{0}' is declared but never used.": {
|
||||
"category": "Error",
|
||||
"code": 6133
|
||||
},
|
||||
"Report Errors on Unused Locals.": {
|
||||
"category": "Message",
|
||||
"code": 6134
|
||||
},
|
||||
"Report Errors on Unused Parameters.": {
|
||||
"category": "Message",
|
||||
"code": 6135
|
||||
},
|
||||
|
||||
"Variable '{0}' implicitly has an '{1}' type.": {
|
||||
"category": "Error",
|
||||
"code": 7005
|
||||
@@ -2865,10 +2949,6 @@
|
||||
"category": "Error",
|
||||
"code": 8012
|
||||
},
|
||||
"'property declarations' can only be used in a .ts file.": {
|
||||
"category": "Error",
|
||||
"code": 8014
|
||||
},
|
||||
"'enum declarations' can only be used in a .ts file.": {
|
||||
"category": "Error",
|
||||
"code": 8015
|
||||
|
||||
+170
-59
@@ -753,6 +753,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
return generateNameForExportDefault();
|
||||
case SyntaxKind.ClassExpression:
|
||||
return generateNameForClassExpression();
|
||||
default:
|
||||
Debug.fail();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1217,7 +1219,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
function jsxEmitReact(node: JsxElement | JsxSelfClosingElement) {
|
||||
/// Emit a tag name, which is either '"div"' for lower-cased names, or
|
||||
/// 'Div' for upper-cased or dotted names
|
||||
function emitTagName(name: Identifier | QualifiedName) {
|
||||
function emitTagName(name: LeftHandSideExpression) {
|
||||
if (name.kind === SyntaxKind.Identifier && isIntrinsicJsxName((<Identifier>name).text)) {
|
||||
write('"');
|
||||
emit(name);
|
||||
@@ -1524,6 +1526,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
case SyntaxKind.AsExpression:
|
||||
case SyntaxKind.AwaitExpression:
|
||||
case SyntaxKind.BinaryExpression:
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.CaseClause:
|
||||
@@ -1670,6 +1673,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
return false;
|
||||
}
|
||||
|
||||
function getClassExpressionInPropertyAccessInStaticPropertyDeclaration(node: Identifier) {
|
||||
if (languageVersion >= ScriptTarget.ES6) {
|
||||
let parent = node.parent;
|
||||
if (parent.kind === SyntaxKind.PropertyAccessExpression && (<PropertyAccessExpression>parent).expression === node) {
|
||||
parent = parent.parent;
|
||||
while (parent && parent.kind !== SyntaxKind.PropertyDeclaration) {
|
||||
parent = parent.parent;
|
||||
}
|
||||
return parent && parent.kind === SyntaxKind.PropertyDeclaration && (parent.flags & NodeFlags.Static) !== 0 &&
|
||||
parent.parent.kind === SyntaxKind.ClassExpression ? parent.parent : undefined;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function emitIdentifier(node: Identifier) {
|
||||
if (convertedLoopState) {
|
||||
if (node.text == "arguments" && resolver.isArgumentsLocalBinding(node)) {
|
||||
@@ -1684,6 +1702,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
write(node.text);
|
||||
}
|
||||
else if (isExpressionIdentifier(node)) {
|
||||
const classExpression = getClassExpressionInPropertyAccessInStaticPropertyDeclaration(node);
|
||||
if (classExpression) {
|
||||
const declaration = resolver.getReferencedValueDeclaration(node);
|
||||
if (declaration === classExpression) {
|
||||
write(getGeneratedNameForNode(declaration.name));
|
||||
return;
|
||||
}
|
||||
}
|
||||
emitExpressionIdentifier(node);
|
||||
}
|
||||
else if (isNameOfNestedBlockScopedRedeclarationOrCapturedBinding(node)) {
|
||||
@@ -1952,7 +1978,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
write("Object.defineProperty(");
|
||||
emit(tempVar);
|
||||
write(", ");
|
||||
emitStart(node.name);
|
||||
emitStart(property.name);
|
||||
emitExpressionForPropertyName(property.name);
|
||||
emitEnd(property.name);
|
||||
write(", {");
|
||||
@@ -2075,7 +2101,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
function createPropertyAccessExpression(expression: Expression, name: Identifier): PropertyAccessExpression {
|
||||
const result = <PropertyAccessExpression>createSynthesizedNode(SyntaxKind.PropertyAccessExpression);
|
||||
result.expression = parenthesizeForAccess(expression);
|
||||
result.dotToken = createSynthesizedNode(SyntaxKind.DotToken);
|
||||
result.name = name;
|
||||
return result;
|
||||
}
|
||||
@@ -2149,9 +2174,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
}
|
||||
|
||||
// Return true if identifier resolves to an exported member of a namespace
|
||||
function isNamespaceExportReference(node: Identifier) {
|
||||
function isExportReference(node: Identifier) {
|
||||
const container = resolver.getReferencedExportContainer(node);
|
||||
return container && container.kind !== SyntaxKind.SourceFile;
|
||||
return !!container;
|
||||
}
|
||||
|
||||
// Return true if identifier resolves to an imported identifier
|
||||
@@ -2184,10 +2209,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
// const foo_1 = require('./foo');
|
||||
// exports.baz = { foo: foo_1.foo };
|
||||
//
|
||||
if (languageVersion < ScriptTarget.ES6 || (modulekind !== ModuleKind.ES6 && isImportedReference(node.name)) || isNamespaceExportReference(node.name) ) {
|
||||
if (languageVersion < ScriptTarget.ES6 || (modulekind !== ModuleKind.ES6 && isImportedReference(node.name)) || isExportReference(node.name)) {
|
||||
// Emit identifier as an identifier
|
||||
write(": ");
|
||||
emit(node.name);
|
||||
emitExpressionIdentifier(node.name);
|
||||
}
|
||||
|
||||
if (languageVersion >= ScriptTarget.ES6 && node.objectAssignmentInitializer) {
|
||||
@@ -2222,11 +2247,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
// Returns 'true' if the code was actually indented, false otherwise.
|
||||
// If the code is not indented, an optional valueToWriteWhenNotIndenting will be
|
||||
// emitted instead.
|
||||
function indentIfOnDifferentLines(parent: Node, node1: Node, node2: Node, valueToWriteWhenNotIndenting?: string): boolean {
|
||||
function indentIfOnDifferentLines(parent: Node, node1: TextRange, node2: TextRange, valueToWriteWhenNotIndenting?: string): boolean {
|
||||
const realNodesAreOnDifferentLines = !nodeIsSynthesized(parent) && !nodeEndIsOnSameLineAsNodeStart(node1, node2);
|
||||
|
||||
// Always use a newline for synthesized code if the synthesizer desires it.
|
||||
const synthesizedNodeIsOnDifferentLine = synthesizedNodeStartsOnNewLine(node2);
|
||||
const synthesizedNodeIsOnDifferentLine = synthesizedNodeStartsOnNewLine(node2 as Node);
|
||||
|
||||
if (realNodesAreOnDifferentLines || synthesizedNodeIsOnDifferentLine) {
|
||||
increaseIndent();
|
||||
@@ -2256,7 +2281,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
}
|
||||
|
||||
emit(node.expression);
|
||||
const indentedBeforeDot = indentIfOnDifferentLines(node, node.expression, node.dotToken);
|
||||
const dotRangeStart = nodeIsSynthesized(node.expression) ? -1 : node.expression.end;
|
||||
const dotRangeEnd = nodeIsSynthesized(node.expression) ? -1 : skipTrivia(currentText, node.expression.end) + 1;
|
||||
const dotToken = <TextRange>{ pos: dotRangeStart, end: dotRangeEnd };
|
||||
const indentedBeforeDot = indentIfOnDifferentLines(node, node.expression, dotToken);
|
||||
|
||||
// 1 .toString is a valid property access, emit a space after the literal
|
||||
// Also emit a space if expression is a integer const enum value - it will appear in generated code as numeric literal
|
||||
@@ -2282,7 +2310,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
write(".");
|
||||
}
|
||||
|
||||
const indentedAfterDot = indentIfOnDifferentLines(node, node.dotToken, node.name);
|
||||
const indentedAfterDot = indentIfOnDifferentLines(node, dotToken, node.name);
|
||||
emit(node.name);
|
||||
decreaseIndentIf(indentedBeforeDot, indentedAfterDot);
|
||||
}
|
||||
@@ -2612,11 +2640,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
return isSourceFileLevelDeclarationInSystemJsModule(targetDeclaration, /*isExported*/ true);
|
||||
}
|
||||
|
||||
function isNameOfExportedDeclarationInNonES6Module(node: Node): boolean {
|
||||
if (modulekind === ModuleKind.System || node.kind !== SyntaxKind.Identifier || nodeIsSynthesized(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !exportEquals && exportSpecifiers && hasProperty(exportSpecifiers, (<Identifier>node).text);
|
||||
}
|
||||
|
||||
function emitPrefixUnaryExpression(node: PrefixUnaryExpression) {
|
||||
const exportChanged = (node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) &&
|
||||
const isPlusPlusOrMinusMinus = (node.operator === SyntaxKind.PlusPlusToken
|
||||
|| node.operator === SyntaxKind.MinusMinusToken);
|
||||
const externalExportChanged = isPlusPlusOrMinusMinus &&
|
||||
isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
|
||||
|
||||
if (exportChanged) {
|
||||
if (externalExportChanged) {
|
||||
// emit
|
||||
// ++x
|
||||
// as
|
||||
@@ -2625,6 +2663,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
emitNodeWithoutSourceMap(node.operand);
|
||||
write(`", `);
|
||||
}
|
||||
const internalExportChanged = isPlusPlusOrMinusMinus &&
|
||||
isNameOfExportedDeclarationInNonES6Module(node.operand);
|
||||
|
||||
if (internalExportChanged) {
|
||||
emitAliasEqual(<Identifier> node.operand);
|
||||
}
|
||||
|
||||
write(tokenToString(node.operator));
|
||||
// In some cases, we need to emit a space between the operator and the operand. One obvious case
|
||||
@@ -2650,14 +2694,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
}
|
||||
emit(node.operand);
|
||||
|
||||
if (exportChanged) {
|
||||
if (externalExportChanged) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
|
||||
function emitPostfixUnaryExpression(node: PostfixUnaryExpression) {
|
||||
const exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
|
||||
if (exportChanged) {
|
||||
const externalExportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
|
||||
const internalExportChanged = isNameOfExportedDeclarationInNonES6Module(node.operand);
|
||||
|
||||
if (externalExportChanged) {
|
||||
// export function returns the value that was passes as the second argument
|
||||
// however for postfix unary expressions result value should be the value before modification.
|
||||
// emit 'x++' as '(export('x', ++x) - 1)' and 'x--' as '(export('x', --x) + 1)'
|
||||
@@ -2675,6 +2721,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
write(") + 1)");
|
||||
}
|
||||
}
|
||||
else if (internalExportChanged) {
|
||||
emitAliasEqual(<Identifier> node.operand);
|
||||
emit(node.operand);
|
||||
if (node.operator === SyntaxKind.PlusPlusToken) {
|
||||
write(" += 1");
|
||||
}
|
||||
else {
|
||||
write(" -= 1");
|
||||
}
|
||||
}
|
||||
else {
|
||||
emit(node.operand);
|
||||
write(tokenToString(node.operator));
|
||||
@@ -2751,7 +2807,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
const identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefineTempVariablesInPlace*/ false, /*shouldEmitCommaBeforeAssignment*/ false);
|
||||
synthesizedLHS.expression = identifier;
|
||||
|
||||
(<PropertyAccessExpression>synthesizedLHS).dotToken = leftHandSideExpression.dotToken;
|
||||
(<PropertyAccessExpression>synthesizedLHS).name = leftHandSideExpression.name;
|
||||
write(", ");
|
||||
}
|
||||
@@ -2776,24 +2831,50 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
}
|
||||
}
|
||||
|
||||
function emitAliasEqual(name: Identifier): boolean {
|
||||
for (const specifier of exportSpecifiers[name.text]) {
|
||||
emitStart(specifier.name);
|
||||
emitContainingModuleName(specifier);
|
||||
if (languageVersion === ScriptTarget.ES3 && name.text === "default") {
|
||||
write('["default"]');
|
||||
}
|
||||
else {
|
||||
write(".");
|
||||
emitNodeWithCommentsAndWithoutSourcemap(specifier.name);
|
||||
}
|
||||
emitEnd(specifier.name);
|
||||
write(" = ");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function emitBinaryExpression(node: BinaryExpression) {
|
||||
if (languageVersion < ScriptTarget.ES6 && node.operatorToken.kind === SyntaxKind.EqualsToken &&
|
||||
(node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) {
|
||||
emitDestructuring(node, node.parent.kind === SyntaxKind.ExpressionStatement);
|
||||
}
|
||||
else {
|
||||
const exportChanged =
|
||||
node.operatorToken.kind >= SyntaxKind.FirstAssignment &&
|
||||
node.operatorToken.kind <= SyntaxKind.LastAssignment &&
|
||||
const isAssignment = isAssignmentOperator(node.operatorToken.kind);
|
||||
|
||||
const externalExportChanged = isAssignment &&
|
||||
isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.left);
|
||||
|
||||
if (exportChanged) {
|
||||
if (externalExportChanged) {
|
||||
// emit assignment 'x <op> y' as 'exports("x", x <op> y)'
|
||||
write(`${exportFunctionForFile}("`);
|
||||
emitNodeWithoutSourceMap(node.left);
|
||||
write(`", `);
|
||||
}
|
||||
|
||||
const internalExportChanged = isAssignment &&
|
||||
isNameOfExportedDeclarationInNonES6Module(node.left);
|
||||
|
||||
if (internalExportChanged) {
|
||||
// export { foo }
|
||||
// emit foo = 2 as exports.foo = foo = 2
|
||||
emitAliasEqual(<Identifier>node.left);
|
||||
}
|
||||
|
||||
if (node.operatorToken.kind === SyntaxKind.AsteriskAsteriskToken || node.operatorToken.kind === SyntaxKind.AsteriskAsteriskEqualsToken) {
|
||||
// Downleveled emit exponentiation operator using Math.pow
|
||||
emitExponentiationOperator(node);
|
||||
@@ -2814,7 +2895,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
decreaseIndentIf(indentedBeforeOperator, indentedAfterOperator);
|
||||
}
|
||||
|
||||
if (exportChanged) {
|
||||
if (externalExportChanged) {
|
||||
write(")");
|
||||
}
|
||||
}
|
||||
@@ -3703,7 +3784,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
getLineOfLocalPositionFromLineMap(currentLineMap, node2.end);
|
||||
}
|
||||
|
||||
function nodeEndIsOnSameLineAsNodeStart(node1: Node, node2: Node) {
|
||||
function nodeEndIsOnSameLineAsNodeStart(node1: TextRange, node2: TextRange) {
|
||||
return getLineOfLocalPositionFromLineMap(currentLineMap, node1.end) ===
|
||||
getLineOfLocalPositionFromLineMap(currentLineMap, skipTrivia(currentText, node2.pos));
|
||||
}
|
||||
@@ -4487,7 +4568,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
}
|
||||
|
||||
function emitRestParameter(node: FunctionLikeDeclaration) {
|
||||
if (languageVersion < ScriptTarget.ES6 && hasRestParameter(node)) {
|
||||
if (languageVersion < ScriptTarget.ES6 && hasDeclaredRestParameter(node)) {
|
||||
const restIndex = node.parameters.length - 1;
|
||||
const restParam = node.parameters[restIndex];
|
||||
|
||||
@@ -4644,7 +4725,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
if (node) {
|
||||
const parameters = node.parameters;
|
||||
const skipCount = node.parameters.length && (<Identifier>node.parameters[0].name).text === "this" ? 1 : 0;
|
||||
const omitCount = languageVersion < ScriptTarget.ES6 && hasRestParameter(node) ? 1 : 0;
|
||||
const omitCount = languageVersion < ScriptTarget.ES6 && hasDeclaredRestParameter(node) ? 1 : 0;
|
||||
emitList(parameters, skipCount, parameters.length - omitCount - skipCount, /*multiLine*/ false, /*trailingComma*/ false);
|
||||
}
|
||||
write(")");
|
||||
@@ -4978,7 +5059,7 @@ const _super = (function (geti, seti) {
|
||||
|
||||
function emitParameterPropertyAssignments(node: ConstructorDeclaration) {
|
||||
forEach(node.parameters, param => {
|
||||
if (param.flags & NodeFlags.AccessibilityModifier) {
|
||||
if (param.flags & NodeFlags.ParameterPropertyModifier) {
|
||||
writeLine();
|
||||
emitStart(param);
|
||||
emitStart(param.name);
|
||||
@@ -5028,13 +5109,13 @@ const _super = (function (geti, seti) {
|
||||
}
|
||||
}
|
||||
|
||||
function emitPropertyDeclaration(node: ClassLikeDeclaration, property: PropertyDeclaration, receiver?: Identifier, isExpression?: boolean) {
|
||||
function emitPropertyDeclaration(node: ClassLikeDeclaration, property: PropertyDeclaration, receiver?: string, isExpression?: boolean) {
|
||||
writeLine();
|
||||
emitLeadingComments(property);
|
||||
emitStart(property);
|
||||
emitStart(property.name);
|
||||
if (receiver) {
|
||||
emit(receiver);
|
||||
write(receiver);
|
||||
}
|
||||
else {
|
||||
if (property.flags & NodeFlags.Static) {
|
||||
@@ -5358,17 +5439,17 @@ const _super = (function (geti, seti) {
|
||||
//
|
||||
// TypeScript | Javascript
|
||||
// --------------------------------|------------------------------------
|
||||
// @dec | let C_1;
|
||||
// class C { | let C = C_1 = class C {
|
||||
// static x() { return C.y; } | static x() { return C_1.y; }
|
||||
// static y = 1; | }
|
||||
// @dec | let C_1 = class C {
|
||||
// class C { | static x() { return C_1.y; }
|
||||
// static x() { return C.y; } | }
|
||||
// static y = 1; | let C = C_1;
|
||||
// } | C.y = 1;
|
||||
// | C = C_1 = __decorate([dec], C);
|
||||
// --------------------------------|------------------------------------
|
||||
// @dec | let C_1;
|
||||
// export class C { | export let C = C_1 = class C {
|
||||
// static x() { return C.y; } | static x() { return C_1.y; }
|
||||
// static y = 1; | }
|
||||
// @dec | let C_1 = class C {
|
||||
// export class C { | static x() { return C_1.y; }
|
||||
// static x() { return C.y; } | }
|
||||
// static y = 1; | export let C = C_1;
|
||||
// } | C.y = 1;
|
||||
// | C = C_1 = __decorate([dec], C);
|
||||
// ---------------------------------------------------------------------
|
||||
@@ -5397,10 +5478,10 @@ const _super = (function (geti, seti) {
|
||||
//
|
||||
// TypeScript | Javascript
|
||||
// --------------------------------|------------------------------------
|
||||
// @dec | let C_1;
|
||||
// export default class C { | let C = C_1 = class C {
|
||||
// static x() { return C.y; } | static x() { return C_1.y; }
|
||||
// static y = 1; | }
|
||||
// @dec | let C_1 = class C {
|
||||
// export default class C { | static x() { return C_1.y; }
|
||||
// static x() { return C.y; } | };
|
||||
// static y = 1; | let C = C_1;
|
||||
// } | C.y = 1;
|
||||
// | C = C_1 = __decorate([dec], C);
|
||||
// | export default C;
|
||||
@@ -5409,25 +5490,25 @@ const _super = (function (geti, seti) {
|
||||
//
|
||||
|
||||
// NOTE: we reuse the same rewriting logic for cases when targeting ES6 and module kind is System.
|
||||
// Because of hoisting top level class declaration need to be emitted as class expressions.
|
||||
// Because of hoisting top level class declaration need to be emitted as class expressions.
|
||||
// Double bind case is only required if node is decorated.
|
||||
if (isDecorated && resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithBodyScopedClassBinding) {
|
||||
decoratedClassAlias = unescapeIdentifier(makeUniqueName(node.name ? node.name.text : "default"));
|
||||
decoratedClassAliases[getNodeId(node)] = decoratedClassAlias;
|
||||
write(`let ${decoratedClassAlias};`);
|
||||
writeLine();
|
||||
}
|
||||
|
||||
if (isES6ExportedDeclaration(node) && !(node.flags & NodeFlags.Default)) {
|
||||
if (isES6ExportedDeclaration(node) && !(node.flags & NodeFlags.Default) && decoratedClassAlias === undefined) {
|
||||
write("export ");
|
||||
}
|
||||
|
||||
if (!isHoistedDeclarationInSystemModule) {
|
||||
write("let ");
|
||||
}
|
||||
emitDeclarationName(node);
|
||||
if (decoratedClassAlias !== undefined) {
|
||||
write(` = ${decoratedClassAlias}`);
|
||||
write(`${decoratedClassAlias}`);
|
||||
}
|
||||
else {
|
||||
emitDeclarationName(node);
|
||||
}
|
||||
|
||||
write(" = ");
|
||||
@@ -5453,13 +5534,16 @@ const _super = (function (geti, seti) {
|
||||
// of it have been initialized by the time it is used.
|
||||
const staticProperties = getInitializedProperties(node, /*isStatic*/ true);
|
||||
const isClassExpressionWithStaticProperties = staticProperties.length > 0 && node.kind === SyntaxKind.ClassExpression;
|
||||
let tempVariable: Identifier;
|
||||
let generatedName: string;
|
||||
|
||||
if (isClassExpressionWithStaticProperties) {
|
||||
tempVariable = createAndRecordTempVariable(TempFlags.Auto);
|
||||
generatedName = getGeneratedNameForNode(node.name);
|
||||
const synthesizedNode = <Identifier>createSynthesizedNode(SyntaxKind.Identifier);
|
||||
synthesizedNode.text = generatedName;
|
||||
recordTempDeclaration(synthesizedNode);
|
||||
write("(");
|
||||
increaseIndent();
|
||||
emit(tempVariable);
|
||||
emit(synthesizedNode);
|
||||
write(" = ");
|
||||
}
|
||||
|
||||
@@ -5489,6 +5573,16 @@ const _super = (function (geti, seti) {
|
||||
emitToken(SyntaxKind.CloseBraceToken, node.members.end);
|
||||
|
||||
if (rewriteAsClassExpression) {
|
||||
if (decoratedClassAlias !== undefined) {
|
||||
write(";");
|
||||
writeLine();
|
||||
if (isES6ExportedDeclaration(node) && !(node.flags & NodeFlags.Default)) {
|
||||
write("export ");
|
||||
}
|
||||
write("let ");
|
||||
emitDeclarationName(node);
|
||||
write(` = ${decoratedClassAlias}`);
|
||||
}
|
||||
decoratedClassAliases[getNodeId(node)] = undefined;
|
||||
write(";");
|
||||
}
|
||||
@@ -5503,11 +5597,11 @@ const _super = (function (geti, seti) {
|
||||
for (const property of staticProperties) {
|
||||
write(",");
|
||||
writeLine();
|
||||
emitPropertyDeclaration(node, property, /*receiver*/ tempVariable, /*isExpression*/ true);
|
||||
emitPropertyDeclaration(node, property, /*receiver*/ generatedName, /*isExpression*/ true);
|
||||
}
|
||||
write(",");
|
||||
writeLine();
|
||||
emit(tempVariable);
|
||||
write(generatedName);
|
||||
decreaseIndent();
|
||||
write(")");
|
||||
}
|
||||
@@ -5548,7 +5642,11 @@ const _super = (function (geti, seti) {
|
||||
}
|
||||
|
||||
function emitClassLikeDeclarationBelowES6(node: ClassLikeDeclaration) {
|
||||
const isES6ExportedClass = isES6ExportedDeclaration(node);
|
||||
if (node.kind === SyntaxKind.ClassDeclaration) {
|
||||
if (isES6ExportedClass && !(node.flags & NodeFlags.Default)) {
|
||||
write("export ");
|
||||
}
|
||||
// source file level classes in system modules are hoisted so 'var's for them are already defined
|
||||
if (!shouldHoistDeclarationInSystemJsModule(node)) {
|
||||
write("var ");
|
||||
@@ -5618,9 +5716,15 @@ const _super = (function (geti, seti) {
|
||||
}
|
||||
emitEnd(node);
|
||||
|
||||
if (node.kind === SyntaxKind.ClassDeclaration) {
|
||||
if (node.kind === SyntaxKind.ClassDeclaration && !isES6ExportedClass) {
|
||||
emitExportMemberAssignment(<ClassDeclaration>node);
|
||||
}
|
||||
else if (isES6ExportedClass && (node.flags & NodeFlags.Default)) {
|
||||
writeLine();
|
||||
write("export default ");
|
||||
emitDeclarationName(node);
|
||||
write(";");
|
||||
}
|
||||
}
|
||||
|
||||
function emitClassMemberPrefix(node: ClassLikeDeclaration, member: Node) {
|
||||
@@ -6058,10 +6162,10 @@ const _super = (function (geti, seti) {
|
||||
|
||||
if (parameters[i].dotDotDotToken) {
|
||||
let parameterType = parameters[i].type;
|
||||
if (parameterType.kind === SyntaxKind.ArrayType) {
|
||||
if (parameterType && parameterType.kind === SyntaxKind.ArrayType) {
|
||||
parameterType = (<ArrayTypeNode>parameterType).elementType;
|
||||
}
|
||||
else if (parameterType.kind === SyntaxKind.TypeReference && (<TypeReferenceNode>parameterType).typeArguments && (<TypeReferenceNode>parameterType).typeArguments.length === 1) {
|
||||
else if (parameterType && parameterType.kind === SyntaxKind.TypeReference && (<TypeReferenceNode>parameterType).typeArguments && (<TypeReferenceNode>parameterType).typeArguments.length === 1) {
|
||||
parameterType = (<TypeReferenceNode>parameterType).typeArguments[0];
|
||||
}
|
||||
else {
|
||||
@@ -6081,9 +6185,15 @@ const _super = (function (geti, seti) {
|
||||
|
||||
/** Serializes the return type of function. Used by the __metadata decorator for a method. */
|
||||
function emitSerializedReturnTypeOfNode(node: Node) {
|
||||
if (node && isFunctionLike(node) && (<FunctionLikeDeclaration>node).type) {
|
||||
emitSerializedTypeNode((<FunctionLikeDeclaration>node).type);
|
||||
return;
|
||||
if (node && isFunctionLike(node)) {
|
||||
if ((<FunctionLikeDeclaration>node).type) {
|
||||
emitSerializedTypeNode((<FunctionLikeDeclaration>node).type);
|
||||
return;
|
||||
}
|
||||
else if (isAsyncFunctionLike(<FunctionLikeDeclaration>node)) {
|
||||
write("Promise");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
write("void 0");
|
||||
@@ -6235,7 +6345,7 @@ const _super = (function (geti, seti) {
|
||||
}
|
||||
|
||||
function getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration: ModuleDeclaration): ModuleDeclaration {
|
||||
if (moduleDeclaration.body.kind === SyntaxKind.ModuleDeclaration) {
|
||||
if (moduleDeclaration.body && moduleDeclaration.body.kind === SyntaxKind.ModuleDeclaration) {
|
||||
const recursiveInnerModule = getInnerMostModuleDeclarationFromDottedModule(<ModuleDeclaration>moduleDeclaration.body);
|
||||
return recursiveInnerModule || <ModuleDeclaration>moduleDeclaration.body;
|
||||
}
|
||||
@@ -6284,6 +6394,7 @@ const _super = (function (geti, seti) {
|
||||
write(getGeneratedNameForNode(node));
|
||||
emitEnd(node.name);
|
||||
write(") ");
|
||||
Debug.assert(node.body !== undefined); // node.body must exist, as this is a non-ambient module
|
||||
if (node.body.kind === SyntaxKind.ModuleBlock) {
|
||||
const saveConvertedLoopState = convertedLoopState;
|
||||
const saveTempFlags = tempFlags;
|
||||
@@ -7879,7 +7990,7 @@ const _super = (function (geti, seti) {
|
||||
node.parent &&
|
||||
node.parent.kind === SyntaxKind.ArrowFunction &&
|
||||
(<ArrowFunction>node.parent).body === node &&
|
||||
compilerOptions.target <= ScriptTarget.ES5) {
|
||||
languageVersion <= ScriptTarget.ES5) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
+275
-56
@@ -137,7 +137,6 @@ namespace ts {
|
||||
return visitNodes(cbNodes, (<ObjectLiteralExpression>node).properties);
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
return visitNode(cbNode, (<PropertyAccessExpression>node).expression) ||
|
||||
visitNode(cbNode, (<PropertyAccessExpression>node).dotToken) ||
|
||||
visitNode(cbNode, (<PropertyAccessExpression>node).name);
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
return visitNode(cbNode, (<ElementAccessExpression>node).expression) ||
|
||||
@@ -303,8 +302,8 @@ namespace ts {
|
||||
case SyntaxKind.ImportClause:
|
||||
return visitNode(cbNode, (<ImportClause>node).name) ||
|
||||
visitNode(cbNode, (<ImportClause>node).namedBindings);
|
||||
case SyntaxKind.GlobalModuleExportDeclaration:
|
||||
return visitNode(cbNode, (<GlobalModuleExportDeclaration>node).name);
|
||||
case SyntaxKind.NamespaceExportDeclaration:
|
||||
return visitNode(cbNode, (<NamespaceExportDeclaration>node).name);
|
||||
|
||||
case SyntaxKind.NamespaceImport:
|
||||
return visitNode(cbNode, (<NamespaceImport>node).name);
|
||||
@@ -401,6 +400,15 @@ namespace ts {
|
||||
return visitNode(cbNode, (<JSDocTypeTag>node).typeExpression);
|
||||
case SyntaxKind.JSDocTemplateTag:
|
||||
return visitNodes(cbNodes, (<JSDocTemplateTag>node).typeParameters);
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
return visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression) ||
|
||||
visitNode(cbNode, (<JSDocTypedefTag>node).name) ||
|
||||
visitNode(cbNode, (<JSDocTypedefTag>node).jsDocTypeLiteral);
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
return visitNodes(cbNodes, (<JSDocTypeLiteral>node).jsDocPropertyTags);
|
||||
case SyntaxKind.JSDocPropertyTag:
|
||||
return visitNode(cbNode, (<JSDocPropertyTag>node).typeExpression) ||
|
||||
visitNode(cbNode, (<JSDocPropertyTag>node).name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,7 +439,14 @@ namespace ts {
|
||||
|
||||
/* @internal */
|
||||
export function parseIsolatedJSDocComment(content: string, start?: number, length?: number) {
|
||||
return Parser.JSDocParser.parseIsolatedJSDocComment(content, start, length);
|
||||
const result = Parser.JSDocParser.parseIsolatedJSDocComment(content, start, length);
|
||||
if (result && result.jsDocComment) {
|
||||
// because the jsDocComment was parsed out of the source file, it might
|
||||
// not be covered by the fixupParentReferences.
|
||||
Parser.fixupParentReferences(result.jsDocComment);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -628,9 +643,14 @@ namespace ts {
|
||||
if (comments) {
|
||||
for (const comment of comments) {
|
||||
const jsDocComment = JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos);
|
||||
if (jsDocComment) {
|
||||
node.jsDocComment = jsDocComment;
|
||||
if (!jsDocComment) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!node.jsDocComments) {
|
||||
node.jsDocComments = [];
|
||||
}
|
||||
node.jsDocComments.push(jsDocComment);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -638,14 +658,14 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function fixupParentReferences(sourceFile: Node) {
|
||||
export function fixupParentReferences(rootNode: Node) {
|
||||
// normally parent references are set during binding. However, for clients that only need
|
||||
// a syntax tree, and no semantic features, then the binding process is an unnecessary
|
||||
// overhead. This functions allows us to set all the parents, without all the expense of
|
||||
// binding.
|
||||
|
||||
let parent: Node = sourceFile;
|
||||
forEachChild(sourceFile, visitNode);
|
||||
let parent: Node = rootNode;
|
||||
forEachChild(rootNode, visitNode);
|
||||
return;
|
||||
|
||||
function visitNode(n: Node): void {
|
||||
@@ -658,6 +678,13 @@ namespace ts {
|
||||
const saveParent = parent;
|
||||
parent = n;
|
||||
forEachChild(n, visitNode);
|
||||
if (n.jsDocComments) {
|
||||
for (const jsDocComment of n.jsDocComments) {
|
||||
jsDocComment.parent = n;
|
||||
parent = jsDocComment;
|
||||
forEachChild(jsDocComment, visitNode);
|
||||
}
|
||||
}
|
||||
parent = saveParent;
|
||||
}
|
||||
}
|
||||
@@ -886,7 +913,7 @@ namespace ts {
|
||||
|
||||
/** Invokes the provided callback then unconditionally restores the parser to the state it
|
||||
* was in immediately prior to invoking the callback. The result of invoking the callback
|
||||
* is returned from this function.
|
||||
* is returned from this function.
|
||||
*/
|
||||
function lookAhead<T>(callback: () => T): T {
|
||||
return speculationHelper(callback, /*isLookAhead*/ true);
|
||||
@@ -1151,6 +1178,7 @@ namespace ts {
|
||||
return token === SyntaxKind.OpenBracketToken
|
||||
|| token === SyntaxKind.OpenBraceToken
|
||||
|| token === SyntaxKind.AsteriskToken
|
||||
|| token === SyntaxKind.DotDotDotToken
|
||||
|| isLiteralPropertyName();
|
||||
}
|
||||
|
||||
@@ -1811,7 +1839,7 @@ namespace ts {
|
||||
function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName {
|
||||
let entity: EntityName = parseIdentifier(diagnosticMessage);
|
||||
while (parseOptional(SyntaxKind.DotToken)) {
|
||||
const node = <QualifiedName>createNode(SyntaxKind.QualifiedName, entity.pos);
|
||||
const node: QualifiedName = <QualifiedName>createNode(SyntaxKind.QualifiedName, entity.pos); // !!!
|
||||
node.left = entity;
|
||||
node.right = parseRightSideOfDot(allowReservedWords);
|
||||
entity = finishNode(node);
|
||||
@@ -2368,6 +2396,7 @@ namespace ts {
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
case SyntaxKind.SymbolKeyword:
|
||||
case SyntaxKind.UndefinedKeyword:
|
||||
case SyntaxKind.NeverKeyword:
|
||||
// If these are followed by a dot, then parse these out as a dotted type reference instead.
|
||||
const node = tryParse(parseKeywordAndNoDot);
|
||||
return node || parseTypeReference();
|
||||
@@ -2410,6 +2439,7 @@ namespace ts {
|
||||
case SyntaxKind.NullKeyword:
|
||||
case SyntaxKind.ThisKeyword:
|
||||
case SyntaxKind.TypeOfKeyword:
|
||||
case SyntaxKind.NeverKeyword:
|
||||
case SyntaxKind.OpenBraceToken:
|
||||
case SyntaxKind.OpenBracketToken:
|
||||
case SyntaxKind.LessThanToken:
|
||||
@@ -2685,7 +2715,8 @@ namespace ts {
|
||||
// 2) LeftHandSideExpression = AssignmentExpression[?in,?yield]
|
||||
// 3) LeftHandSideExpression AssignmentOperator AssignmentExpression[?in,?yield]
|
||||
// 4) ArrowFunctionExpression[?in,?yield]
|
||||
// 5) [+Yield] YieldExpression[?In]
|
||||
// 5) AsyncArrowFunctionExpression[in,yield,await]
|
||||
// 6) [+Yield] YieldExpression[?In]
|
||||
//
|
||||
// Note: for ease of implementation we treat productions '2' and '3' as the same thing.
|
||||
// (i.e. they're both BinaryExpressions with an assignment operator in it).
|
||||
@@ -2695,11 +2726,18 @@ namespace ts {
|
||||
return parseYieldExpression();
|
||||
}
|
||||
|
||||
// Then, check if we have an arrow function (production '4') that starts with a parenthesized
|
||||
// parameter list. If we do, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is
|
||||
// Then, check if we have an arrow function (production '4' and '5') that starts with a parenthesized
|
||||
// parameter list or is an async arrow function.
|
||||
// AsyncArrowFunctionExpression:
|
||||
// 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In]
|
||||
// 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In]
|
||||
// Production (1) of AsyncArrowFunctionExpression is parsed in "tryParseAsyncSimpleArrowFunctionExpression".
|
||||
// And production (2) is parsed in "tryParseParenthesizedArrowFunctionExpression".
|
||||
//
|
||||
// If we do successfully parse arrow-function, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is
|
||||
// not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done
|
||||
// with AssignmentExpression if we see one.
|
||||
const arrowExpression = tryParseParenthesizedArrowFunctionExpression();
|
||||
const arrowExpression = tryParseParenthesizedArrowFunctionExpression() || tryParseAsyncSimpleArrowFunctionExpression();
|
||||
if (arrowExpression) {
|
||||
return arrowExpression;
|
||||
}
|
||||
@@ -2791,10 +2829,17 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function parseSimpleArrowFunctionExpression(identifier: Identifier): Expression {
|
||||
function parseSimpleArrowFunctionExpression(identifier: Identifier, asyncModifier?: ModifiersArray): ArrowFunction {
|
||||
Debug.assert(token === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>");
|
||||
|
||||
const node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction, identifier.pos);
|
||||
let node: ArrowFunction;
|
||||
if (asyncModifier) {
|
||||
node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction, asyncModifier.pos);
|
||||
setModifiers(node, asyncModifier);
|
||||
}
|
||||
else {
|
||||
node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction, identifier.pos);
|
||||
}
|
||||
|
||||
const parameter = <ParameterDeclaration>createNode(SyntaxKind.Parameter, identifier.pos);
|
||||
parameter.name = identifier;
|
||||
@@ -2805,7 +2850,7 @@ namespace ts {
|
||||
node.parameters.end = parameter.end;
|
||||
|
||||
node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, "=>");
|
||||
node.body = parseArrowFunctionExpressionBody(/*isAsync*/ false);
|
||||
node.body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier);
|
||||
|
||||
return finishNode(node);
|
||||
}
|
||||
@@ -2973,6 +3018,40 @@ namespace ts {
|
||||
return parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity*/ false);
|
||||
}
|
||||
|
||||
function tryParseAsyncSimpleArrowFunctionExpression(): ArrowFunction {
|
||||
// We do a check here so that we won't be doing unnecessarily call to "lookAhead"
|
||||
if (token === SyntaxKind.AsyncKeyword) {
|
||||
const isUnParenthesizedAsyncArrowFunction = lookAhead(isUnParenthesizedAsyncArrowFunctionWorker);
|
||||
if (isUnParenthesizedAsyncArrowFunction === Tristate.True) {
|
||||
const asyncModifier = parseModifiersForArrowFunction();
|
||||
const expr = parseBinaryExpressionOrHigher(/*precedence*/ 0);
|
||||
return parseSimpleArrowFunctionExpression(<Identifier>expr, asyncModifier);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function isUnParenthesizedAsyncArrowFunctionWorker(): Tristate {
|
||||
// AsyncArrowFunctionExpression:
|
||||
// 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In]
|
||||
// 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In]
|
||||
if (token === SyntaxKind.AsyncKeyword) {
|
||||
nextToken();
|
||||
// If the "async" is followed by "=>" token then it is not a begining of an async arrow-function
|
||||
// but instead a simple arrow-function which will be parsed inside "parseAssignmentExpressionOrHigher"
|
||||
if (scanner.hasPrecedingLineBreak() || token === SyntaxKind.EqualsGreaterThanToken) {
|
||||
return Tristate.False;
|
||||
}
|
||||
// Check for un-parenthesized AsyncArrowFunction
|
||||
const expr = parseBinaryExpressionOrHigher(/*precedence*/ 0);
|
||||
if (!scanner.hasPrecedingLineBreak() && expr.kind === SyntaxKind.Identifier && token === SyntaxKind.EqualsGreaterThanToken) {
|
||||
return Tristate.True;
|
||||
}
|
||||
}
|
||||
|
||||
return Tristate.False;
|
||||
}
|
||||
|
||||
function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): ArrowFunction {
|
||||
const node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction);
|
||||
setModifiers(node, parseModifiersForArrowFunction());
|
||||
@@ -3345,8 +3424,8 @@ namespace ts {
|
||||
if (sourceFile.languageVariant !== LanguageVariant.JSX) {
|
||||
return false;
|
||||
}
|
||||
// We are in JSX context and the token is part of JSXElement.
|
||||
// Fall through
|
||||
// We are in JSX context and the token is part of JSXElement.
|
||||
// Fall through
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
@@ -3492,12 +3571,12 @@ namespace ts {
|
||||
// If it wasn't then just try to parse out a '.' and report an error.
|
||||
const node = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
|
||||
node.expression = expression;
|
||||
node.dotToken = parseExpectedToken(SyntaxKind.DotToken, /*reportAtCurrentPosition*/ false, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access);
|
||||
parseExpectedToken(SyntaxKind.DotToken, /*reportAtCurrentPosition*/ false, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access);
|
||||
node.name = parseRightSideOfDot(/*allowIdentifierNames*/ true);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function tagNamesAreEquivalent(lhs: EntityName, rhs: EntityName): boolean {
|
||||
function tagNamesAreEquivalent(lhs: JsxTagNameExpression, rhs: JsxTagNameExpression): boolean {
|
||||
if (lhs.kind !== rhs.kind) {
|
||||
return false;
|
||||
}
|
||||
@@ -3506,8 +3585,15 @@ namespace ts {
|
||||
return (<Identifier>lhs).text === (<Identifier>rhs).text;
|
||||
}
|
||||
|
||||
return (<QualifiedName>lhs).right.text === (<QualifiedName>rhs).right.text &&
|
||||
tagNamesAreEquivalent((<QualifiedName>lhs).left, (<QualifiedName>rhs).left);
|
||||
if (lhs.kind === SyntaxKind.ThisKeyword) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we are at this statement then we must have PropertyAccessExpression and because tag name in Jsx element can only
|
||||
// take forms of JsxTagNameExpression which includes an identifier, "this" expression, or another propertyAccessExpression
|
||||
// it is safe to case the expression property as such. See parseJsxElementName for how we parse tag name in Jsx element
|
||||
return (<PropertyAccessExpression>lhs).name.text === (<PropertyAccessExpression>rhs).name.text &&
|
||||
tagNamesAreEquivalent((<PropertyAccessExpression>lhs).expression as JsxTagNameExpression, (<PropertyAccessExpression>rhs).expression as JsxTagNameExpression);
|
||||
}
|
||||
|
||||
|
||||
@@ -3575,7 +3661,7 @@ namespace ts {
|
||||
Debug.fail("Unknown JSX child kind " + token);
|
||||
}
|
||||
|
||||
function parseJsxChildren(openingTagName: EntityName): NodeArray<JsxChild> {
|
||||
function parseJsxChildren(openingTagName: LeftHandSideExpression): NodeArray<JsxChild> {
|
||||
const result = <NodeArray<JsxChild>>[];
|
||||
result.pos = scanner.getStartPos();
|
||||
const saveParsingContext = parsingContext;
|
||||
@@ -3638,17 +3724,22 @@ namespace ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseJsxElementName(): EntityName {
|
||||
function parseJsxElementName(): JsxTagNameExpression {
|
||||
scanJsxIdentifier();
|
||||
let elementName: EntityName = parseIdentifierName();
|
||||
// JsxElement can have name in the form of
|
||||
// propertyAccessExpression
|
||||
// primaryExpression in the form of an identifier and "this" keyword
|
||||
// We can't just simply use parseLeftHandSideExpressionOrHigher because then we will start consider class,function etc as a keyword
|
||||
// We only want to consider "this" as a primaryExpression
|
||||
let expression: JsxTagNameExpression = token === SyntaxKind.ThisKeyword ?
|
||||
parseTokenNode<PrimaryExpression>() : parseIdentifierName();
|
||||
while (parseOptional(SyntaxKind.DotToken)) {
|
||||
scanJsxIdentifier();
|
||||
const node = <QualifiedName>createNode(SyntaxKind.QualifiedName, elementName.pos);
|
||||
node.left = elementName;
|
||||
node.right = parseIdentifierName();
|
||||
elementName = finishNode(node);
|
||||
const propertyAccess: PropertyAccessExpression = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
|
||||
propertyAccess.expression = expression;
|
||||
propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true);
|
||||
expression = finishNode(propertyAccess);
|
||||
}
|
||||
return elementName;
|
||||
return expression;
|
||||
}
|
||||
|
||||
function parseJsxExpression(inExpressionContext: boolean): JsxExpression {
|
||||
@@ -3728,7 +3819,6 @@ namespace ts {
|
||||
if (dotToken) {
|
||||
const propertyAccess = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
|
||||
propertyAccess.expression = expression;
|
||||
propertyAccess.dotToken = dotToken;
|
||||
propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true);
|
||||
expression = finishNode(propertyAccess);
|
||||
continue;
|
||||
@@ -4048,9 +4138,9 @@ namespace ts {
|
||||
const isAsync = !!(node.flags & NodeFlags.Async);
|
||||
node.name =
|
||||
isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalIdentifier) :
|
||||
isGenerator ? doInYieldContext(parseOptionalIdentifier) :
|
||||
isAsync ? doInAwaitContext(parseOptionalIdentifier) :
|
||||
parseOptionalIdentifier();
|
||||
isGenerator ? doInYieldContext(parseOptionalIdentifier) :
|
||||
isAsync ? doInAwaitContext(parseOptionalIdentifier) :
|
||||
parseOptionalIdentifier();
|
||||
|
||||
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ isGenerator, /*awaitContext*/ isAsync, /*requireCompleteParameterList*/ false, node);
|
||||
node.body = parseFunctionBlock(/*allowYield*/ isGenerator, /*allowAwait*/ isAsync, /*ignoreMissingOpenBrace*/ false);
|
||||
@@ -4621,7 +4711,7 @@ namespace ts {
|
||||
case SyntaxKind.EqualsToken:
|
||||
return parseExportAssignment(fullStart, decorators, modifiers);
|
||||
case SyntaxKind.AsKeyword:
|
||||
return parseGlobalModuleExportDeclaration(fullStart, decorators, modifiers);
|
||||
return parseNamespaceExportDeclaration(fullStart, decorators, modifiers);
|
||||
default:
|
||||
return parseExportDeclaration(fullStart, decorators, modifiers);
|
||||
}
|
||||
@@ -4988,7 +5078,7 @@ namespace ts {
|
||||
|
||||
if (token === SyntaxKind.ConstKeyword && permitInvalidConstAsModifier) {
|
||||
// We need to ensure that any subsequent modifiers appear on the same line
|
||||
// so that when 'const' is a standalone declaration, we don't issue an error.
|
||||
// so that when 'const' is a standalone declaration, we don't issue an error.
|
||||
if (!tryParse(nextTokenIsOnSameLineAndCanFollowModifier)) {
|
||||
break;
|
||||
}
|
||||
@@ -5251,14 +5341,21 @@ namespace ts {
|
||||
node.decorators = decorators;
|
||||
setModifiers(node, modifiers);
|
||||
if (token === SyntaxKind.GlobalKeyword) {
|
||||
// parse 'global' as name of global scope augmentation
|
||||
// parse 'global' as name of global scope augmentation
|
||||
node.name = parseIdentifier();
|
||||
node.flags |= NodeFlags.GlobalAugmentation;
|
||||
}
|
||||
else {
|
||||
node.name = parseLiteralNode(/*internName*/ true);
|
||||
}
|
||||
node.body = parseModuleBlock();
|
||||
|
||||
if (token === SyntaxKind.OpenBraceToken) {
|
||||
node.body = parseModuleBlock();
|
||||
}
|
||||
else {
|
||||
parseSemicolon();
|
||||
}
|
||||
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
@@ -5293,8 +5390,8 @@ namespace ts {
|
||||
return nextToken() === SyntaxKind.SlashToken;
|
||||
}
|
||||
|
||||
function parseGlobalModuleExportDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: ModifiersArray): GlobalModuleExportDeclaration {
|
||||
const exportDeclaration = <GlobalModuleExportDeclaration>createNode(SyntaxKind.GlobalModuleExportDeclaration, fullStart);
|
||||
function parseNamespaceExportDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: ModifiersArray): NamespaceExportDeclaration {
|
||||
const exportDeclaration = <NamespaceExportDeclaration>createNode(SyntaxKind.NamespaceExportDeclaration, fullStart);
|
||||
exportDeclaration.decorators = decorators;
|
||||
exportDeclaration.modifiers = modifiers;
|
||||
parseExpected(SyntaxKind.AsKeyword);
|
||||
@@ -5840,7 +5937,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkForEmptyTypeArgumentList(typeArguments: NodeArray<Node>) {
|
||||
if (parseDiagnostics.length === 0 && typeArguments && typeArguments.length === 0) {
|
||||
if (parseDiagnostics.length === 0 && typeArguments && typeArguments.length === 0) {
|
||||
const start = typeArguments.pos - "<".length;
|
||||
const end = skipTrivia(sourceText, typeArguments.end) + ">".length;
|
||||
return parseErrorAtPosition(start, end - start, Diagnostics.Type_argument_list_cannot_be_empty);
|
||||
@@ -6001,7 +6098,6 @@ namespace ts {
|
||||
Debug.assert(end <= content.length);
|
||||
|
||||
let tags: NodeArray<JSDocTag>;
|
||||
|
||||
let result: JSDocComment;
|
||||
|
||||
// Check for /** (JSDoc opening part)
|
||||
@@ -6087,7 +6183,7 @@ namespace ts {
|
||||
atToken.end = scanner.getTextPos();
|
||||
nextJSDocToken();
|
||||
|
||||
const tagName = parseJSDocIdentifier();
|
||||
const tagName = parseJSDocIdentifierName();
|
||||
if (!tagName) {
|
||||
return;
|
||||
}
|
||||
@@ -6108,6 +6204,8 @@ namespace ts {
|
||||
return handleTemplateTag(atToken, tagName);
|
||||
case "type":
|
||||
return handleTypeTag(atToken, tagName);
|
||||
case "typedef":
|
||||
return handleTypedefTag(atToken, tagName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6150,7 +6248,7 @@ namespace ts {
|
||||
let isBracketed: boolean;
|
||||
// Looking for something like '[foo]' or 'foo'
|
||||
if (parseOptionalToken(SyntaxKind.OpenBracketToken)) {
|
||||
name = parseJSDocIdentifier();
|
||||
name = parseJSDocIdentifierName();
|
||||
isBracketed = true;
|
||||
|
||||
// May have an optional default, e.g. '[foo = 42]'
|
||||
@@ -6160,8 +6258,8 @@ namespace ts {
|
||||
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
}
|
||||
else if (token === SyntaxKind.Identifier) {
|
||||
name = parseJSDocIdentifier();
|
||||
else if (tokenIsIdentifierOrKeyword(token)) {
|
||||
name = parseJSDocIdentifierName();
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
@@ -6215,6 +6313,122 @@ namespace ts {
|
||||
return finishNode(result);
|
||||
}
|
||||
|
||||
function handlePropertyTag(atToken: Node, tagName: Identifier): JSDocPropertyTag {
|
||||
const typeExpression = tryParseTypeExpression();
|
||||
skipWhitespace();
|
||||
const name = parseJSDocIdentifierName();
|
||||
if (!name) {
|
||||
parseErrorAtPosition(scanner.getStartPos(), /*length*/ 0, Diagnostics.Identifier_expected);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const result = <JSDocPropertyTag>createNode(SyntaxKind.JSDocPropertyTag, atToken.pos);
|
||||
result.atToken = atToken;
|
||||
result.tagName = tagName;
|
||||
result.name = name;
|
||||
result.typeExpression = typeExpression;
|
||||
return finishNode(result);
|
||||
}
|
||||
|
||||
function handleTypedefTag(atToken: Node, tagName: Identifier): JSDocTypedefTag {
|
||||
const typeExpression = tryParseTypeExpression();
|
||||
skipWhitespace();
|
||||
|
||||
const typedefTag = <JSDocTypedefTag>createNode(SyntaxKind.JSDocTypedefTag, atToken.pos);
|
||||
typedefTag.atToken = atToken;
|
||||
typedefTag.tagName = tagName;
|
||||
typedefTag.name = parseJSDocIdentifierName();
|
||||
typedefTag.typeExpression = typeExpression;
|
||||
|
||||
if (typeExpression) {
|
||||
if (typeExpression.type.kind === SyntaxKind.JSDocTypeReference) {
|
||||
const jsDocTypeReference = <JSDocTypeReference>typeExpression.type;
|
||||
if (jsDocTypeReference.name.kind === SyntaxKind.Identifier) {
|
||||
const name = <Identifier>jsDocTypeReference.name;
|
||||
if (name.text === "Object") {
|
||||
typedefTag.jsDocTypeLiteral = scanChildTags();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!typedefTag.jsDocTypeLiteral) {
|
||||
typedefTag.jsDocTypeLiteral = typeExpression.type;
|
||||
}
|
||||
}
|
||||
else {
|
||||
typedefTag.jsDocTypeLiteral = scanChildTags();
|
||||
}
|
||||
|
||||
return finishNode(typedefTag);
|
||||
|
||||
function scanChildTags(): JSDocTypeLiteral {
|
||||
const jsDocTypeLiteral = <JSDocTypeLiteral>createNode(SyntaxKind.JSDocTypeLiteral, scanner.getStartPos());
|
||||
let resumePos = scanner.getStartPos();
|
||||
let canParseTag = true;
|
||||
let seenAsterisk = false;
|
||||
let parentTagTerminated = false;
|
||||
|
||||
while (token !== SyntaxKind.EndOfFileToken && !parentTagTerminated) {
|
||||
nextJSDocToken();
|
||||
switch (token) {
|
||||
case SyntaxKind.AtToken:
|
||||
if (canParseTag) {
|
||||
parentTagTerminated = !tryParseChildTag(jsDocTypeLiteral);
|
||||
}
|
||||
seenAsterisk = false;
|
||||
break;
|
||||
case SyntaxKind.NewLineTrivia:
|
||||
resumePos = scanner.getStartPos() - 1;
|
||||
canParseTag = true;
|
||||
seenAsterisk = false;
|
||||
break;
|
||||
case SyntaxKind.AsteriskToken:
|
||||
if (seenAsterisk) {
|
||||
canParseTag = false;
|
||||
}
|
||||
seenAsterisk = true;
|
||||
break;
|
||||
case SyntaxKind.Identifier:
|
||||
canParseTag = false;
|
||||
case SyntaxKind.EndOfFileToken:
|
||||
break;
|
||||
}
|
||||
}
|
||||
scanner.setTextPos(resumePos);
|
||||
return finishNode(jsDocTypeLiteral);
|
||||
}
|
||||
}
|
||||
|
||||
function tryParseChildTag(parentTag: JSDocTypeLiteral): boolean {
|
||||
Debug.assert(token === SyntaxKind.AtToken);
|
||||
const atToken = createNode(SyntaxKind.AtToken, scanner.getStartPos());
|
||||
atToken.end = scanner.getTextPos();
|
||||
nextJSDocToken();
|
||||
|
||||
const tagName = parseJSDocIdentifierName();
|
||||
if (!tagName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (tagName.text) {
|
||||
case "type":
|
||||
if (parentTag.jsDocTypeTag) {
|
||||
// already has a @type tag, terminate the parent tag now.
|
||||
return false;
|
||||
}
|
||||
parentTag.jsDocTypeTag = handleTypeTag(atToken, tagName);
|
||||
return true;
|
||||
case "prop":
|
||||
case "property":
|
||||
if (!parentTag.jsDocPropertyTags) {
|
||||
parentTag.jsDocPropertyTags = <NodeArray<JSDocPropertyTag>>[];
|
||||
}
|
||||
const propertyTag = handlePropertyTag(atToken, tagName);
|
||||
parentTag.jsDocPropertyTags.push(propertyTag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function handleTemplateTag(atToken: Node, tagName: Identifier): JSDocTemplateTag {
|
||||
if (forEach(tags, t => t.kind === SyntaxKind.JSDocTemplateTag)) {
|
||||
parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_already_specified, tagName.text);
|
||||
@@ -6225,7 +6439,7 @@ namespace ts {
|
||||
typeParameters.pos = scanner.getStartPos();
|
||||
|
||||
while (true) {
|
||||
const name = parseJSDocIdentifier();
|
||||
const name = parseJSDocIdentifierName();
|
||||
if (!name) {
|
||||
parseErrorAtPosition(scanner.getStartPos(), 0, Diagnostics.Identifier_expected);
|
||||
return undefined;
|
||||
@@ -6258,8 +6472,12 @@ namespace ts {
|
||||
return token = scanner.scanJSDocToken();
|
||||
}
|
||||
|
||||
function parseJSDocIdentifier(): Identifier {
|
||||
if (token !== SyntaxKind.Identifier) {
|
||||
function parseJSDocIdentifierName(): Identifier {
|
||||
return createJSDocIdentifier(tokenIsIdentifierOrKeyword(token));
|
||||
}
|
||||
|
||||
function createJSDocIdentifier(isIdentifier: boolean): Identifier {
|
||||
if (!isIdentifier) {
|
||||
parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
|
||||
return undefined;
|
||||
}
|
||||
@@ -6380,10 +6598,6 @@ namespace ts {
|
||||
node._children = undefined;
|
||||
}
|
||||
|
||||
if (node.jsDocComment) {
|
||||
node.jsDocComment = undefined;
|
||||
}
|
||||
|
||||
node.pos += delta;
|
||||
node.end += delta;
|
||||
|
||||
@@ -6392,6 +6606,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
forEachChild(node, visitNode, visitArray);
|
||||
if (node.jsDocComments) {
|
||||
for (const jsDocComment of node.jsDocComments) {
|
||||
forEachChild(jsDocComment, visitNode, visitArray);
|
||||
}
|
||||
}
|
||||
checkNodePositions(node, aggressiveChecks);
|
||||
}
|
||||
|
||||
|
||||
+257
-138
@@ -9,16 +9,11 @@ namespace ts {
|
||||
/* @internal */ export let ioWriteTime = 0;
|
||||
|
||||
/** The version of the TypeScript compiler release */
|
||||
export const version = "1.9.0";
|
||||
|
||||
const emptyArray: any[] = [];
|
||||
|
||||
const defaultLibrarySearchPaths = [
|
||||
"types/",
|
||||
"node_modules/",
|
||||
"node_modules/@types/",
|
||||
];
|
||||
|
||||
export const version = "1.9.0";
|
||||
const defaultTypeRoots = ["node_modules/@types"];
|
||||
|
||||
export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean): string {
|
||||
while (true) {
|
||||
@@ -95,7 +90,8 @@ namespace ts {
|
||||
return compilerOptions.traceResolution && host.trace !== undefined;
|
||||
}
|
||||
|
||||
function hasZeroOrOneAsteriskCharacter(str: string): boolean {
|
||||
/* @internal */
|
||||
export function hasZeroOrOneAsteriskCharacter(str: string): boolean {
|
||||
let seenAsterisk = false;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
if (str.charCodeAt(i) === CharacterCodes.asterisk) {
|
||||
@@ -182,6 +178,11 @@ namespace ts {
|
||||
|
||||
const typeReferenceExtensions = [".d.ts"];
|
||||
|
||||
function getEffectiveTypeRoots(options: CompilerOptions, host: ModuleResolutionHost) {
|
||||
return options.typeRoots ||
|
||||
map(defaultTypeRoots, d => combinePaths(options.configFilePath ? getDirectoryPath(options.configFilePath) : host.getCurrentDirectory(), d));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | undefined} containingFile - file that contains type reference directive, can be undefined if containing file is unknown.
|
||||
* This is possible in case if resolution is performed for directives specified via 'types' parameter. In this case initial path for secondary lookups
|
||||
@@ -196,24 +197,22 @@ namespace ts {
|
||||
traceEnabled
|
||||
};
|
||||
|
||||
// use typesRoot and fallback to directory that contains tsconfig if typesRoot is not set
|
||||
const rootDir = options.typesRoot || (options.configFilePath ? getDirectoryPath(options.configFilePath) : undefined);
|
||||
|
||||
const typeRoots = getEffectiveTypeRoots(options, host);
|
||||
if (traceEnabled) {
|
||||
if (containingFile === undefined) {
|
||||
if (rootDir === undefined) {
|
||||
if (typeRoots === undefined) {
|
||||
trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_not_set, typeReferenceDirectiveName);
|
||||
}
|
||||
else {
|
||||
trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_1, typeReferenceDirectiveName, rootDir);
|
||||
trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_1, typeReferenceDirectiveName, typeRoots);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (rootDir === undefined) {
|
||||
if (typeRoots === undefined) {
|
||||
trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_not_set, typeReferenceDirectiveName, containingFile);
|
||||
}
|
||||
else {
|
||||
trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_2, typeReferenceDirectiveName, containingFile, rootDir);
|
||||
trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_2, typeReferenceDirectiveName, containingFile, typeRoots);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -221,14 +220,13 @@ namespace ts {
|
||||
const failedLookupLocations: string[] = [];
|
||||
|
||||
// Check primary library paths
|
||||
if (rootDir !== undefined) {
|
||||
const effectivePrimarySearchPaths = options.typesSearchPaths || defaultLibrarySearchPaths;
|
||||
for (const searchPath of effectivePrimarySearchPaths) {
|
||||
const primaryPath = combinePaths(rootDir, searchPath);
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Resolving_with_primary_search_path_0, primaryPath);
|
||||
}
|
||||
const candidate = combinePaths(primaryPath, typeReferenceDirectiveName);
|
||||
if (typeRoots.length) {
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Resolving_with_primary_search_path_0, typeRoots.join(", "));
|
||||
}
|
||||
const primarySearchPaths = typeRoots;
|
||||
for (const typeRoot of primarySearchPaths) {
|
||||
const candidate = combinePaths(typeRoot, typeReferenceDirectiveName);
|
||||
const candidateDirectory = getDirectoryPath(candidate);
|
||||
const resolvedFile = loadNodeModuleFromDirectory(typeReferenceExtensions, candidate, failedLookupLocations,
|
||||
!directoryProbablyExists(candidateDirectory, host), moduleResolutionState);
|
||||
@@ -255,9 +253,6 @@ namespace ts {
|
||||
if (containingFile) {
|
||||
initialLocationForSecondaryLookup = getDirectoryPath(containingFile);
|
||||
}
|
||||
else {
|
||||
initialLocationForSecondaryLookup = rootDir;
|
||||
}
|
||||
|
||||
if (initialLocationForSecondaryLookup !== undefined) {
|
||||
// check secondary locations
|
||||
@@ -496,48 +491,23 @@ namespace ts {
|
||||
trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, state.compilerOptions.baseUrl, moduleName);
|
||||
}
|
||||
|
||||
let longestMatchPrefixLength = -1;
|
||||
let matchedPattern: string;
|
||||
let matchedStar: string;
|
||||
|
||||
// string is for exact match
|
||||
let matchedPattern: Pattern | string | undefined = undefined;
|
||||
if (state.compilerOptions.paths) {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName);
|
||||
}
|
||||
|
||||
for (const key in state.compilerOptions.paths) {
|
||||
const pattern: string = key;
|
||||
const indexOfStar = pattern.indexOf("*");
|
||||
if (indexOfStar !== -1) {
|
||||
const prefix = pattern.substr(0, indexOfStar);
|
||||
const suffix = pattern.substr(indexOfStar + 1);
|
||||
if (moduleName.length >= prefix.length + suffix.length &&
|
||||
startsWith(moduleName, prefix) &&
|
||||
endsWith(moduleName, suffix)) {
|
||||
|
||||
// use length of prefix as betterness criteria
|
||||
if (prefix.length > longestMatchPrefixLength) {
|
||||
longestMatchPrefixLength = prefix.length;
|
||||
matchedPattern = pattern;
|
||||
matchedStar = moduleName.substr(prefix.length, moduleName.length - suffix.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pattern === moduleName) {
|
||||
// pattern was matched as is - no need to search further
|
||||
matchedPattern = pattern;
|
||||
matchedStar = undefined;
|
||||
break;
|
||||
}
|
||||
}
|
||||
matchedPattern = matchPatternOrExact(getKeys(state.compilerOptions.paths), moduleName);
|
||||
}
|
||||
|
||||
if (matchedPattern) {
|
||||
const matchedStar = typeof matchedPattern === "string" ? undefined : matchedText(matchedPattern, moduleName);
|
||||
const matchedPatternText = typeof matchedPattern === "string" ? matchedPattern : patternText(matchedPattern);
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Module_name_0_matched_pattern_1, moduleName, matchedPattern);
|
||||
trace(state.host, Diagnostics.Module_name_0_matched_pattern_1, moduleName, matchedPatternText);
|
||||
}
|
||||
for (const subst of state.compilerOptions.paths[matchedPattern]) {
|
||||
const path = matchedStar ? subst.replace("\*", matchedStar) : subst;
|
||||
for (const subst of state.compilerOptions.paths[matchedPatternText]) {
|
||||
const path = matchedStar ? subst.replace("*", matchedStar) : subst;
|
||||
const candidate = normalizePath(combinePaths(state.compilerOptions.baseUrl, path));
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Trying_substitution_0_candidate_module_location_Colon_1, subst, path);
|
||||
@@ -560,6 +530,75 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* patternStrings contains both pattern strings (containing "*") and regular strings.
|
||||
* Return an exact match if possible, or a pattern match, or undefined.
|
||||
* (These are verified by verifyCompilerOptions to have 0 or 1 "*" characters.)
|
||||
*/
|
||||
function matchPatternOrExact(patternStrings: string[], candidate: string): string | Pattern | undefined {
|
||||
const patterns: Pattern[] = [];
|
||||
for (const patternString of patternStrings) {
|
||||
const pattern = tryParsePattern(patternString);
|
||||
if (pattern) {
|
||||
patterns.push(pattern);
|
||||
}
|
||||
else if (patternString === candidate) {
|
||||
// pattern was matched as is - no need to search further
|
||||
return patternString;
|
||||
}
|
||||
}
|
||||
|
||||
return findBestPatternMatch(patterns, _ => _, candidate);
|
||||
}
|
||||
|
||||
function patternText({prefix, suffix}: Pattern): string {
|
||||
return `${prefix}*${suffix}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given that candidate matches pattern, returns the text matching the '*'.
|
||||
* E.g.: matchedText(tryParsePattern("foo*baz"), "foobarbaz") === "bar"
|
||||
*/
|
||||
function matchedText(pattern: Pattern, candidate: string): string {
|
||||
Debug.assert(isPatternMatch(pattern, candidate));
|
||||
return candidate.substr(pattern.prefix.length, candidate.length - pattern.suffix.length);
|
||||
}
|
||||
|
||||
/** Return the object corresponding to the best pattern to match `candidate`. */
|
||||
/* @internal */
|
||||
export function findBestPatternMatch<T>(values: T[], getPattern: (value: T) => Pattern, candidate: string): T | undefined {
|
||||
let matchedValue: T | undefined = undefined;
|
||||
// use length of prefix as betterness criteria
|
||||
let longestMatchPrefixLength = -1;
|
||||
|
||||
for (const v of values) {
|
||||
const pattern = getPattern(v);
|
||||
if (isPatternMatch(pattern, candidate) && pattern.prefix.length > longestMatchPrefixLength) {
|
||||
longestMatchPrefixLength = pattern.prefix.length;
|
||||
matchedValue = v;
|
||||
}
|
||||
}
|
||||
|
||||
return matchedValue;
|
||||
}
|
||||
|
||||
function isPatternMatch({prefix, suffix}: Pattern, candidate: string) {
|
||||
return candidate.length >= prefix.length + suffix.length &&
|
||||
startsWith(candidate, prefix) &&
|
||||
endsWith(candidate, suffix);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function tryParsePattern(pattern: string): Pattern | undefined {
|
||||
// This should be verified outside of here and a proper error thrown.
|
||||
Debug.assert(hasZeroOrOneAsteriskCharacter(pattern));
|
||||
const indexOfStar = pattern.indexOf("*");
|
||||
return indexOfStar === -1 ? undefined : {
|
||||
prefix: pattern.substr(0, indexOfStar),
|
||||
suffix: pattern.substr(indexOfStar + 1)
|
||||
};
|
||||
}
|
||||
|
||||
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
|
||||
const containingDirectory = getDirectoryPath(containingFile);
|
||||
const supportedExtensions = getSupportedExtensions(compilerOptions);
|
||||
@@ -570,22 +609,29 @@ namespace ts {
|
||||
let resolvedFileName = tryLoadModuleUsingOptionalResolutionSettings(moduleName, containingDirectory, nodeLoadModuleByRelativeName,
|
||||
failedLookupLocations, supportedExtensions, state);
|
||||
|
||||
if (resolvedFileName) {
|
||||
return createResolvedModule(resolvedFileName, /*isExternalLibraryImport*/false, failedLookupLocations);
|
||||
let isExternalLibraryImport = false;
|
||||
if (!resolvedFileName) {
|
||||
if (moduleHasNonRelativeName(moduleName)) {
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Loading_module_0_from_node_modules_folder, moduleName);
|
||||
}
|
||||
resolvedFileName = loadModuleFromNodeModules(moduleName, containingDirectory, failedLookupLocations, state);
|
||||
isExternalLibraryImport = resolvedFileName !== undefined;
|
||||
}
|
||||
else {
|
||||
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
|
||||
resolvedFileName = nodeLoadModuleByRelativeName(candidate, supportedExtensions, failedLookupLocations, /*onlyRecordFailures*/ false, state);
|
||||
}
|
||||
}
|
||||
|
||||
let isExternalLibraryImport = false;
|
||||
if (moduleHasNonRelativeName(moduleName)) {
|
||||
if (resolvedFileName && host.realpath) {
|
||||
const originalFileName = resolvedFileName;
|
||||
resolvedFileName = normalizePath(host.realpath(resolvedFileName));
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Loading_module_0_from_node_modules_folder, moduleName);
|
||||
trace(host, Diagnostics.Resolving_real_path_for_0_result_1, originalFileName, resolvedFileName);
|
||||
}
|
||||
resolvedFileName = loadModuleFromNodeModules(moduleName, containingDirectory, failedLookupLocations, state);
|
||||
isExternalLibraryImport = resolvedFileName !== undefined;
|
||||
}
|
||||
else {
|
||||
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
|
||||
resolvedFileName = nodeLoadModuleByRelativeName(candidate, supportedExtensions, failedLookupLocations, /*onlyRecordFailures*/ false, state);
|
||||
}
|
||||
|
||||
return createResolvedModule(resolvedFileName, isExternalLibraryImport, failedLookupLocations);
|
||||
}
|
||||
|
||||
@@ -612,8 +658,25 @@ namespace ts {
|
||||
* in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations.
|
||||
*/
|
||||
function loadModuleFromFile(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string {
|
||||
// First try to keep/add an extension: importing "./foo.ts" can be matched by a file "./foo.ts", and "./foo" by "./foo.d.ts"
|
||||
const resolvedByAddingOrKeepingExtension = loadModuleFromFileWorker(candidate, extensions, failedLookupLocation, onlyRecordFailures, state);
|
||||
if (resolvedByAddingOrKeepingExtension) {
|
||||
return resolvedByAddingOrKeepingExtension;
|
||||
}
|
||||
// Then try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one, e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts"
|
||||
if (hasJavaScriptFileExtension(candidate)) {
|
||||
const extensionless = removeFileExtension(candidate);
|
||||
if (state.traceEnabled) {
|
||||
const extension = candidate.substring(extensionless.length);
|
||||
trace(state.host, Diagnostics.File_name_0_has_a_1_extension_stripping_it, candidate, extension);
|
||||
}
|
||||
return loadModuleFromFileWorker(extensionless, extensions, failedLookupLocation, onlyRecordFailures, state);
|
||||
}
|
||||
}
|
||||
|
||||
function loadModuleFromFileWorker(candidate: string, extensions: string[], failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string {
|
||||
if (!onlyRecordFailures) {
|
||||
// check if containig folder exists - if it doesn't then just record failures for all supported extensions without disk probing
|
||||
// check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing
|
||||
const directory = getDirectoryPath(candidate);
|
||||
if (directory) {
|
||||
onlyRecordFailures = !directoryProbablyExists(directory, state.host);
|
||||
@@ -622,7 +685,7 @@ namespace ts {
|
||||
return forEach(extensions, tryLoad);
|
||||
|
||||
function tryLoad(ext: string): string {
|
||||
if (ext === ".tsx" && state.skipTsx) {
|
||||
if (state.skipTsx && isJsxOrTsxExtension(ext)) {
|
||||
return undefined;
|
||||
}
|
||||
const fileName = fileExtensionIs(candidate, ext) ? candidate : candidate + ext;
|
||||
@@ -873,6 +936,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const newLine = getNewLineCharacter(options);
|
||||
const realpath = sys.realpath && ((path: string) => sys.realpath(path));
|
||||
|
||||
return {
|
||||
getSourceFile,
|
||||
@@ -886,7 +950,9 @@ namespace ts {
|
||||
fileExists: fileName => sys.fileExists(fileName),
|
||||
readFile: fileName => sys.readFile(fileName),
|
||||
trace: (s: string) => sys.write(s + newLine),
|
||||
directoryExists: directoryName => sys.directoryExists(directoryName)
|
||||
directoryExists: directoryName => sys.directoryExists(directoryName),
|
||||
getDirectories: (path: string) => sys.getDirectories(path),
|
||||
realpath
|
||||
};
|
||||
}
|
||||
|
||||
@@ -949,6 +1015,37 @@ namespace ts {
|
||||
return resolutions;
|
||||
}
|
||||
|
||||
function getInferredTypesRoot(options: CompilerOptions, rootFiles: string[], host: CompilerHost) {
|
||||
return computeCommonSourceDirectoryOfFilenames(rootFiles, host.getCurrentDirectory(), f => host.getCanonicalFileName(f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a set of options and a set of root files, returns the set of type directive names
|
||||
* that should be included for this program automatically.
|
||||
* This list could either come from the config file,
|
||||
* or from enumerating the types root + initial secondary types lookup location.
|
||||
* More type directives might appear in the program later as a result of loading actual source files;
|
||||
* this list is only the set of defaults that are implicitly included.
|
||||
*/
|
||||
export function getAutomaticTypeDirectiveNames(options: CompilerOptions, rootFiles: string[], host: CompilerHost): string[] {
|
||||
// Use explicit type list from tsconfig.json
|
||||
if (options.types) {
|
||||
return options.types;
|
||||
}
|
||||
|
||||
// Walk the primary type lookup locations
|
||||
let result: string[] = [];
|
||||
if (host.directoryExists && host.getDirectories) {
|
||||
const typeRoots = getEffectiveTypeRoots(options, host);
|
||||
for (const root of typeRoots) {
|
||||
if (host.directoryExists(root)) {
|
||||
result = result.concat(host.getDirectories(root));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function createProgram(rootNames: string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program): Program {
|
||||
let program: Program;
|
||||
let files: SourceFile[] = [];
|
||||
@@ -959,15 +1056,16 @@ namespace ts {
|
||||
|
||||
let resolvedTypeReferenceDirectives: Map<ResolvedTypeReferenceDirective> = {};
|
||||
let fileProcessingDiagnostics = createDiagnosticCollection();
|
||||
let skipDefaultLib = options.noLib;
|
||||
const programDiagnostics = createDiagnosticCollection();
|
||||
const currentDirectory = host.getCurrentDirectory();
|
||||
const supportedExtensions = getSupportedExtensions(options);
|
||||
|
||||
const start = new Date().getTime();
|
||||
|
||||
host = host || createCompilerHost(options);
|
||||
|
||||
let skipDefaultLib = options.noLib;
|
||||
const programDiagnostics = createDiagnosticCollection();
|
||||
const currentDirectory = host.getCurrentDirectory();
|
||||
const supportedExtensions = getSupportedExtensions(options);
|
||||
|
||||
// Map storing if there is emit blocking diagnostics for given input
|
||||
const hasEmitBlockingDiagnostics = createFileMap<boolean>(getCanonicalFileName);
|
||||
|
||||
@@ -995,15 +1093,20 @@ namespace ts {
|
||||
const filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? createFileMap<SourceFile>(fileName => fileName.toLowerCase()) : undefined;
|
||||
|
||||
if (!tryReuseStructureFromOldProgram()) {
|
||||
// load type declarations specified via 'types' argument
|
||||
if (options.types && options.types.length) {
|
||||
const resolutions = resolveTypeReferenceDirectiveNamesWorker(options.types, /*containingFile*/ undefined);
|
||||
for (let i = 0; i < options.types.length; i++) {
|
||||
processTypeReferenceDirective(options.types[i], resolutions[i]);
|
||||
forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false));
|
||||
|
||||
// load type declarations specified via 'types' argument or implicitly from types/ and node_modules/@types folders
|
||||
const typeReferences: string[] = getAutomaticTypeDirectiveNames(options, rootNames, host);
|
||||
|
||||
if (typeReferences) {
|
||||
const inferredRoot = getInferredTypesRoot(options, rootNames, host);
|
||||
const containingFilename = combinePaths(inferredRoot, "__inferred type names__.ts");
|
||||
const resolutions = resolveTypeReferenceDirectiveNamesWorker(typeReferences, containingFilename);
|
||||
for (let i = 0; i < typeReferences.length; i++) {
|
||||
processTypeReferenceDirective(typeReferences[i], resolutions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false));
|
||||
// Do not process the default library if:
|
||||
// - The '--noLib' flag is used.
|
||||
// - A 'no-default-lib' reference comment is encountered in
|
||||
@@ -1029,6 +1132,7 @@ namespace ts {
|
||||
program = {
|
||||
getRootFileNames: () => rootNames,
|
||||
getSourceFile,
|
||||
getSourceFileByPath,
|
||||
getSourceFiles: () => files,
|
||||
getCompilerOptions: () => options,
|
||||
getSyntacticDiagnostics,
|
||||
@@ -1047,7 +1151,7 @@ namespace ts {
|
||||
getSymbolCount: () => getDiagnosticsProducingTypeChecker().getSymbolCount(),
|
||||
getTypeCount: () => getDiagnosticsProducingTypeChecker().getTypeCount(),
|
||||
getFileProcessingDiagnostics: () => fileProcessingDiagnostics,
|
||||
resolvedTypeReferenceDirectives
|
||||
getResolvedTypeReferenceDirectives: () => resolvedTypeReferenceDirectives
|
||||
};
|
||||
|
||||
verifyCompilerOptions();
|
||||
@@ -1098,14 +1202,18 @@ namespace ts {
|
||||
// if any of these properties has changed - structure cannot be reused
|
||||
const oldOptions = oldProgram.getCompilerOptions();
|
||||
if ((oldOptions.module !== options.module) ||
|
||||
(oldOptions.moduleResolution !== options.moduleResolution) ||
|
||||
(oldOptions.noResolve !== options.noResolve) ||
|
||||
(oldOptions.target !== options.target) ||
|
||||
(oldOptions.noLib !== options.noLib) ||
|
||||
(oldOptions.jsx !== options.jsx) ||
|
||||
(oldOptions.allowJs !== options.allowJs) ||
|
||||
(oldOptions.rootDir !== options.rootDir) ||
|
||||
(oldOptions.typesSearchPaths !== options.typesSearchPaths) ||
|
||||
(oldOptions.configFilePath !== options.configFilePath)) {
|
||||
(oldOptions.configFilePath !== options.configFilePath) ||
|
||||
(oldOptions.baseUrl !== options.baseUrl) ||
|
||||
!arrayIsEqualTo(oldOptions.typeRoots, oldOptions.typeRoots) ||
|
||||
!arrayIsEqualTo(oldOptions.rootDirs, options.rootDirs) ||
|
||||
!mapIsEqualTo(oldOptions.paths, options.paths)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1127,7 +1235,10 @@ namespace ts {
|
||||
const modifiedSourceFiles: SourceFile[] = [];
|
||||
|
||||
for (const oldSourceFile of oldProgram.getSourceFiles()) {
|
||||
let newSourceFile = host.getSourceFile(oldSourceFile.fileName, options.target);
|
||||
let newSourceFile = host.getSourceFileByPath
|
||||
? host.getSourceFileByPath(oldSourceFile.fileName, oldSourceFile.path, options.target)
|
||||
: host.getSourceFile(oldSourceFile.fileName, options.target);
|
||||
|
||||
if (!newSourceFile) {
|
||||
return false;
|
||||
}
|
||||
@@ -1208,7 +1319,7 @@ namespace ts {
|
||||
for (const modifiedFile of modifiedSourceFiles) {
|
||||
fileProcessingDiagnostics.reattachFileDiagnostics(modifiedFile);
|
||||
}
|
||||
resolvedTypeReferenceDirectives = oldProgram.resolvedTypeReferenceDirectives;
|
||||
resolvedTypeReferenceDirectives = oldProgram.getResolvedTypeReferenceDirectives();
|
||||
oldProgram.structureIsReused = true;
|
||||
|
||||
return true;
|
||||
@@ -1222,6 +1333,7 @@ namespace ts {
|
||||
getCurrentDirectory: () => currentDirectory,
|
||||
getNewLine: () => host.getNewLine(),
|
||||
getSourceFile: program.getSourceFile,
|
||||
getSourceFileByPath: program.getSourceFileByPath,
|
||||
getSourceFiles: program.getSourceFiles,
|
||||
writeFile: writeFileCallback || (
|
||||
(fileName, data, writeByteOrderMark, onError, sourceFiles) => host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles)),
|
||||
@@ -1297,7 +1409,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getSourceFile(fileName: string): SourceFile {
|
||||
return filesByName.get(toPath(fileName, currentDirectory, getCanonicalFileName));
|
||||
return getSourceFileByPath(toPath(fileName, currentDirectory, getCanonicalFileName));
|
||||
}
|
||||
|
||||
function getSourceFileByPath(path: Path): SourceFile {
|
||||
return filesByName.get(path);
|
||||
}
|
||||
|
||||
function getDiagnosticsHelper(
|
||||
@@ -1485,8 +1601,19 @@ namespace ts {
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.property_declarations_can_only_be_used_in_a_ts_file));
|
||||
return true;
|
||||
const propertyDeclaration = <PropertyDeclaration>node;
|
||||
if (propertyDeclaration.modifiers) {
|
||||
for (const modifier of propertyDeclaration.modifiers) {
|
||||
if (modifier.kind !== SyntaxKind.StaticKeyword) {
|
||||
diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (checkTypeAnnotation((<PropertyDeclaration>node).type)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.enum_declarations_can_only_be_used_in_a_ts_file));
|
||||
return true;
|
||||
@@ -1655,9 +1782,12 @@ namespace ts {
|
||||
// The StringLiteral must specify a top - level external module name.
|
||||
// Relative external module names are not permitted
|
||||
|
||||
// NOTE: body of ambient module is always a module block
|
||||
for (const statement of (<ModuleBlock>(<ModuleDeclaration>node).body).statements) {
|
||||
collectModuleReferences(statement, /*inAmbientModule*/ true);
|
||||
// NOTE: body of ambient module is always a module block, if it exists
|
||||
const body = <ModuleBlock>(<ModuleDeclaration>node).body;
|
||||
if (body) {
|
||||
for (const statement of body.statements) {
|
||||
collectModuleReferences(statement, /*inAmbientModule*/ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1739,10 +1869,6 @@ namespace ts {
|
||||
reportFileNamesDifferOnlyInCasingError(fileName, file.fileName, refFile, refPos, refEnd);
|
||||
}
|
||||
|
||||
if (file) {
|
||||
file.wasReferenced = file.wasReferenced || isReference;
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
@@ -1759,7 +1885,6 @@ namespace ts {
|
||||
|
||||
filesByName.set(path, file);
|
||||
if (file) {
|
||||
file.wasReferenced = file.wasReferenced || isReference;
|
||||
file.path = path;
|
||||
|
||||
if (host.useCaseSensitiveFileNames()) {
|
||||
@@ -1852,7 +1977,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
fileProcessingDiagnostics.add(createDiagnostic(refFile, refPos, refEnd, Diagnostics.Cannot_find_name_0, typeReferenceDirective));
|
||||
fileProcessingDiagnostics.add(createDiagnostic(refFile, refPos, refEnd, Diagnostics.Cannot_find_type_definition_file_for_0, typeReferenceDirective));
|
||||
}
|
||||
|
||||
if (saveResolution) {
|
||||
@@ -1885,26 +2010,13 @@ namespace ts {
|
||||
// add file to program only if:
|
||||
// - resolution was successful
|
||||
// - noResolve is falsy
|
||||
// - module name come from the list fo imports
|
||||
// - module name comes from the list of imports
|
||||
const shouldAddFile = resolution &&
|
||||
!options.noResolve &&
|
||||
i < file.imports.length;
|
||||
|
||||
if (shouldAddFile) {
|
||||
const importedFile = findSourceFile(resolution.resolvedFileName, toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName), /*isDefaultLib*/ false, /*isReference*/ false, file, skipTrivia(file.text, file.imports[i].pos), file.imports[i].end);
|
||||
|
||||
if (importedFile && resolution.isExternalLibraryImport) {
|
||||
// Since currently irrespective of allowJs, we only look for supportedTypeScript extension external module files,
|
||||
// this check is ok. Otherwise this would be never true for javascript file
|
||||
if (!isExternalModule(importedFile) && importedFile.statements.length) {
|
||||
const start = getTokenPosOfNode(file.imports[i], file);
|
||||
fileProcessingDiagnostics.add(createFileDiagnostic(file, start, file.imports[i].end - start, Diagnostics.Exported_external_package_typings_file_0_is_not_a_module_Please_contact_the_package_author_to_update_the_package_definition, importedFile.fileName));
|
||||
}
|
||||
else if (importedFile.referencedFiles.length) {
|
||||
const firstRef = importedFile.referencedFiles[0];
|
||||
fileProcessingDiagnostics.add(createFileDiagnostic(importedFile, firstRef.pos, firstRef.end - firstRef.pos, Diagnostics.Exported_external_package_typings_file_cannot_contain_tripleslash_references_Please_contact_the_package_author_to_update_the_package_definition));
|
||||
}
|
||||
}
|
||||
findSourceFile(resolution.resolvedFileName, toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName), /*isDefaultLib*/ false, /*isReference*/ false, file, skipTrivia(file.text, file.imports[i].pos), file.imports[i].end);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1984,20 +2096,31 @@ namespace ts {
|
||||
if (!hasZeroOrOneAsteriskCharacter(key)) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, key));
|
||||
}
|
||||
for (const subst of options.paths[key]) {
|
||||
if (!hasZeroOrOneAsteriskCharacter(subst)) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substitution_0_in_pattern_1_in_can_have_at_most_one_Asterisk_character, subst, key));
|
||||
if (isArray(options.paths[key])) {
|
||||
for (const subst of options.paths[key]) {
|
||||
const typeOfSubst = typeof subst;
|
||||
if (typeOfSubst === "string") {
|
||||
if (!hasZeroOrOneAsteriskCharacter(subst)) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substitution_0_in_pattern_1_in_can_have_at_most_one_Asterisk_character, subst, key));
|
||||
}
|
||||
}
|
||||
else {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substitution_0_for_pattern_1_has_incorrect_type_expected_string_got_2, subst, key, typeOfSubst));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substitutions_for_pattern_0_should_be_an_array, key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (options.inlineSources) {
|
||||
if (!options.sourceMap && !options.inlineSourceMap) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_inlineSources_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided));
|
||||
if (!options.sourceMap && !options.inlineSourceMap) {
|
||||
if (options.inlineSources) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "inlineSources"));
|
||||
}
|
||||
if (options.sourceRoot) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "sourceRoot", "inlineSources"));
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "sourceRoot"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2005,14 +2128,9 @@ namespace ts {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "outFile"));
|
||||
}
|
||||
|
||||
if (!options.sourceMap && (options.mapRoot || options.sourceRoot)) {
|
||||
// Error to specify --mapRoot or --sourceRoot without mapSourceFiles
|
||||
if (options.mapRoot) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "mapRoot", "sourceMap"));
|
||||
}
|
||||
if (options.sourceRoot && !options.inlineSourceMap) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "sourceRoot", "sourceMap"));
|
||||
}
|
||||
if (options.mapRoot && !options.sourceMap) {
|
||||
// Error to specify --mapRoot without --sourcemap
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "mapRoot", "sourceMap"));
|
||||
}
|
||||
|
||||
if (options.declarationDir) {
|
||||
@@ -2046,17 +2164,18 @@ namespace ts {
|
||||
else if (firstExternalModuleSourceFile && languageVersion < ScriptTarget.ES6 && options.module === ModuleKind.None) {
|
||||
// We cannot use createDiagnosticFromNode because nodes do not have parents yet
|
||||
const span = getErrorSpanForNode(firstExternalModuleSourceFile, firstExternalModuleSourceFile.externalModuleIndicator);
|
||||
programDiagnostics.add(createFileDiagnostic(firstExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_modules_unless_the_module_flag_is_provided_with_a_valid_module_type_Consider_setting_the_module_compiler_option_in_a_tsconfig_json_file));
|
||||
}
|
||||
|
||||
// Cannot specify module gen target of es6 when below es6
|
||||
if (options.module === ModuleKind.ES6 && languageVersion < ScriptTarget.ES6) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_compile_modules_into_es2015_when_targeting_ES5_or_lower));
|
||||
programDiagnostics.add(createFileDiagnostic(firstExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_use_imports_exports_or_module_augmentations_when_module_is_none));
|
||||
}
|
||||
|
||||
// Cannot specify module gen that isn't amd or system with --out
|
||||
if (outFile && options.module && !(options.module === ModuleKind.AMD || options.module === ModuleKind.System)) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Only_amd_and_system_modules_are_supported_alongside_0, options.out ? "out" : "outFile"));
|
||||
if (outFile) {
|
||||
if (options.module && !(options.module === ModuleKind.AMD || options.module === ModuleKind.System)) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Only_amd_and_system_modules_are_supported_alongside_0, options.out ? "out" : "outFile"));
|
||||
}
|
||||
else if (options.module === undefined && firstExternalModuleSourceFile) {
|
||||
const span = getErrorSpanForNode(firstExternalModuleSourceFile, firstExternalModuleSourceFile.externalModuleIndicator);
|
||||
programDiagnostics.add(createFileDiagnostic(firstExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_modules_using_option_0_unless_the_module_flag_is_amd_or_system, options.out ? "out" : "outFile"));
|
||||
}
|
||||
}
|
||||
|
||||
// there has to be common source directory if user specified --outdir || --sourceRoot
|
||||
|
||||
@@ -91,6 +91,7 @@ namespace ts {
|
||||
"let": SyntaxKind.LetKeyword,
|
||||
"module": SyntaxKind.ModuleKeyword,
|
||||
"namespace": SyntaxKind.NamespaceKeyword,
|
||||
"never": SyntaxKind.NeverKeyword,
|
||||
"new": SyntaxKind.NewKeyword,
|
||||
"null": SyntaxKind.NullKeyword,
|
||||
"number": SyntaxKind.NumberKeyword,
|
||||
@@ -433,7 +434,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function skipTrivia(text: string, pos: number, stopAfterLineBreak?: boolean): number {
|
||||
export function skipTrivia(text: string, pos: number, stopAfterLineBreak?: boolean, stopAtComments = false): number {
|
||||
// Using ! with a greater than test is a fast way of testing the following conditions:
|
||||
// pos === undefined || pos === null || isNaN(pos) || pos < 0;
|
||||
if (!(pos >= 0)) {
|
||||
@@ -461,6 +462,9 @@ namespace ts {
|
||||
pos++;
|
||||
continue;
|
||||
case CharacterCodes.slash:
|
||||
if (stopAtComments) {
|
||||
break;
|
||||
}
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.slash) {
|
||||
pos += 2;
|
||||
while (pos < text.length) {
|
||||
|
||||
@@ -168,7 +168,7 @@ namespace ts {
|
||||
sourceMapData.sourceMapDecodedMappings[sourceMapData.sourceMapDecodedMappings.length - 1] :
|
||||
defaultLastEncodedSourceMapSpan;
|
||||
|
||||
// TODO: Update lastEncodedNameIndex
|
||||
// TODO: Update lastEncodedNameIndex
|
||||
// Since we dont support this any more, lets not worry about it right now.
|
||||
// When we start supporting nameIndex, we will get back to this
|
||||
|
||||
|
||||
+121
-177
@@ -2,7 +2,12 @@
|
||||
|
||||
namespace ts {
|
||||
export type FileWatcherCallback = (fileName: string, removed?: boolean) => void;
|
||||
export type DirectoryWatcherCallback = (directoryName: string) => void;
|
||||
export type DirectoryWatcherCallback = (fileName: string) => void;
|
||||
export interface WatchedFile {
|
||||
fileName: string;
|
||||
callback: FileWatcherCallback;
|
||||
mtime?: Date;
|
||||
}
|
||||
|
||||
export interface System {
|
||||
args: string[];
|
||||
@@ -10,6 +15,7 @@ namespace ts {
|
||||
useCaseSensitiveFileNames: boolean;
|
||||
write(s: string): void;
|
||||
readFile(path: string, encoding?: string): string;
|
||||
getFileSize?(path: string): number;
|
||||
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
|
||||
watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
|
||||
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
@@ -19,17 +25,13 @@ namespace ts {
|
||||
createDirectory(path: string): void;
|
||||
getExecutingFilePath(): string;
|
||||
getCurrentDirectory(): string;
|
||||
readDirectory(path: string, extension?: string, exclude?: string[]): string[];
|
||||
getDirectories(path: string): string[];
|
||||
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[];
|
||||
getModifiedTime?(path: string): Date;
|
||||
createHash?(data: string): string;
|
||||
getMemoryUsage?(): number;
|
||||
exit(exitCode?: number): void;
|
||||
}
|
||||
|
||||
interface WatchedFile {
|
||||
fileName: string;
|
||||
callback: FileWatcherCallback;
|
||||
mtime?: Date;
|
||||
realpath?(path: string): string;
|
||||
}
|
||||
|
||||
export interface FileWatcher {
|
||||
@@ -71,16 +73,19 @@ namespace ts {
|
||||
resolvePath(path: string): string;
|
||||
readFile(path: string): string;
|
||||
writeFile(path: string, contents: string): void;
|
||||
readDirectory(path: string, extension?: string, exclude?: string[]): string[];
|
||||
getDirectories(path: string): string[];
|
||||
readDirectory(path: string, extensions?: string[], basePaths?: string[], excludeEx?: string, includeFileEx?: string, includeDirEx?: string): string[];
|
||||
watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
|
||||
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
realpath(path: string): string;
|
||||
};
|
||||
|
||||
export var sys: System = (function () {
|
||||
export var sys: System = (function() {
|
||||
|
||||
function getWScriptSystem(): System {
|
||||
|
||||
const fso = new ActiveXObject("Scripting.FileSystemObject");
|
||||
const shell = new ActiveXObject("WScript.Shell");
|
||||
|
||||
const fileStream = new ActiveXObject("ADODB.Stream");
|
||||
fileStream.Type = 2 /*text*/;
|
||||
@@ -148,10 +153,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getCanonicalPath(path: string): string {
|
||||
return path.toLowerCase();
|
||||
}
|
||||
|
||||
function getNames(collection: any): string[] {
|
||||
const result: string[] = [];
|
||||
for (let e = new Enumerator(collection); !e.atEnd(); e.moveNext()) {
|
||||
@@ -160,28 +161,25 @@ namespace ts {
|
||||
return result.sort();
|
||||
}
|
||||
|
||||
function readDirectory(path: string, extension?: string, exclude?: string[]): string[] {
|
||||
const result: string[] = [];
|
||||
exclude = map(exclude, s => getCanonicalPath(combinePaths(path, s)));
|
||||
visitDirectory(path);
|
||||
return result;
|
||||
function visitDirectory(path: string) {
|
||||
function getDirectories(path: string): string[] {
|
||||
const folder = fso.GetFolder(path);
|
||||
return getNames(folder.subfolders);
|
||||
}
|
||||
|
||||
function getAccessibleFileSystemEntries(path: string): FileSystemEntries {
|
||||
try {
|
||||
const folder = fso.GetFolder(path || ".");
|
||||
const files = getNames(folder.files);
|
||||
for (const current of files) {
|
||||
const name = combinePaths(path, current);
|
||||
if ((!extension || fileExtensionIs(name, extension)) && !contains(exclude, getCanonicalPath(name))) {
|
||||
result.push(name);
|
||||
}
|
||||
}
|
||||
const subfolders = getNames(folder.subfolders);
|
||||
for (const current of subfolders) {
|
||||
const name = combinePaths(path, current);
|
||||
if (!contains(exclude, getCanonicalPath(name))) {
|
||||
visitDirectory(name);
|
||||
}
|
||||
}
|
||||
const directories = getNames(folder.subfolders);
|
||||
return { files, directories };
|
||||
}
|
||||
catch (e) {
|
||||
return { files: [], directories: [] };
|
||||
}
|
||||
}
|
||||
|
||||
function readDirectory(path: string, extensions?: string[], excludes?: string[], includes?: string[]): string[] {
|
||||
return matchFiles(path, extensions, excludes, includes, /*useCaseSensitiveFileNames*/ false, shell.CurrentDirectory, getAccessibleFileSystemEntries);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -211,8 +209,9 @@ namespace ts {
|
||||
return WScript.ScriptFullName;
|
||||
},
|
||||
getCurrentDirectory() {
|
||||
return new ActiveXObject("WScript.Shell").CurrentDirectory;
|
||||
return shell.CurrentDirectory;
|
||||
},
|
||||
getDirectories,
|
||||
readDirectory,
|
||||
exit(exitCode?: number): void {
|
||||
try {
|
||||
@@ -230,83 +229,7 @@ namespace ts {
|
||||
const _os = require("os");
|
||||
const _crypto = require("crypto");
|
||||
|
||||
// average async stat takes about 30 microseconds
|
||||
// set chunk size to do 30 files in < 1 millisecond
|
||||
function createPollingWatchedFileSet(interval = 2500, chunkSize = 30) {
|
||||
let watchedFiles: WatchedFile[] = [];
|
||||
let nextFileToCheck = 0;
|
||||
let watchTimer: any;
|
||||
|
||||
function getModifiedTime(fileName: string): Date {
|
||||
return _fs.statSync(fileName).mtime;
|
||||
}
|
||||
|
||||
function poll(checkedIndex: number) {
|
||||
const watchedFile = watchedFiles[checkedIndex];
|
||||
if (!watchedFile) {
|
||||
return;
|
||||
}
|
||||
|
||||
_fs.stat(watchedFile.fileName, (err: any, stats: any) => {
|
||||
if (err) {
|
||||
watchedFile.callback(watchedFile.fileName);
|
||||
}
|
||||
else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) {
|
||||
watchedFile.mtime = getModifiedTime(watchedFile.fileName);
|
||||
watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// this implementation uses polling and
|
||||
// stat due to inconsistencies of fs.watch
|
||||
// and efficiency of stat on modern filesystems
|
||||
function startWatchTimer() {
|
||||
watchTimer = setInterval(() => {
|
||||
let count = 0;
|
||||
let nextToCheck = nextFileToCheck;
|
||||
let firstCheck = -1;
|
||||
while ((count < chunkSize) && (nextToCheck !== firstCheck)) {
|
||||
poll(nextToCheck);
|
||||
if (firstCheck < 0) {
|
||||
firstCheck = nextToCheck;
|
||||
}
|
||||
nextToCheck++;
|
||||
if (nextToCheck === watchedFiles.length) {
|
||||
nextToCheck = 0;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
nextFileToCheck = nextToCheck;
|
||||
}, interval);
|
||||
}
|
||||
|
||||
function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile {
|
||||
const file: WatchedFile = {
|
||||
fileName,
|
||||
callback,
|
||||
mtime: getModifiedTime(fileName)
|
||||
};
|
||||
|
||||
watchedFiles.push(file);
|
||||
if (watchedFiles.length === 1) {
|
||||
startWatchTimer();
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
function removeFile(file: WatchedFile) {
|
||||
watchedFiles = copyListRemovingItem(file, watchedFiles);
|
||||
}
|
||||
|
||||
return {
|
||||
getModifiedTime: getModifiedTime,
|
||||
poll: poll,
|
||||
startWatchTimer: startWatchTimer,
|
||||
addFile: addFile,
|
||||
removeFile: removeFile
|
||||
};
|
||||
}
|
||||
const useNonPollingWatchers = process.env["TSC_NONPOLLING_WATCHER"];
|
||||
|
||||
function createWatchedFileSet() {
|
||||
const dirWatchers: Map<DirectoryWatcher> = {};
|
||||
@@ -389,26 +312,11 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// REVIEW: for now this implementation uses polling.
|
||||
// The advantage of polling is that it works reliably
|
||||
// on all os and with network mounted files.
|
||||
// For 90 referenced files, the average time to detect
|
||||
// changes is 2*msInterval (by default 5 seconds).
|
||||
// The overhead of this is .04 percent (1/2500) with
|
||||
// average pause of < 1 millisecond (and max
|
||||
// pause less than 1.5 milliseconds); question is
|
||||
// do we anticipate reference sets in the 100s and
|
||||
// do we care about waiting 10-20 seconds to detect
|
||||
// changes for large reference sets? If so, do we want
|
||||
// to increase the chunk size or decrease the interval
|
||||
// time dynamically to match the large reference set?
|
||||
const pollingWatchedFileSet = createPollingWatchedFileSet();
|
||||
const watchedFileSet = createWatchedFileSet();
|
||||
|
||||
function isNode4OrLater(): boolean {
|
||||
return parseInt(process.version.charAt(1)) >= 4;
|
||||
}
|
||||
return parseInt(process.version.charAt(1)) >= 4;
|
||||
}
|
||||
|
||||
const platform: string = _os.platform();
|
||||
// win32\win64 are case insensitive platforms, MacOS (darwin) by default is also case insensitive
|
||||
@@ -462,8 +370,43 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getCanonicalPath(path: string): string {
|
||||
return useCaseSensitiveFileNames ? path : path.toLowerCase();
|
||||
function getAccessibleFileSystemEntries(path: string): FileSystemEntries {
|
||||
try {
|
||||
const entries = _fs.readdirSync(path || ".").sort();
|
||||
const files: string[] = [];
|
||||
const directories: string[] = [];
|
||||
for (const entry of entries) {
|
||||
// This is necessary because on some file system node fails to exclude
|
||||
// "." and "..". See https://github.com/nodejs/node/issues/4002
|
||||
if (entry === "." || entry === "..") {
|
||||
continue;
|
||||
}
|
||||
const name = combinePaths(path, entry);
|
||||
|
||||
let stat: any;
|
||||
try {
|
||||
stat = _fs.statSync(name);
|
||||
}
|
||||
catch (e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (stat.isFile()) {
|
||||
files.push(entry);
|
||||
}
|
||||
else if (stat.isDirectory()) {
|
||||
directories.push(entry);
|
||||
}
|
||||
}
|
||||
return { files, directories };
|
||||
}
|
||||
catch (e) {
|
||||
return { files: [], directories: [] };
|
||||
}
|
||||
}
|
||||
|
||||
function readDirectory(path: string, extensions?: string[], excludes?: string[], includes?: string[]): string[] {
|
||||
return matchFiles(path, extensions, excludes, includes, useCaseSensitiveFileNames, process.cwd(), getAccessibleFileSystemEntries);
|
||||
}
|
||||
|
||||
const enum FileSystemEntryKind {
|
||||
@@ -492,37 +435,8 @@ namespace ts {
|
||||
return fileSystemEntryExists(path, FileSystemEntryKind.Directory);
|
||||
}
|
||||
|
||||
function readDirectory(path: string, extension?: string, exclude?: string[]): string[] {
|
||||
const result: string[] = [];
|
||||
exclude = map(exclude, s => getCanonicalPath(combinePaths(path, s)));
|
||||
visitDirectory(path);
|
||||
return result;
|
||||
function visitDirectory(path: string) {
|
||||
const files = _fs.readdirSync(path || ".").sort();
|
||||
const directories: string[] = [];
|
||||
for (const current of files) {
|
||||
// This is necessary because on some file system node fails to exclude
|
||||
// "." and "..". See https://github.com/nodejs/node/issues/4002
|
||||
if (current === "." || current === "..") {
|
||||
continue;
|
||||
}
|
||||
const name = combinePaths(path, current);
|
||||
if (!contains(exclude, getCanonicalPath(name))) {
|
||||
const stat = _fs.statSync(name);
|
||||
if (stat.isFile()) {
|
||||
if (!extension || fileExtensionIs(name, extension)) {
|
||||
result.push(name);
|
||||
}
|
||||
}
|
||||
else if (stat.isDirectory()) {
|
||||
directories.push(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const current of directories) {
|
||||
visitDirectory(current);
|
||||
}
|
||||
}
|
||||
function getDirectories(path: string): string[] {
|
||||
return filter<string>(_fs.readdirSync(path), p => fileSystemEntryExists(combinePaths(path, p), FileSystemEntryKind.Directory));
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -535,15 +449,26 @@ namespace ts {
|
||||
readFile,
|
||||
writeFile,
|
||||
watchFile: (fileName, callback) => {
|
||||
// Node 4.0 stabilized the `fs.watch` function on Windows which avoids polling
|
||||
// and is more efficient than `fs.watchFile` (ref: https://github.com/nodejs/node/pull/2649
|
||||
// and https://github.com/Microsoft/TypeScript/issues/4643), therefore
|
||||
// if the current node.js version is newer than 4, use `fs.watch` instead.
|
||||
const watchSet = isNode4OrLater() ? watchedFileSet : pollingWatchedFileSet;
|
||||
const watchedFile = watchSet.addFile(fileName, callback);
|
||||
return {
|
||||
close: () => watchSet.removeFile(watchedFile)
|
||||
};
|
||||
if (useNonPollingWatchers) {
|
||||
const watchedFile = watchedFileSet.addFile(fileName, callback);
|
||||
return {
|
||||
close: () => watchedFileSet.removeFile(watchedFile)
|
||||
};
|
||||
}
|
||||
else {
|
||||
_fs.watchFile(fileName, { persistent: true, interval: 250 }, fileChanged);
|
||||
return {
|
||||
close: () => _fs.unwatchFile(fileName, fileChanged)
|
||||
};
|
||||
}
|
||||
|
||||
function fileChanged(curr: any, prev: any) {
|
||||
if (+curr.mtime <= +prev.mtime) {
|
||||
return;
|
||||
}
|
||||
|
||||
callback(fileName);
|
||||
}
|
||||
},
|
||||
watchDirectory: (directoryName, callback, recursive) => {
|
||||
// Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows
|
||||
@@ -570,7 +495,7 @@ namespace ts {
|
||||
}
|
||||
);
|
||||
},
|
||||
resolvePath: function (path: string): string {
|
||||
resolvePath: function(path: string): string {
|
||||
return _path.resolve(path);
|
||||
},
|
||||
fileExists,
|
||||
@@ -586,6 +511,7 @@ namespace ts {
|
||||
getCurrentDirectory() {
|
||||
return process.cwd();
|
||||
},
|
||||
getDirectories,
|
||||
readDirectory,
|
||||
getModifiedTime(path) {
|
||||
try {
|
||||
@@ -606,14 +532,27 @@ namespace ts {
|
||||
}
|
||||
return process.memoryUsage().heapUsed;
|
||||
},
|
||||
getFileSize(path) {
|
||||
try {
|
||||
const stat = _fs.statSync(path);
|
||||
if (stat.isFile()) {
|
||||
return stat.size;
|
||||
}
|
||||
}
|
||||
catch (e) { }
|
||||
return 0;
|
||||
},
|
||||
exit(exitCode?: number): void {
|
||||
process.exit(exitCode);
|
||||
},
|
||||
realpath(path: string): string {
|
||||
return _fs.realpathSync(path);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getChakraSystem(): System {
|
||||
|
||||
const realpath = ChakraHost.realpath && ((path: string) => ChakraHost.realpath(path));
|
||||
return {
|
||||
newLine: ChakraHost.newLine || "\r\n",
|
||||
args: ChakraHost.args,
|
||||
@@ -637,12 +576,20 @@ namespace ts {
|
||||
createDirectory: ChakraHost.createDirectory,
|
||||
getExecutingFilePath: () => ChakraHost.executingFile,
|
||||
getCurrentDirectory: () => ChakraHost.currentDirectory,
|
||||
readDirectory: ChakraHost.readDirectory,
|
||||
getDirectories: ChakraHost.getDirectories,
|
||||
readDirectory: (path: string, extensions?: string[], excludes?: string[], includes?: string[]) => {
|
||||
const pattern = getFileMatcherPatterns(path, extensions, excludes, includes, !!ChakraHost.useCaseSensitiveFileNames, ChakraHost.currentDirectory);
|
||||
return ChakraHost.readDirectory(path, extensions, pattern.basePaths, pattern.excludePattern, pattern.includeFilePattern, pattern.includeDirectoryPattern);
|
||||
},
|
||||
exit: ChakraHost.quit,
|
||||
realpath
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof WScript !== "undefined" && typeof ActiveXObject === "function") {
|
||||
if (typeof ChakraHost !== "undefined") {
|
||||
return getChakraSystem();
|
||||
}
|
||||
else if (typeof WScript !== "undefined" && typeof ActiveXObject === "function") {
|
||||
return getWScriptSystem();
|
||||
}
|
||||
else if (typeof process !== "undefined" && process.nextTick && !process.browser && typeof require !== "undefined") {
|
||||
@@ -650,9 +597,6 @@ namespace ts {
|
||||
// process.browser check excludes webpack and browserify
|
||||
return getNodeSystem();
|
||||
}
|
||||
else if (typeof ChakraHost !== "undefined") {
|
||||
return getChakraSystem();
|
||||
}
|
||||
else {
|
||||
return undefined; // Unsupported host
|
||||
}
|
||||
|
||||
+18
-8
@@ -44,11 +44,9 @@ namespace ts {
|
||||
const territory = matchResult[3];
|
||||
|
||||
// First try the entire locale, then fall back to just language if that's all we have.
|
||||
if (!trySetLanguageAndTerritory(language, territory, errors) &&
|
||||
!trySetLanguageAndTerritory(language, undefined, errors)) {
|
||||
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Unsupported_locale_0, locale));
|
||||
return false;
|
||||
// Either ways do not fail, and fallback to the English diagnostic strings.
|
||||
if (!trySetLanguageAndTerritory(language, territory, errors)) {
|
||||
trySetLanguageAndTerritory(language, undefined, errors);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -393,9 +391,21 @@ namespace ts {
|
||||
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
return;
|
||||
}
|
||||
if (isWatchSet(configParseResult.options) && !sys.watchFile) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"), /* compilerHost */ undefined);
|
||||
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
if (isWatchSet(configParseResult.options)) {
|
||||
if (!sys.watchFile) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"), /* compilerHost */ undefined);
|
||||
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
}
|
||||
|
||||
if (!directoryWatcher && sys.watchDirectory && configFileName) {
|
||||
const directory = ts.getDirectoryPath(configFileName);
|
||||
directoryWatcher = sys.watchDirectory(
|
||||
// When the configFileName is just "tsconfig.json", the watched directory should be
|
||||
// the current directory; if there is a given "project" parameter, then the configFileName
|
||||
// is an absolute file name.
|
||||
directory == "" ? "." : directory,
|
||||
watchedDirectoryChanged, /*recursive*/ true);
|
||||
};
|
||||
}
|
||||
return configParseResult;
|
||||
}
|
||||
|
||||
@@ -3,22 +3,26 @@
|
||||
"noImplicitAny": true,
|
||||
"removeComments": true,
|
||||
"preserveConstEnums": true,
|
||||
"out": "../../built/local/tsc.js",
|
||||
"sourceMap": true
|
||||
"outFile": "../../built/local/tsc.js",
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"stripInternal": true
|
||||
},
|
||||
"files": [
|
||||
"types.ts",
|
||||
"core.ts",
|
||||
"sys.ts",
|
||||
"diagnosticInformationMap.generated.ts",
|
||||
"types.ts",
|
||||
"scanner.ts",
|
||||
"parser.ts",
|
||||
"utilities.ts",
|
||||
"binder.ts",
|
||||
"checker.ts",
|
||||
"sourcemap.ts",
|
||||
"declarationEmitter.ts",
|
||||
"emitter.ts",
|
||||
"program.ts",
|
||||
"commandLineParser.ts",
|
||||
"tsc.ts"
|
||||
"tsc.ts",
|
||||
"diagnosticInformationMap.generated.ts"
|
||||
]
|
||||
}
|
||||
|
||||
+212
-80
@@ -164,6 +164,7 @@ namespace ts {
|
||||
IsKeyword,
|
||||
ModuleKeyword,
|
||||
NamespaceKeyword,
|
||||
NeverKeyword,
|
||||
ReadonlyKeyword,
|
||||
RequireKeyword,
|
||||
NumberKeyword,
|
||||
@@ -276,7 +277,7 @@ namespace ts {
|
||||
ModuleDeclaration,
|
||||
ModuleBlock,
|
||||
CaseBlock,
|
||||
GlobalModuleExportDeclaration,
|
||||
NamespaceExportDeclaration,
|
||||
ImportEqualsDeclaration,
|
||||
ImportDeclaration,
|
||||
ImportClause,
|
||||
@@ -342,6 +343,9 @@ namespace ts {
|
||||
JSDocReturnTag,
|
||||
JSDocTypeTag,
|
||||
JSDocTemplateTag,
|
||||
JSDocTypedefTag,
|
||||
JSDocPropertyTag,
|
||||
JSDocTypeLiteral,
|
||||
|
||||
// Synthesized list
|
||||
SyntaxList,
|
||||
@@ -371,6 +375,10 @@ namespace ts {
|
||||
FirstBinaryOperator = LessThanToken,
|
||||
LastBinaryOperator = CaretEqualsToken,
|
||||
FirstNode = QualifiedName,
|
||||
FirstJSDocNode = JSDocTypeExpression,
|
||||
LastJSDocNode = JSDocTypeLiteral,
|
||||
FirstJSDocTagNode = JSDocComment,
|
||||
LastJSDocTagNode = JSDocTypeLiteral
|
||||
}
|
||||
|
||||
export const enum NodeFlags {
|
||||
@@ -407,12 +415,15 @@ namespace ts {
|
||||
HasAggregatedChildData = 1 << 29, // If we've computed data from children and cached it in this node
|
||||
HasJsxSpreadAttribute = 1 << 30,
|
||||
|
||||
Modifier = Export | Ambient | Public | Private | Protected | Static | Abstract | Default | Async,
|
||||
Modifier = Export | Ambient | Public | Private | Protected | Static | Abstract | Default | Async | Readonly,
|
||||
AccessibilityModifier = Public | Private | Protected,
|
||||
// Accessibility modifiers and 'readonly' can be attached to a parameter in a constructor to make it a property.
|
||||
ParameterPropertyModifier = AccessibilityModifier | Readonly,
|
||||
BlockScoped = Let | Const,
|
||||
|
||||
ReachabilityCheckFlags = HasImplicitReturn | HasExplicitReturn,
|
||||
EmitHelperFlags = HasClassExtends | HasDecorators | HasParamDecorators | HasAsyncFunctions,
|
||||
ReachabilityAndEmitFlags = ReachabilityCheckFlags | EmitHelperFlags,
|
||||
|
||||
// Parsing context flags
|
||||
ContextFlags = DisallowInContext | YieldContext | DecoratorContext | AwaitContext | JavaScriptFile,
|
||||
@@ -445,11 +456,12 @@ namespace ts {
|
||||
modifiers?: ModifiersArray; // Array of modifiers
|
||||
/* @internal */ id?: number; // Unique id (used to look up NodeLinks)
|
||||
parent?: Node; // Parent node (initialized by binding
|
||||
/* @internal */ jsDocComment?: JSDocComment; // JSDoc for the node, if it has any. Only for .js files.
|
||||
/* @internal */ jsDocComments?: JSDocComment[]; // JSDoc for the node, if it has any. Only for .js files.
|
||||
/* @internal */ symbol?: Symbol; // Symbol declared by node (initialized by binding)
|
||||
/* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding)
|
||||
/* @internal */ nextContainer?: Node; // Next container in declaration order (initialized by binding)
|
||||
/* @internal */ localSymbol?: Symbol; // Local symbol declared by node (initialized by binding only for exported nodes)
|
||||
/* @internal */ flowNode?: FlowNode; // Associated FlowNode (initialized by binding)
|
||||
}
|
||||
|
||||
export interface NodeArray<T> extends Array<T>, TextRange {
|
||||
@@ -478,11 +490,6 @@ namespace ts {
|
||||
originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later
|
||||
}
|
||||
|
||||
// Transient identifier node (marked by id === -1)
|
||||
export interface TransientIdentifier extends Identifier {
|
||||
resolvedSymbol: Symbol;
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.QualifiedName)
|
||||
export interface QualifiedName extends Node {
|
||||
// Must have same layout as PropertyAccess
|
||||
@@ -613,6 +620,7 @@ namespace ts {
|
||||
// SyntaxKind.PropertyAssignment
|
||||
// SyntaxKind.ShorthandPropertyAssignment
|
||||
// SyntaxKind.EnumMember
|
||||
// SyntaxKind.JSDocPropertyTag
|
||||
export interface VariableLikeDeclaration extends Declaration {
|
||||
propertyName?: PropertyName;
|
||||
dotDotDotToken?: Node;
|
||||
@@ -972,7 +980,6 @@ namespace ts {
|
||||
// @kind(SyntaxKind.PropertyAccessExpression)
|
||||
export interface PropertyAccessExpression extends MemberExpression, Declaration {
|
||||
expression: LeftHandSideExpression;
|
||||
dotToken: Node;
|
||||
name: Identifier;
|
||||
}
|
||||
|
||||
@@ -1035,11 +1042,13 @@ namespace ts {
|
||||
closingElement: JsxClosingElement;
|
||||
}
|
||||
|
||||
export type JsxTagNameExpression = PrimaryExpression | PropertyAccessExpression;
|
||||
|
||||
/// The opening element of a <Tag>...</Tag> JsxElement
|
||||
// @kind(SyntaxKind.JsxOpeningElement)
|
||||
export interface JsxOpeningElement extends Expression {
|
||||
_openingElementBrand?: any;
|
||||
tagName: EntityName;
|
||||
tagName: JsxTagNameExpression;
|
||||
attributes: NodeArray<JsxAttribute | JsxSpreadAttribute>;
|
||||
}
|
||||
|
||||
@@ -1066,7 +1075,7 @@ namespace ts {
|
||||
|
||||
// @kind(SyntaxKind.JsxClosingElement)
|
||||
export interface JsxClosingElement extends Node {
|
||||
tagName: EntityName;
|
||||
tagName: JsxTagNameExpression;
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.JsxExpression)
|
||||
@@ -1180,6 +1189,7 @@ namespace ts {
|
||||
export interface SwitchStatement extends Statement {
|
||||
expression: Expression;
|
||||
caseBlock: CaseBlock;
|
||||
possiblyExhaustive?: boolean;
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.CaseBlock)
|
||||
@@ -1293,7 +1303,7 @@ namespace ts {
|
||||
// @kind(SyntaxKind.ModuleDeclaration)
|
||||
export interface ModuleDeclaration extends DeclarationStatement {
|
||||
name: Identifier | LiteralExpression;
|
||||
body: ModuleBlock | ModuleDeclaration;
|
||||
body?: ModuleBlock | ModuleDeclaration;
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.ModuleBlock)
|
||||
@@ -1342,8 +1352,8 @@ namespace ts {
|
||||
name: Identifier;
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.GlobalModuleImport)
|
||||
export interface GlobalModuleExportDeclaration extends DeclarationStatement {
|
||||
// @kind(SyntaxKind.NamespaceExportDeclaration)
|
||||
export interface NamespaceExportDeclaration extends DeclarationStatement {
|
||||
name: Identifier;
|
||||
moduleReference: LiteralLikeNode;
|
||||
}
|
||||
@@ -1511,6 +1521,25 @@ namespace ts {
|
||||
typeExpression: JSDocTypeExpression;
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.JSDocTypedefTag)
|
||||
export interface JSDocTypedefTag extends JSDocTag, Declaration {
|
||||
name?: Identifier;
|
||||
typeExpression?: JSDocTypeExpression;
|
||||
jsDocTypeLiteral?: JSDocTypeLiteral;
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.JSDocPropertyTag)
|
||||
export interface JSDocPropertyTag extends JSDocTag, TypeElement {
|
||||
name: Identifier;
|
||||
typeExpression: JSDocTypeExpression;
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.JSDocTypeLiteral)
|
||||
export interface JSDocTypeLiteral extends JSDocType {
|
||||
jsDocPropertyTags?: NodeArray<JSDocPropertyTag>;
|
||||
jsDocTypeTag?: JSDocTypeTag;
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.JSDocParameterTag)
|
||||
export interface JSDocParameterTag extends JSDocTag {
|
||||
preParameterName?: Identifier;
|
||||
@@ -1519,6 +1548,59 @@ namespace ts {
|
||||
isBracketed: boolean;
|
||||
}
|
||||
|
||||
export const enum FlowFlags {
|
||||
Unreachable = 1 << 0, // Unreachable code
|
||||
Start = 1 << 1, // Start of flow graph
|
||||
BranchLabel = 1 << 2, // Non-looping junction
|
||||
LoopLabel = 1 << 3, // Looping junction
|
||||
Assignment = 1 << 4, // Assignment
|
||||
TrueCondition = 1 << 5, // Condition known to be true
|
||||
FalseCondition = 1 << 6, // Condition known to be false
|
||||
SwitchClause = 1 << 7, // Switch statement clause
|
||||
Referenced = 1 << 8, // Referenced as antecedent once
|
||||
Shared = 1 << 9, // Referenced as antecedent more than once
|
||||
Label = BranchLabel | LoopLabel,
|
||||
Condition = TrueCondition | FalseCondition
|
||||
}
|
||||
|
||||
export interface FlowNode {
|
||||
flags: FlowFlags;
|
||||
id?: number; // Node id used by flow type cache in checker
|
||||
}
|
||||
|
||||
// FlowStart represents the start of a control flow. For a function expression or arrow
|
||||
// function, the container property references the function (which in turn has a flowNode
|
||||
// property for the containing control flow).
|
||||
export interface FlowStart extends FlowNode {
|
||||
container?: FunctionExpression | ArrowFunction;
|
||||
}
|
||||
|
||||
// FlowLabel represents a junction with multiple possible preceding control flows.
|
||||
export interface FlowLabel extends FlowNode {
|
||||
antecedents: FlowNode[];
|
||||
}
|
||||
|
||||
// FlowAssignment represents a node that assigns a value to a narrowable reference,
|
||||
// i.e. an identifier or a dotted name that starts with an identifier or 'this'.
|
||||
export interface FlowAssignment extends FlowNode {
|
||||
node: Expression | VariableDeclaration | BindingElement;
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
|
||||
// FlowCondition represents a condition that is known to be true or false at the
|
||||
// node's location in the control flow.
|
||||
export interface FlowCondition extends FlowNode {
|
||||
expression: Expression;
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
|
||||
export interface FlowSwitchClause extends FlowNode {
|
||||
switchStatement: SwitchStatement;
|
||||
clauseStart: number; // Start index of case/default clause range
|
||||
clauseEnd: number; // End index of case/default clause range
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
|
||||
export interface AmdDependency {
|
||||
path: string;
|
||||
name: string;
|
||||
@@ -1562,8 +1644,6 @@ namespace ts {
|
||||
/* @internal */ externalModuleIndicator: Node;
|
||||
// The first node that causes this file to be a CommonJS module
|
||||
/* @internal */ commonJsModuleIndicator: Node;
|
||||
// True if the file was a root file in a compilation or a /// reference targets
|
||||
/* @internal */ wasReferenced?: boolean;
|
||||
|
||||
/* @internal */ identifiers: Map<string>;
|
||||
/* @internal */ nodeCount: number;
|
||||
@@ -1588,16 +1668,26 @@ namespace ts {
|
||||
/* @internal */ resolvedTypeReferenceDirectiveNames: Map<ResolvedTypeReferenceDirective>;
|
||||
/* @internal */ imports: LiteralExpression[];
|
||||
/* @internal */ moduleAugmentations: LiteralExpression[];
|
||||
/* @internal */ patternAmbientModules?: PatternAmbientModule[];
|
||||
}
|
||||
|
||||
export interface ScriptReferenceHost {
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
getSourceFile(fileName: string): SourceFile;
|
||||
getSourceFileByPath(path: Path): SourceFile;
|
||||
getCurrentDirectory(): string;
|
||||
}
|
||||
|
||||
export interface ParseConfigHost {
|
||||
readDirectory(rootDir: string, extension: string, exclude: string[]): string[];
|
||||
useCaseSensitiveFileNames: boolean;
|
||||
|
||||
readDirectory(rootDir: string, extensions: string[], excludes: string[], includes: string[]): string[];
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether the specified path exists and is a file.
|
||||
* @param path The path to test.
|
||||
*/
|
||||
fileExists(path: string): boolean;
|
||||
}
|
||||
|
||||
export interface WriteFileCallback {
|
||||
@@ -1662,7 +1752,7 @@ namespace ts {
|
||||
/* @internal */ getTypeCount(): number;
|
||||
|
||||
/* @internal */ getFileProcessingDiagnostics(): DiagnosticCollection;
|
||||
/* @internal */ resolvedTypeReferenceDirectives: Map<ResolvedTypeReferenceDirective>;
|
||||
/* @internal */ getResolvedTypeReferenceDirectives(): Map<ResolvedTypeReferenceDirective>;
|
||||
// For testing purposes only.
|
||||
/* @internal */ structureIsReused?: boolean;
|
||||
}
|
||||
@@ -1723,6 +1813,7 @@ namespace ts {
|
||||
|
||||
getSourceFiles(): SourceFile[];
|
||||
getSourceFile(fileName: string): SourceFile;
|
||||
getResolvedTypeReferenceDirectives(): Map<ResolvedTypeReferenceDirective>;
|
||||
}
|
||||
|
||||
export interface TypeChecker {
|
||||
@@ -1734,12 +1825,14 @@ namespace ts {
|
||||
getIndexTypeOfType(type: Type, kind: IndexKind): Type;
|
||||
getBaseTypes(type: InterfaceType): ObjectType[];
|
||||
getReturnTypeOfSignature(signature: Signature): Type;
|
||||
getNonNullableType(type: Type): Type;
|
||||
|
||||
getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[];
|
||||
getSymbolAtLocation(node: Node): Symbol;
|
||||
getSymbolsOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: string): Symbol[];
|
||||
getShorthandAssignmentValueSymbol(location: Node): Symbol;
|
||||
getExportSpecifierLocalTargetSymbol(location: ExportSpecifier): Symbol;
|
||||
getPropertySymbolOfDestructuringAssignment(location: Identifier): Symbol;
|
||||
getTypeAtLocation(node: Node): Type;
|
||||
typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string;
|
||||
symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string;
|
||||
@@ -1783,7 +1876,7 @@ namespace ts {
|
||||
buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
|
||||
buildTypePredicateDisplay(predicate: TypePredicate, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
|
||||
buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
|
||||
buildDisplayForParametersAndDelimiters(thisType: Type, parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
|
||||
buildDisplayForParametersAndDelimiters(thisParameter: Symbol, parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
|
||||
buildDisplayForTypeParametersAndDelimiters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
|
||||
buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
|
||||
}
|
||||
@@ -1818,6 +1911,7 @@ namespace ts {
|
||||
WriteTypeArgumentsOfSignature = 0x00000020, // Write the type arguments instead of type parameters of the signature
|
||||
InElementType = 0x00000040, // Writing an array or union element type
|
||||
UseFullyQualifiedType = 0x00000080, // Write out the fully qualified type name (eg. Module.Type, instead of Type)
|
||||
InFirstTypeArgument = 0x00000100, // Writing first type argument of the instantiated type
|
||||
}
|
||||
|
||||
export const enum SymbolFormatFlags {
|
||||
@@ -1930,6 +2024,8 @@ namespace ts {
|
||||
moduleExportsSomeValue(moduleReferenceExpression: Expression): boolean;
|
||||
isArgumentsLocalBinding(node: Identifier): boolean;
|
||||
getExternalModuleFileFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration): SourceFile;
|
||||
getTypeReferenceDirectivesForEntityName(name: EntityName | PropertyAccessExpression): string[];
|
||||
getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): string[];
|
||||
}
|
||||
|
||||
export const enum SymbolFlags {
|
||||
@@ -1983,7 +2079,7 @@ namespace ts {
|
||||
BlockScopedVariableExcludes = Value,
|
||||
|
||||
ParameterExcludes = Value,
|
||||
PropertyExcludes = Value,
|
||||
PropertyExcludes = None,
|
||||
EnumMemberExcludes = Value,
|
||||
FunctionExcludes = Value & ~(Function | ValueModule),
|
||||
ClassExcludes = (Value | Type) & ~(ValueModule | Interface), // class-interface mergability done in checker.ts
|
||||
@@ -2026,11 +2122,13 @@ namespace ts {
|
||||
members?: SymbolTable; // Class, interface or literal instance members
|
||||
exports?: SymbolTable; // Module exports
|
||||
globalExports?: SymbolTable; // Conditional global UMD exports
|
||||
/* @internal */ isReadonly?: boolean; // readonly? (set only for intersections and unions)
|
||||
/* @internal */ id?: number; // Unique id (used to look up SymbolLinks)
|
||||
/* @internal */ mergeId?: number; // Merge id (used to look up merged symbol)
|
||||
/* @internal */ parent?: Symbol; // Parent symbol
|
||||
/* @internal */ exportSymbol?: Symbol; // Exported symbol associated with this symbol
|
||||
/* @internal */ constEnumOnlyModule?: boolean; // True if module contains only const enums or other modules with only const enums
|
||||
/* @internal */ hasReference?: boolean; // True if the symbol is referenced elsewhere
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -2049,8 +2147,6 @@ namespace ts {
|
||||
isDeclarationWithCollidingName?: boolean; // True if symbol is block scoped redeclaration
|
||||
bindingElement?: BindingElement; // Binding element associated with property symbol
|
||||
exportsSomeValue?: boolean; // True if module exports some value (not just types)
|
||||
firstAssignmentChecked?: boolean; // True if first assignment node has been computed
|
||||
firstAssignment?: Node; // First assignment node (undefined if no assignments)
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -2060,6 +2156,20 @@ namespace ts {
|
||||
[index: string]: Symbol;
|
||||
}
|
||||
|
||||
/** Represents a "prefix*suffix" pattern. */
|
||||
/* @internal */
|
||||
export interface Pattern {
|
||||
prefix: string;
|
||||
suffix: string;
|
||||
}
|
||||
|
||||
/** Used to track a `declare module "foo*"`-like declaration. */
|
||||
/* @internal */
|
||||
export interface PatternAmbientModule {
|
||||
pattern: Pattern;
|
||||
symbol: Symbol;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export const enum NodeCheckFlags {
|
||||
TypeChecked = 0x00000001, // Node has been type checked
|
||||
@@ -2084,22 +2194,18 @@ namespace ts {
|
||||
/* @internal */
|
||||
export interface NodeLinks {
|
||||
resolvedType?: Type; // Cached type of type node
|
||||
resolvedAwaitedType?: Type; // Cached awaited type of type node
|
||||
resolvedSignature?: Signature; // Cached signature of signature node or call expression
|
||||
resolvedSymbol?: Symbol; // Cached name resolution result
|
||||
resolvedIndexInfo?: IndexInfo; // Cached indexing info resolution result
|
||||
flags?: NodeCheckFlags; // Set of flags specific to Node
|
||||
enumMemberValue?: number; // Constant value of enum member
|
||||
isVisible?: boolean; // Is this node visible
|
||||
generatedName?: string; // Generated name for module, enum, or import declaration
|
||||
generatedNames?: Map<string>; // Generated names table for source file
|
||||
assignmentMap?: Map<boolean>; // Cached map of references assigned within this node
|
||||
hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context
|
||||
importOnRightSide?: Symbol; // for import declarations - import that appear on the right side
|
||||
jsxFlags?: JsxFlags; // flags for knowing what kind of element/attributes we're dealing with
|
||||
resolvedJsxType?: Type; // resolved element attributes type of a JSX openinglike element
|
||||
hasSuperCall?: boolean; // recorded result when we try to find super-call. We only try to find one if this flag is undefined, indicating that we haven't made an attempt.
|
||||
superCall?: ExpressionStatement; // Cached first super-call found in the constructor. Used in checking whether super is called before this-accessing
|
||||
superCall?: ExpressionStatement; // Cached first super-call found in the constructor. Used in checking whether super is called before this-accessing
|
||||
switchTypes?: Type[]; // Cached array of switch case expression types
|
||||
}
|
||||
|
||||
export const enum TypeFlags {
|
||||
@@ -2127,7 +2233,7 @@ namespace ts {
|
||||
/* @internal */
|
||||
FreshObjectLiteral = 0x00100000, // Fresh object literal type
|
||||
/* @internal */
|
||||
ContainsUndefinedOrNull = 0x00200000, // Type is or contains undefined or null type
|
||||
ContainsWideningType = 0x00200000, // Type is or contains undefined or null widening type
|
||||
/* @internal */
|
||||
ContainsObjectLiteral = 0x00400000, // Type is or contains object literal type
|
||||
/* @internal */
|
||||
@@ -2135,11 +2241,14 @@ namespace ts {
|
||||
ESSymbol = 0x01000000, // Type of symbol primitive introduced in ES6
|
||||
ThisType = 0x02000000, // This type
|
||||
ObjectLiteralPatternWithComputedProperties = 0x04000000, // Object literal type implied by binding pattern has computed properties
|
||||
Never = 0x08000000, // Never type
|
||||
|
||||
/* @internal */
|
||||
Nullable = Undefined | Null,
|
||||
/* @internal */
|
||||
Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null,
|
||||
Falsy = Void | Undefined | Null, // TODO: Add false, 0, and ""
|
||||
/* @internal */
|
||||
Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null | Never,
|
||||
/* @internal */
|
||||
Primitive = String | Number | Boolean | ESSymbol | Void | Undefined | Null | StringLiteral | Enum,
|
||||
StringLike = String | StringLiteral,
|
||||
@@ -2147,10 +2256,14 @@ namespace ts {
|
||||
ObjectType = Class | Interface | Reference | Tuple | Anonymous,
|
||||
UnionOrIntersection = Union | Intersection,
|
||||
StructuredType = ObjectType | Union | Intersection,
|
||||
|
||||
// 'Narrowable' types are types where narrowing actually narrows.
|
||||
// This *should* be every type other than null, undefined, void, and never
|
||||
Narrowable = Any | StructuredType | TypeParameter | StringLike | NumberLike | Boolean | ESSymbol,
|
||||
/* @internal */
|
||||
RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral,
|
||||
RequiresWidening = ContainsWideningType | ContainsObjectLiteral,
|
||||
/* @internal */
|
||||
PropagatingFlags = ContainsUndefinedOrNull | ContainsObjectLiteral | ContainsAnyFunctionType
|
||||
PropagatingFlags = ContainsWideningType | ContainsObjectLiteral | ContainsAnyFunctionType
|
||||
}
|
||||
|
||||
export type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression;
|
||||
@@ -2285,7 +2398,8 @@ namespace ts {
|
||||
declaration: SignatureDeclaration; // Originating declaration
|
||||
typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic)
|
||||
parameters: Symbol[]; // Parameters
|
||||
thisType?: Type; // type of this-type
|
||||
/* @internal */
|
||||
thisParameter?: Symbol; // symbol of this-type parameter
|
||||
/* @internal */
|
||||
resolvedReturnType: Type; // Resolved return type
|
||||
/* @internal */
|
||||
@@ -2408,90 +2522,86 @@ namespace ts {
|
||||
export type CompilerOptionsValue = string | number | boolean | (string | number)[] | TsConfigOnlyOptions;
|
||||
|
||||
export interface CompilerOptions {
|
||||
allowNonTsExtensions?: boolean;
|
||||
allowJs?: boolean;
|
||||
/*@internal*/ allowNonTsExtensions?: boolean;
|
||||
allowSyntheticDefaultImports?: boolean;
|
||||
allowUnreachableCode?: boolean;
|
||||
allowUnusedLabels?: boolean;
|
||||
baseUrl?: string;
|
||||
charset?: string;
|
||||
/* @internal */ configFilePath?: string;
|
||||
declaration?: boolean;
|
||||
declarationDir?: string;
|
||||
diagnostics?: boolean;
|
||||
/* @internal */ diagnostics?: boolean;
|
||||
emitBOM?: boolean;
|
||||
help?: boolean;
|
||||
init?: boolean;
|
||||
emitDecoratorMetadata?: boolean;
|
||||
experimentalDecorators?: boolean;
|
||||
forceConsistentCasingInFileNames?: boolean;
|
||||
/*@internal*/help?: boolean;
|
||||
/*@internal*/init?: boolean;
|
||||
inlineSourceMap?: boolean;
|
||||
inlineSources?: boolean;
|
||||
isolatedModules?: boolean;
|
||||
jsx?: JsxEmit;
|
||||
reactNamespace?: string;
|
||||
listFiles?: boolean;
|
||||
typesSearchPaths?: string[];
|
||||
lib?: string[];
|
||||
/*@internal*/listEmittedFiles?: boolean;
|
||||
/*@internal*/listFiles?: boolean;
|
||||
locale?: string;
|
||||
mapRoot?: string;
|
||||
module?: ModuleKind;
|
||||
moduleResolution?: ModuleResolutionKind;
|
||||
newLine?: NewLineKind;
|
||||
noEmit?: boolean;
|
||||
noEmitHelpers?: boolean;
|
||||
noEmitOnError?: boolean;
|
||||
noErrorTruncation?: boolean;
|
||||
noFallthroughCasesInSwitch?: boolean;
|
||||
noImplicitAny?: boolean;
|
||||
noImplicitReturns?: boolean;
|
||||
noImplicitThis?: boolean;
|
||||
noUnusedLocals?: boolean;
|
||||
noUnusedParameters?: boolean;
|
||||
noImplicitUseStrict?: boolean;
|
||||
noLib?: boolean;
|
||||
noResolve?: boolean;
|
||||
out?: string;
|
||||
outFile?: string;
|
||||
outDir?: string;
|
||||
outFile?: string;
|
||||
paths?: PathSubstitutions;
|
||||
preserveConstEnums?: boolean;
|
||||
/* @internal */ pretty?: DiagnosticStyle;
|
||||
project?: string;
|
||||
/* @internal */ pretty?: DiagnosticStyle;
|
||||
reactNamespace?: string;
|
||||
removeComments?: boolean;
|
||||
rootDir?: string;
|
||||
rootDirs?: RootPaths;
|
||||
skipLibCheck?: boolean;
|
||||
skipDefaultLibCheck?: boolean;
|
||||
sourceMap?: boolean;
|
||||
sourceRoot?: string;
|
||||
strictNullChecks?: boolean;
|
||||
/* @internal */ stripInternal?: boolean;
|
||||
suppressExcessPropertyErrors?: boolean;
|
||||
suppressImplicitAnyIndexErrors?: boolean;
|
||||
target?: ScriptTarget;
|
||||
version?: boolean;
|
||||
watch?: boolean;
|
||||
isolatedModules?: boolean;
|
||||
experimentalDecorators?: boolean;
|
||||
emitDecoratorMetadata?: boolean;
|
||||
moduleResolution?: ModuleResolutionKind;
|
||||
allowUnusedLabels?: boolean;
|
||||
allowUnreachableCode?: boolean;
|
||||
noImplicitReturns?: boolean;
|
||||
noFallthroughCasesInSwitch?: boolean;
|
||||
forceConsistentCasingInFileNames?: boolean;
|
||||
baseUrl?: string;
|
||||
paths?: PathSubstitutions;
|
||||
rootDirs?: RootPaths;
|
||||
traceResolution?: boolean;
|
||||
allowSyntheticDefaultImports?: boolean;
|
||||
allowJs?: boolean;
|
||||
noImplicitUseStrict?: boolean;
|
||||
strictNullChecks?: boolean;
|
||||
listEmittedFiles?: boolean;
|
||||
lib?: string[];
|
||||
/* @internal */ stripInternal?: boolean;
|
||||
|
||||
// Skip checking lib.d.ts to help speed up tests.
|
||||
/* @internal */ skipDefaultLibCheck?: boolean;
|
||||
// Do not perform validation of output file name in transpile scenarios
|
||||
/* @internal */ suppressOutputPathCheck?: boolean;
|
||||
|
||||
/* @internal */
|
||||
// When options come from a config file, its path is recorded here
|
||||
configFilePath?: string;
|
||||
/* @internal */
|
||||
// Path used to used to compute primary search locations
|
||||
typesRoot?: string;
|
||||
target?: ScriptTarget;
|
||||
traceResolution?: boolean;
|
||||
disableSizeLimit?: boolean;
|
||||
types?: string[];
|
||||
/** Paths used to used to compute primary types search locations */
|
||||
typeRoots?: string[];
|
||||
typesSearchPaths?: string[];
|
||||
/*@internal*/ version?: boolean;
|
||||
/*@internal*/ watch?: boolean;
|
||||
|
||||
list?: string[];
|
||||
[option: string]: CompilerOptionsValue;
|
||||
[option: string]: CompilerOptionsValue | undefined;
|
||||
}
|
||||
|
||||
export interface TypingOptions {
|
||||
enableAutoDiscovery?: boolean;
|
||||
include?: string[];
|
||||
exclude?: string[];
|
||||
[option: string]: string[] | boolean;
|
||||
[option: string]: string[] | boolean | undefined;
|
||||
}
|
||||
|
||||
export interface DiscoverTypingsInfo {
|
||||
@@ -2563,7 +2673,19 @@ namespace ts {
|
||||
options: CompilerOptions;
|
||||
typingOptions?: TypingOptions;
|
||||
fileNames: string[];
|
||||
raw?: any;
|
||||
errors: Diagnostic[];
|
||||
wildcardDirectories?: Map<WatchDirectoryFlags>;
|
||||
}
|
||||
|
||||
export const enum WatchDirectoryFlags {
|
||||
None = 0,
|
||||
Recursive = 1 << 0,
|
||||
}
|
||||
|
||||
export interface ExpandResult {
|
||||
fileNames: string[];
|
||||
wildcardDirectories: Map<WatchDirectoryFlags>;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -2746,6 +2868,8 @@ namespace ts {
|
||||
readFile(fileName: string): string;
|
||||
trace?(s: string): void;
|
||||
directoryExists?(directoryName: string): boolean;
|
||||
realpath?(path: string): string;
|
||||
getCurrentDirectory?(): string;
|
||||
}
|
||||
|
||||
export interface ResolvedModule {
|
||||
@@ -2778,11 +2902,14 @@ namespace ts {
|
||||
|
||||
export interface CompilerHost extends ModuleResolutionHost {
|
||||
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile;
|
||||
getSourceFileByPath?(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile;
|
||||
getCancellationToken?(): CancellationToken;
|
||||
getDefaultLibFileName(options: CompilerOptions): string;
|
||||
getDefaultLibLocation?(): string;
|
||||
getDefaultTypeDirectiveNames?(rootPath: string): string[];
|
||||
writeFile: WriteFileCallback;
|
||||
getCurrentDirectory(): string;
|
||||
getDirectories(path: string): string[];
|
||||
getCanonicalFileName(fileName: string): string;
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
getNewLine(): string;
|
||||
@@ -2796,7 +2923,7 @@ namespace ts {
|
||||
*/
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string): ResolvedModule[];
|
||||
/**
|
||||
* This method is a companion for 'resolveModuleNames' and is used to resolve 'types' references to actual type declaration files
|
||||
* This method is a companion for 'resolveModuleNames' and is used to resolve 'types' references to actual type declaration files
|
||||
*/
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
}
|
||||
@@ -2832,4 +2959,9 @@ namespace ts {
|
||||
|
||||
/* @internal */ reattachFileDiagnostics(newFile: SourceFile): void;
|
||||
}
|
||||
|
||||
// SyntaxKind.SyntaxList
|
||||
export interface SyntaxList extends Node {
|
||||
_children: Node[];
|
||||
}
|
||||
}
|
||||
|
||||
+188
-48
@@ -84,6 +84,25 @@ namespace ts {
|
||||
return node.end - node.pos;
|
||||
}
|
||||
|
||||
export function mapIsEqualTo<T>(map1: Map<T>, map2: Map<T>): boolean {
|
||||
if (!map1 || !map2) {
|
||||
return map1 === map2;
|
||||
}
|
||||
return containsAll(map1, map2) && containsAll(map2, map1);
|
||||
}
|
||||
|
||||
function containsAll<T>(map: Map<T>, other: Map<T>): boolean {
|
||||
for (const key in map) {
|
||||
if (!hasProperty(map, key)) {
|
||||
continue;
|
||||
}
|
||||
if (!hasProperty(other, key) || map[key] !== other[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function arrayIsEqualTo<T>(array1: T[], array2: T[], equaler?: (a: T, b: T) => boolean): boolean {
|
||||
if (!array1 || !array2) {
|
||||
return array1 === array2;
|
||||
@@ -268,16 +287,36 @@ namespace ts {
|
||||
return !nodeIsMissing(node);
|
||||
}
|
||||
|
||||
export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile): number {
|
||||
export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile, includeJsDocComment?: boolean): number {
|
||||
// With nodes that have no width (i.e. 'Missing' nodes), we actually *don't*
|
||||
// want to skip trivia because this will launch us forward to the next token.
|
||||
if (nodeIsMissing(node)) {
|
||||
return node.pos;
|
||||
}
|
||||
|
||||
if (isJSDocNode(node)) {
|
||||
return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos, /*stopAfterLineBreak*/ false, /*stopAtComments*/ true);
|
||||
}
|
||||
|
||||
if (includeJsDocComment && node.jsDocComments && node.jsDocComments.length > 0) {
|
||||
return getTokenPosOfNode(node.jsDocComments[0]);
|
||||
}
|
||||
|
||||
// For a syntax list, it is possible that one of its children has JSDocComment nodes, while
|
||||
// the syntax list itself considers them as normal trivia. Therefore if we simply skip
|
||||
// trivia for the list, we may have skipped the JSDocComment as well. So we should process its
|
||||
// first child to determine the actual position of its first token.
|
||||
if (node.kind === SyntaxKind.SyntaxList && (<SyntaxList>node)._children.length > 0) {
|
||||
return getTokenPosOfNode((<SyntaxList>node)._children[0], sourceFile, includeJsDocComment);
|
||||
}
|
||||
|
||||
return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos);
|
||||
}
|
||||
|
||||
export function isJSDocNode(node: Node) {
|
||||
return node.kind >= SyntaxKind.FirstJSDocNode && node.kind <= SyntaxKind.LastJSDocNode;
|
||||
}
|
||||
|
||||
export function getNonDecoratorTokenPosOfNode(node: Node, sourceFile?: SourceFile): number {
|
||||
if (nodeIsMissing(node) || !node.decorators) {
|
||||
return getTokenPosOfNode(node, sourceFile);
|
||||
@@ -333,6 +372,11 @@ namespace ts {
|
||||
((<ModuleDeclaration>node).name.kind === SyntaxKind.StringLiteral || isGlobalScopeAugmentation(<ModuleDeclaration>node));
|
||||
}
|
||||
|
||||
export function isShorthandAmbientModule(node: Node): boolean {
|
||||
// The only kind of module that can be missing a body is a shorthand ambient module.
|
||||
return node.kind === SyntaxKind.ModuleDeclaration && (!(<ModuleDeclaration>node).body);
|
||||
}
|
||||
|
||||
export function isBlockScopedContainerTopLevel(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.SourceFile ||
|
||||
node.kind === SyntaxKind.ModuleDeclaration ||
|
||||
@@ -435,7 +479,7 @@ namespace ts {
|
||||
const { line: startLine } = getLineAndCharacterOfPosition(sourceFile, node.body.pos);
|
||||
const { line: endLine } = getLineAndCharacterOfPosition(sourceFile, node.body.end);
|
||||
if (startLine < endLine) {
|
||||
// The arrow function spans multiple lines,
|
||||
// The arrow function spans multiple lines,
|
||||
// make the error span be the first line, inclusive.
|
||||
return createTextSpan(pos, getEndLinePosition(startLine, sourceFile) - pos + 1);
|
||||
}
|
||||
@@ -564,9 +608,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function getJsDocCommentsFromText(node: Node, text: string) {
|
||||
const commentRanges = (node.kind === SyntaxKind.Parameter || node.kind === SyntaxKind.TypeParameter) ?
|
||||
concatenate(getTrailingCommentRanges(text, node.pos),
|
||||
getLeadingCommentRanges(text, node.pos)) :
|
||||
const commentRanges = (node.kind === SyntaxKind.Parameter ||
|
||||
node.kind === SyntaxKind.TypeParameter ||
|
||||
node.kind === SyntaxKind.FunctionExpression ||
|
||||
node.kind === SyntaxKind.ArrowFunction) ?
|
||||
concatenate(getTrailingCommentRanges(text, node.pos), getLeadingCommentRanges(text, node.pos)) :
|
||||
getLeadingCommentRangesOfNodeFromText(node, text);
|
||||
return filter(commentRanges, isJsDocComment);
|
||||
|
||||
@@ -594,6 +640,7 @@ namespace ts {
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
case SyntaxKind.SymbolKeyword:
|
||||
case SyntaxKind.UndefinedKeyword:
|
||||
case SyntaxKind.NeverKeyword:
|
||||
return true;
|
||||
case SyntaxKind.VoidKeyword:
|
||||
return node.parent.kind !== SyntaxKind.VoidExpression;
|
||||
@@ -783,6 +830,8 @@ namespace ts {
|
||||
case SyntaxKind.ConstructorType:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function introducesArgumentsExoticObject(node: Node) {
|
||||
@@ -958,6 +1007,20 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function getImmediatelyInvokedFunctionExpression(func: Node): CallExpression {
|
||||
if (func.kind === SyntaxKind.FunctionExpression || func.kind === SyntaxKind.ArrowFunction) {
|
||||
let prev = func;
|
||||
let parent = func.parent;
|
||||
while (parent.kind === SyntaxKind.ParenthesizedExpression) {
|
||||
prev = parent;
|
||||
parent = parent.parent;
|
||||
}
|
||||
if (parent.kind === SyntaxKind.CallExpression && (parent as CallExpression).expression === prev) {
|
||||
return parent as CallExpression;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a node is a property or element access expression for super.
|
||||
*/
|
||||
@@ -1047,6 +1110,7 @@ namespace ts {
|
||||
|
||||
export function isExpression(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ThisKeyword:
|
||||
case SyntaxKind.SuperKeyword:
|
||||
case SyntaxKind.NullKeyword:
|
||||
case SyntaxKind.TrueKeyword:
|
||||
@@ -1196,6 +1260,22 @@ namespace ts {
|
||||
return isRequire && (!checkArgumentIsStringLiteral || (<CallExpression>expression).arguments[0].kind === SyntaxKind.StringLiteral);
|
||||
}
|
||||
|
||||
export function isSingleOrDoubleQuote(charCode: number) {
|
||||
return charCode === CharacterCodes.singleQuote || charCode === CharacterCodes.doubleQuote;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the node is a variable declaration whose initializer is a function expression.
|
||||
* This function does not test if the node is in a JavaScript file or not.
|
||||
*/
|
||||
export function isDeclarationOfFunctionExpression(s: Symbol) {
|
||||
if (s.valueDeclaration && s.valueDeclaration.kind === SyntaxKind.VariableDeclaration) {
|
||||
const declaration = s.valueDeclaration as VariableDeclaration;
|
||||
return declaration.initializer && declaration.initializer.kind === SyntaxKind.FunctionExpression;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Given a BinaryExpression, returns SpecialPropertyAssignmentKind for the various kinds of property
|
||||
/// assignments we treat as special in the binder
|
||||
export function getSpecialPropertyAssignmentKind(expression: Node): SpecialPropertyAssignmentKind {
|
||||
@@ -1227,8 +1307,15 @@ namespace ts {
|
||||
else if (lhs.expression.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
// chained dot, e.g. x.y.z = expr; this var is the 'x.y' part
|
||||
const innerPropertyAccess = <PropertyAccessExpression>lhs.expression;
|
||||
if (innerPropertyAccess.expression.kind === SyntaxKind.Identifier && innerPropertyAccess.name.text === "prototype") {
|
||||
return SpecialPropertyAssignmentKind.PrototypeProperty;
|
||||
if (innerPropertyAccess.expression.kind === SyntaxKind.Identifier) {
|
||||
// module.exports.name = expr
|
||||
const innerPropertyAccessIdentifier = <Identifier>innerPropertyAccess.expression;
|
||||
if (innerPropertyAccessIdentifier.text === "module" && innerPropertyAccess.name.text === "exports") {
|
||||
return SpecialPropertyAssignmentKind.ExportsProperty;
|
||||
}
|
||||
if (innerPropertyAccess.name.text === "prototype") {
|
||||
return SpecialPropertyAssignmentKind.PrototypeProperty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1281,26 +1368,28 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const jsDocComment = getJSDocComment(node, checkParentVariableStatement);
|
||||
if (!jsDocComment) {
|
||||
const jsDocComments = getJSDocComments(node, checkParentVariableStatement);
|
||||
if (!jsDocComments) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
for (const tag of jsDocComment.tags) {
|
||||
if (tag.kind === kind) {
|
||||
return tag;
|
||||
for (const jsDocComment of jsDocComments) {
|
||||
for (const tag of jsDocComment.tags) {
|
||||
if (tag.kind === kind) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getJSDocComment(node: Node, checkParentVariableStatement: boolean): JSDocComment {
|
||||
if (node.jsDocComment) {
|
||||
return node.jsDocComment;
|
||||
function getJSDocComments(node: Node, checkParentVariableStatement: boolean): JSDocComment[] {
|
||||
if (node.jsDocComments) {
|
||||
return node.jsDocComments;
|
||||
}
|
||||
// Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement.
|
||||
// /**
|
||||
// Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement.
|
||||
// /**
|
||||
// * @param {number} name
|
||||
// * @returns {number}
|
||||
// * @returns {number}
|
||||
// */
|
||||
// var x = function(name) { return name.length; }
|
||||
if (checkParentVariableStatement) {
|
||||
@@ -1311,7 +1400,7 @@ namespace ts {
|
||||
|
||||
const variableStatementNode = isInitializerOfVariableDeclarationInStatement ? node.parent.parent.parent : undefined;
|
||||
if (variableStatementNode) {
|
||||
return variableStatementNode.jsDocComment;
|
||||
return variableStatementNode.jsDocComments;
|
||||
}
|
||||
|
||||
// Also recognize when the node is the RHS of an assignment expression
|
||||
@@ -1322,12 +1411,12 @@ namespace ts {
|
||||
(parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken &&
|
||||
parent.parent.kind === SyntaxKind.ExpressionStatement;
|
||||
if (isSourceOfAssignmentExpressionStatement) {
|
||||
return parent.parent.jsDocComment;
|
||||
return parent.parent.jsDocComments;
|
||||
}
|
||||
|
||||
const isPropertyAssignmentExpression = parent && parent.kind === SyntaxKind.PropertyAssignment;
|
||||
if (isPropertyAssignmentExpression) {
|
||||
return parent.jsDocComment;
|
||||
return parent.jsDocComments;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1352,14 +1441,16 @@ namespace ts {
|
||||
// annotation.
|
||||
const parameterName = (<Identifier>parameter.name).text;
|
||||
|
||||
const jsDocComment = getJSDocComment(parameter.parent, /*checkParentVariableStatement*/ true);
|
||||
if (jsDocComment) {
|
||||
for (const tag of jsDocComment.tags) {
|
||||
if (tag.kind === SyntaxKind.JSDocParameterTag) {
|
||||
const parameterTag = <JSDocParameterTag>tag;
|
||||
const name = parameterTag.preParameterName || parameterTag.postParameterName;
|
||||
if (name.text === parameterName) {
|
||||
return parameterTag;
|
||||
const jsDocComments = getJSDocComments(parameter.parent, /*checkParentVariableStatement*/ true);
|
||||
if (jsDocComments) {
|
||||
for (const jsDocComment of jsDocComments) {
|
||||
for (const tag of jsDocComment.tags) {
|
||||
if (tag.kind === SyntaxKind.JSDocParameterTag) {
|
||||
const parameterTag = <JSDocParameterTag>tag;
|
||||
const name = parameterTag.preParameterName || parameterTag.postParameterName;
|
||||
if (name.text === parameterName) {
|
||||
return parameterTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1373,23 +1464,26 @@ namespace ts {
|
||||
return isRestParameter(lastOrUndefined(s.parameters));
|
||||
}
|
||||
|
||||
export function isRestParameter(node: ParameterDeclaration) {
|
||||
if (node) {
|
||||
if (node.flags & NodeFlags.JavaScriptFile) {
|
||||
if (node.type && node.type.kind === SyntaxKind.JSDocVariadicType) {
|
||||
return true;
|
||||
}
|
||||
export function hasDeclaredRestParameter(s: SignatureDeclaration): boolean {
|
||||
return isDeclaredRestParam(lastOrUndefined(s.parameters));
|
||||
}
|
||||
|
||||
const paramTag = getCorrespondingJSDocParameterTag(node);
|
||||
if (paramTag && paramTag.typeExpression) {
|
||||
return paramTag.typeExpression.type.kind === SyntaxKind.JSDocVariadicType;
|
||||
}
|
||||
export function isRestParameter(node: ParameterDeclaration) {
|
||||
if (node && (node.flags & NodeFlags.JavaScriptFile)) {
|
||||
if (node.type && node.type.kind === SyntaxKind.JSDocVariadicType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return node.dotDotDotToken !== undefined;
|
||||
const paramTag = getCorrespondingJSDocParameterTag(node);
|
||||
if (paramTag && paramTag.typeExpression) {
|
||||
return paramTag.typeExpression.type.kind === SyntaxKind.JSDocVariadicType;
|
||||
}
|
||||
}
|
||||
return isDeclaredRestParam(node);
|
||||
}
|
||||
|
||||
return false;
|
||||
export function isDeclaredRestParam(node: ParameterDeclaration) {
|
||||
return node && node.dotDotDotToken !== undefined;
|
||||
}
|
||||
|
||||
export function isLiteralKind(kind: SyntaxKind): boolean {
|
||||
@@ -1408,6 +1502,31 @@ namespace ts {
|
||||
return !!node && (node.kind === SyntaxKind.ArrayBindingPattern || node.kind === SyntaxKind.ObjectBindingPattern);
|
||||
}
|
||||
|
||||
// A node is an assignment target if it is on the left hand side of an '=' token, if it is parented by a property
|
||||
// assignment in an object literal that is an assignment target, or if it is parented by an array literal that is
|
||||
// an assignment target. Examples include 'a = xxx', '{ p: a } = xxx', '[{ p: a}] = xxx'.
|
||||
export function isAssignmentTarget(node: Node): boolean {
|
||||
while (node.parent.kind === SyntaxKind.ParenthesizedExpression) {
|
||||
node = node.parent;
|
||||
}
|
||||
while (true) {
|
||||
const parent = node.parent;
|
||||
if (parent.kind === SyntaxKind.ArrayLiteralExpression || parent.kind === SyntaxKind.SpreadElementExpression) {
|
||||
node = parent;
|
||||
continue;
|
||||
}
|
||||
if (parent.kind === SyntaxKind.PropertyAssignment || parent.kind === SyntaxKind.ShorthandPropertyAssignment) {
|
||||
node = parent.parent;
|
||||
continue;
|
||||
}
|
||||
return parent.kind === SyntaxKind.BinaryExpression &&
|
||||
(<BinaryExpression>parent).operatorToken.kind === SyntaxKind.EqualsToken &&
|
||||
(<BinaryExpression>parent).left === node ||
|
||||
(parent.kind === SyntaxKind.ForInStatement || parent.kind === SyntaxKind.ForOfStatement) &&
|
||||
(<ForInStatement | ForOfStatement>parent).initializer === node;
|
||||
}
|
||||
}
|
||||
|
||||
export function isNodeDescendentOf(node: Node, ancestor: Node): boolean {
|
||||
while (node) {
|
||||
if (node === ancestor) return true;
|
||||
@@ -1456,6 +1575,7 @@ namespace ts {
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.TypeParameter:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1504,7 +1624,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// True if the given identifier, string literal, or number literal is the name of a declaration node
|
||||
export function isDeclarationName(name: Node): name is Identifier | StringLiteral | LiteralExpression {
|
||||
export function isDeclarationName(name: Node): boolean {
|
||||
if (name.kind !== SyntaxKind.Identifier && name.kind !== SyntaxKind.StringLiteral && name.kind !== SyntaxKind.NumericLiteral) {
|
||||
return false;
|
||||
}
|
||||
@@ -1523,6 +1643,12 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isLiteralComputedPropertyDeclarationName(node: Node) {
|
||||
return (node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NumericLiteral) &&
|
||||
node.parent.kind === SyntaxKind.ComputedPropertyName &&
|
||||
isDeclaration(node.parent.parent);
|
||||
}
|
||||
|
||||
// Return true if the given identifier is classified as an IdentifierName
|
||||
export function isIdentifierName(node: Identifier): boolean {
|
||||
let parent = node.parent;
|
||||
@@ -1568,7 +1694,7 @@ namespace ts {
|
||||
// export default ...
|
||||
export function isAliasSymbolDeclaration(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.ImportEqualsDeclaration ||
|
||||
node.kind === SyntaxKind.GlobalModuleExportDeclaration ||
|
||||
node.kind === SyntaxKind.NamespaceExportDeclaration ||
|
||||
node.kind === SyntaxKind.ImportClause && !!(<ImportClause>node).name ||
|
||||
node.kind === SyntaxKind.NamespaceImport ||
|
||||
node.kind === SyntaxKind.ImportSpecifier ||
|
||||
@@ -1576,7 +1702,7 @@ namespace ts {
|
||||
node.kind === SyntaxKind.ExportAssignment && (<ExportAssignment>node).expression.kind === SyntaxKind.Identifier;
|
||||
}
|
||||
|
||||
export function getClassExtendsHeritageClauseElement(node: ClassLikeDeclaration) {
|
||||
export function getClassExtendsHeritageClauseElement(node: ClassLikeDeclaration | InterfaceDeclaration) {
|
||||
const heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ExtendsKeyword);
|
||||
return heritageClause && heritageClause.types.length > 0 ? heritageClause.types[0] : undefined;
|
||||
}
|
||||
@@ -1699,7 +1825,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function getPropertyNameForPropertyNameNode(name: DeclarationName): string {
|
||||
if (name.kind === SyntaxKind.Identifier || name.kind === SyntaxKind.StringLiteral || name.kind === SyntaxKind.NumericLiteral) {
|
||||
if (name.kind === SyntaxKind.Identifier || name.kind === SyntaxKind.StringLiteral || name.kind === SyntaxKind.NumericLiteral || name.kind === SyntaxKind.Parameter) {
|
||||
return (<Identifier | LiteralExpression>name).text;
|
||||
}
|
||||
if (name.kind === SyntaxKind.ComputedPropertyName) {
|
||||
@@ -1708,6 +1834,9 @@ namespace ts {
|
||||
const rightHandSideName = (<PropertyAccessExpression>nameExpression).name.text;
|
||||
return getPropertyNameForKnownSymbolName(rightHandSideName);
|
||||
}
|
||||
else if (nameExpression.kind === SyntaxKind.StringLiteral || nameExpression.kind === SyntaxKind.NumericLiteral) {
|
||||
return (<LiteralExpression>nameExpression).text;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
@@ -2201,7 +2330,9 @@ namespace ts {
|
||||
|
||||
export function getSourceFilePathInNewDir(sourceFile: SourceFile, host: EmitHost, newDirPath: string) {
|
||||
let sourceFilePath = getNormalizedAbsolutePath(sourceFile.fileName, host.getCurrentDirectory());
|
||||
sourceFilePath = sourceFilePath.replace(host.getCommonSourceDirectory(), "");
|
||||
const commonSourceDirectory = host.getCommonSourceDirectory();
|
||||
const isSourceFileInCommonSourceDirectory = host.getCanonicalFileName(sourceFilePath).indexOf(host.getCanonicalFileName(commonSourceDirectory)) === 0;
|
||||
sourceFilePath = isSourceFileInCommonSourceDirectory ? sourceFilePath.substring(commonSourceDirectory.length) : sourceFilePath;
|
||||
return combinePaths(newDirPath, sourceFilePath);
|
||||
}
|
||||
|
||||
@@ -2228,7 +2359,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function getSetAccessorTypeAnnotationNode(accessor: AccessorDeclaration): TypeNode {
|
||||
return accessor && accessor.parameters.length > 0 && accessor.parameters[0].type;
|
||||
if (accessor && accessor.parameters.length > 0) {
|
||||
const hasThis = accessor.parameters.length === 2 &&
|
||||
accessor.parameters[0].name.kind === SyntaxKind.Identifier &&
|
||||
(accessor.parameters[0].name as Identifier).originalKeywordKind === SyntaxKind.ThisKeyword;
|
||||
return accessor.parameters[hasThis ? 1 : 0].type;
|
||||
}
|
||||
}
|
||||
|
||||
export function getAllAccessorDeclarations(declarations: NodeArray<Declaration>, accessor: AccessorDeclaration) {
|
||||
@@ -2580,6 +2716,10 @@ namespace ts {
|
||||
return forEach(supportedJavascriptExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
|
||||
export function hasTypeScriptFileExtension(fileName: string) {
|
||||
return forEach(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace each instance of non-ascii characters by one, two, three, or four escape sequences
|
||||
* representing the UTF-8 encoding of the character, and return the expanded char code list.
|
||||
@@ -2965,7 +3105,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function isParameterPropertyDeclaration(node: ParameterDeclaration): boolean {
|
||||
return node.flags & NodeFlags.AccessibilityModifier && node.parent.kind === SyntaxKind.Constructor && isClassLike(node.parent.parent);
|
||||
return node.flags & NodeFlags.ParameterPropertyModifier && node.parent.kind === SyntaxKind.Constructor && isClassLike(node.parent.parent);
|
||||
}
|
||||
|
||||
export function startsWith(str: string, prefix: string): boolean {
|
||||
|
||||
+132
-120
@@ -1,7 +1,8 @@
|
||||
/// <reference path="harness.ts" />
|
||||
/// <reference path="runnerbase.ts" />
|
||||
/// <reference path="typeWriter.ts" />
|
||||
/* tslint:disable:no-null */
|
||||
// In harness baselines, null is different than undefined. See `generateActual` in `harness.ts`.
|
||||
/* tslint:disable:no-null-keyword */
|
||||
|
||||
const enum CompilerTestType {
|
||||
Conformance,
|
||||
@@ -11,7 +12,7 @@ const enum CompilerTestType {
|
||||
|
||||
class CompilerBaselineRunner extends RunnerBase {
|
||||
private basePath = "tests/cases";
|
||||
private testSuiteName: string;
|
||||
private testSuiteName: TestRunnerKind;
|
||||
private errors: boolean;
|
||||
private emit: boolean;
|
||||
private decl: boolean;
|
||||
@@ -40,6 +41,14 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
this.basePath += "/" + this.testSuiteName;
|
||||
}
|
||||
|
||||
public kind() {
|
||||
return this.testSuiteName;
|
||||
}
|
||||
|
||||
public enumerateTestFiles() {
|
||||
return this.enumerateFiles(this.basePath, /\.tsx?$/, { recursive: true });
|
||||
}
|
||||
|
||||
private makeUnitName(name: string, root: string) {
|
||||
return ts.isRootedDiskPath(name) ? name : ts.combinePaths(root, name);
|
||||
};
|
||||
@@ -89,16 +98,16 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
otherFiles = [];
|
||||
|
||||
if (testCaseContent.settings["noImplicitReferences"] || /require\(/.test(lastUnit.content) || /reference\spath/.test(lastUnit.content)) {
|
||||
toBeCompiled.push({ unitName: this.makeUnitName(lastUnit.name, rootDir), content: lastUnit.content });
|
||||
toBeCompiled.push({ unitName: this.makeUnitName(lastUnit.name, rootDir), content: lastUnit.content, fileOptions: lastUnit.fileOptions });
|
||||
units.forEach(unit => {
|
||||
if (unit.name !== lastUnit.name) {
|
||||
otherFiles.push({ unitName: this.makeUnitName(unit.name, rootDir), content: unit.content });
|
||||
otherFiles.push({ unitName: this.makeUnitName(unit.name, rootDir), content: unit.content, fileOptions: unit.fileOptions });
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
toBeCompiled = units.map(unit => {
|
||||
return { unitName: this.makeUnitName(unit.name, rootDir), content: unit.content };
|
||||
return { unitName: this.makeUnitName(unit.name, rootDir), content: unit.content, fileOptions: unit.fileOptions };
|
||||
});
|
||||
}
|
||||
|
||||
@@ -107,7 +116,7 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
}
|
||||
|
||||
const output = Harness.Compiler.compileFiles(
|
||||
toBeCompiled, otherFiles, harnessSettings, /*options*/ tsConfigOptions, /*currentDirectory*/ undefined);
|
||||
toBeCompiled, otherFiles, harnessSettings, /*options*/ tsConfigOptions, /*currentDirectory*/ harnessSettings["currentDirectory"]);
|
||||
|
||||
options = output.options;
|
||||
result = output.result;
|
||||
@@ -145,7 +154,7 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
|
||||
it (`Correct module resolution tracing for ${fileName}`, () => {
|
||||
if (options.traceResolution) {
|
||||
Harness.Baseline.runBaseline("Correct sourcemap content for " + fileName, justName.replace(/\.tsx?$/, ".trace.json"), () => {
|
||||
Harness.Baseline.runBaseline("Correct module resolution tracing for " + fileName, justName.replace(/\.tsx?$/, ".trace.json"), () => {
|
||||
return JSON.stringify(result.traceResults || [], undefined, 4);
|
||||
});
|
||||
}
|
||||
@@ -256,125 +265,128 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
}
|
||||
|
||||
// NEWTODO: Type baselines
|
||||
if (result.errors.length === 0) {
|
||||
// The full walker simulates the types that you would get from doing a full
|
||||
// compile. The pull walker simulates the types you get when you just do
|
||||
// a type query for a random node (like how the LS would do it). Most of the
|
||||
// time, these will be the same. However, occasionally, they can be different.
|
||||
// Specifically, when the compiler internally depends on symbol IDs to order
|
||||
// things, then we may see different results because symbols can be created in a
|
||||
// different order with 'pull' operations, and thus can produce slightly differing
|
||||
// output.
|
||||
//
|
||||
// For example, with a full type check, we may see a type displayed as: number | string
|
||||
// But with a pull type check, we may see it as: string | number
|
||||
//
|
||||
// These types are equivalent, but depend on what order the compiler observed
|
||||
// certain parts of the program.
|
||||
|
||||
const program = result.program;
|
||||
const allFiles = toBeCompiled.concat(otherFiles).filter(file => !!program.getSourceFile(file.unitName));
|
||||
|
||||
const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true);
|
||||
|
||||
const fullResults: ts.Map<TypeWriterResult[]> = {};
|
||||
const pullResults: ts.Map<TypeWriterResult[]> = {};
|
||||
|
||||
for (const sourceFile of allFiles) {
|
||||
fullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName);
|
||||
pullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName);
|
||||
}
|
||||
|
||||
// Produce baselines. The first gives the types for all expressions.
|
||||
// The second gives symbols for all identifiers.
|
||||
let e1: Error, e2: Error;
|
||||
try {
|
||||
checkBaseLines(/*isSymbolBaseLine*/ false);
|
||||
}
|
||||
catch (e) {
|
||||
e1 = e;
|
||||
}
|
||||
|
||||
try {
|
||||
checkBaseLines(/*isSymbolBaseLine*/ true);
|
||||
}
|
||||
catch (e) {
|
||||
e2 = e;
|
||||
}
|
||||
|
||||
if (e1 || e2) {
|
||||
throw e1 || e2;
|
||||
}
|
||||
|
||||
if (result.errors.length !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
function checkBaseLines(isSymbolBaseLine: boolean) {
|
||||
const fullBaseLine = generateBaseLine(fullResults, isSymbolBaseLine);
|
||||
const pullBaseLine = generateBaseLine(pullResults, isSymbolBaseLine);
|
||||
// The full walker simulates the types that you would get from doing a full
|
||||
// compile. The pull walker simulates the types you get when you just do
|
||||
// a type query for a random node (like how the LS would do it). Most of the
|
||||
// time, these will be the same. However, occasionally, they can be different.
|
||||
// Specifically, when the compiler internally depends on symbol IDs to order
|
||||
// things, then we may see different results because symbols can be created in a
|
||||
// different order with 'pull' operations, and thus can produce slightly differing
|
||||
// output.
|
||||
//
|
||||
// For example, with a full type check, we may see a type displayed as: number | string
|
||||
// But with a pull type check, we may see it as: string | number
|
||||
//
|
||||
// These types are equivalent, but depend on what order the compiler observed
|
||||
// certain parts of the program.
|
||||
|
||||
const fullExtension = isSymbolBaseLine ? ".symbols" : ".types";
|
||||
const pullExtension = isSymbolBaseLine ? ".symbols.pull" : ".types.pull";
|
||||
const program = result.program;
|
||||
const allFiles = toBeCompiled.concat(otherFiles).filter(file => !!program.getSourceFile(file.unitName));
|
||||
|
||||
if (fullBaseLine !== pullBaseLine) {
|
||||
Harness.Baseline.runBaseline("Correct full information for " + fileName, justName.replace(/\.tsx?/, fullExtension), () => fullBaseLine);
|
||||
Harness.Baseline.runBaseline("Correct pull information for " + fileName, justName.replace(/\.tsx?/, pullExtension), () => pullBaseLine);
|
||||
}
|
||||
else {
|
||||
Harness.Baseline.runBaseline("Correct information for " + fileName, justName.replace(/\.tsx?/, fullExtension), () => fullBaseLine);
|
||||
}
|
||||
const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true);
|
||||
|
||||
const fullResults: ts.Map<TypeWriterResult[]> = {};
|
||||
const pullResults: ts.Map<TypeWriterResult[]> = {};
|
||||
|
||||
for (const sourceFile of allFiles) {
|
||||
fullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName);
|
||||
pullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName);
|
||||
}
|
||||
|
||||
// Produce baselines. The first gives the types for all expressions.
|
||||
// The second gives symbols for all identifiers.
|
||||
let e1: Error, e2: Error;
|
||||
try {
|
||||
checkBaseLines(/*isSymbolBaseLine*/ false);
|
||||
}
|
||||
catch (e) {
|
||||
e1 = e;
|
||||
}
|
||||
|
||||
try {
|
||||
checkBaseLines(/*isSymbolBaseLine*/ true);
|
||||
}
|
||||
catch (e) {
|
||||
e2 = e;
|
||||
}
|
||||
|
||||
if (e1 || e2) {
|
||||
throw e1 || e2;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
function checkBaseLines(isSymbolBaseLine: boolean) {
|
||||
const fullBaseLine = generateBaseLine(fullResults, isSymbolBaseLine);
|
||||
const pullBaseLine = generateBaseLine(pullResults, isSymbolBaseLine);
|
||||
|
||||
const fullExtension = isSymbolBaseLine ? ".symbols" : ".types";
|
||||
const pullExtension = isSymbolBaseLine ? ".symbols.pull" : ".types.pull";
|
||||
|
||||
if (fullBaseLine !== pullBaseLine) {
|
||||
Harness.Baseline.runBaseline("Correct full information for " + fileName, justName.replace(/\.tsx?/, fullExtension), () => fullBaseLine);
|
||||
Harness.Baseline.runBaseline("Correct pull information for " + fileName, justName.replace(/\.tsx?/, pullExtension), () => pullBaseLine);
|
||||
}
|
||||
|
||||
function generateBaseLine(typeWriterResults: ts.Map<TypeWriterResult[]>, isSymbolBaseline: boolean): string {
|
||||
const typeLines: string[] = [];
|
||||
const typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {};
|
||||
|
||||
allFiles.forEach(file => {
|
||||
const codeLines = file.content.split("\n");
|
||||
typeWriterResults[file.unitName].forEach(result => {
|
||||
if (isSymbolBaseline && !result.symbol) {
|
||||
return;
|
||||
}
|
||||
|
||||
const typeOrSymbolString = isSymbolBaseline ? result.symbol : result.type;
|
||||
const formattedLine = result.sourceText.replace(/\r?\n/g, "") + " : " + typeOrSymbolString;
|
||||
if (!typeMap[file.unitName]) {
|
||||
typeMap[file.unitName] = {};
|
||||
}
|
||||
|
||||
let typeInfo = [formattedLine];
|
||||
const existingTypeInfo = typeMap[file.unitName][result.line];
|
||||
if (existingTypeInfo) {
|
||||
typeInfo = existingTypeInfo.concat(typeInfo);
|
||||
}
|
||||
typeMap[file.unitName][result.line] = typeInfo;
|
||||
});
|
||||
|
||||
typeLines.push("=== " + file.unitName + " ===\r\n");
|
||||
for (let i = 0; i < codeLines.length; i++) {
|
||||
const currentCodeLine = codeLines[i];
|
||||
typeLines.push(currentCodeLine + "\r\n");
|
||||
if (typeMap[file.unitName]) {
|
||||
const typeInfo = typeMap[file.unitName][i];
|
||||
if (typeInfo) {
|
||||
typeInfo.forEach(ty => {
|
||||
typeLines.push(">" + ty + "\r\n");
|
||||
});
|
||||
if (i + 1 < codeLines.length && (codeLines[i + 1].match(/^\s*[{|}]\s*$/) || codeLines[i + 1].trim() === "")) {
|
||||
}
|
||||
else {
|
||||
typeLines.push("\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
typeLines.push("No type information for this code.");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return typeLines.join("");
|
||||
else {
|
||||
Harness.Baseline.runBaseline("Correct information for " + fileName, justName.replace(/\.tsx?/, fullExtension), () => fullBaseLine);
|
||||
}
|
||||
}
|
||||
|
||||
function generateBaseLine(typeWriterResults: ts.Map<TypeWriterResult[]>, isSymbolBaseline: boolean): string {
|
||||
const typeLines: string[] = [];
|
||||
const typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {};
|
||||
|
||||
allFiles.forEach(file => {
|
||||
const codeLines = file.content.split("\n");
|
||||
typeWriterResults[file.unitName].forEach(result => {
|
||||
if (isSymbolBaseline && !result.symbol) {
|
||||
return;
|
||||
}
|
||||
|
||||
const typeOrSymbolString = isSymbolBaseline ? result.symbol : result.type;
|
||||
const formattedLine = result.sourceText.replace(/\r?\n/g, "") + " : " + typeOrSymbolString;
|
||||
if (!typeMap[file.unitName]) {
|
||||
typeMap[file.unitName] = {};
|
||||
}
|
||||
|
||||
let typeInfo = [formattedLine];
|
||||
const existingTypeInfo = typeMap[file.unitName][result.line];
|
||||
if (existingTypeInfo) {
|
||||
typeInfo = existingTypeInfo.concat(typeInfo);
|
||||
}
|
||||
typeMap[file.unitName][result.line] = typeInfo;
|
||||
});
|
||||
|
||||
typeLines.push("=== " + file.unitName + " ===\r\n");
|
||||
for (let i = 0; i < codeLines.length; i++) {
|
||||
const currentCodeLine = codeLines[i];
|
||||
typeLines.push(currentCodeLine + "\r\n");
|
||||
if (typeMap[file.unitName]) {
|
||||
const typeInfo = typeMap[file.unitName][i];
|
||||
if (typeInfo) {
|
||||
typeInfo.forEach(ty => {
|
||||
typeLines.push(">" + ty + "\r\n");
|
||||
});
|
||||
if (i + 1 < codeLines.length && (codeLines[i + 1].match(/^\s*[{|}]\s*$/) || codeLines[i + 1].trim() === "")) {
|
||||
}
|
||||
else {
|
||||
typeLines.push("\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
typeLines.push("No type information for this code.");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return typeLines.join("");
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -387,7 +399,7 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
|
||||
// this will set up a series of describe/it blocks to run between the setup and cleanup phases
|
||||
if (this.tests.length === 0) {
|
||||
const testFiles = this.enumerateFiles(this.basePath, /\.tsx?$/, { recursive: true });
|
||||
const testFiles = this.enumerateTestFiles();
|
||||
testFiles.forEach(fn => {
|
||||
fn = fn.replace(/\\/g, "/");
|
||||
this.checkTestCodeOutput(fn);
|
||||
|
||||
Vendored
+6
-2
@@ -167,9 +167,13 @@ declare module chai {
|
||||
module assert {
|
||||
function equal(actual: any, expected: any, message?: string): void;
|
||||
function notEqual(actual: any, expected: any, message?: string): void;
|
||||
function deepEqual<T>(actual: T, expected: T, message?: string): void;
|
||||
function notDeepEqual<T>(actual: T, expected: T, message?: string): void;
|
||||
function lengthOf(object: any[], length: number, message?: string): void;
|
||||
function isTrue(value: any, message?: string): void;
|
||||
function isFalse(value: any, message?: string): void;
|
||||
function isNull(value: any, message?: string): void;
|
||||
function isNotNull(value: any, message?: string): void;
|
||||
function isOk(actual: any, message?: string): void;
|
||||
function isUndefined(value: any, message?: string): void;
|
||||
function isDefined(value: any, message?: string): void;
|
||||
}
|
||||
}
|
||||
+252
-188
@@ -18,7 +18,6 @@
|
||||
/// <reference path="harnessLanguageService.ts" />
|
||||
/// <reference path="harness.ts" />
|
||||
/// <reference path="fourslashRunner.ts" />
|
||||
/* tslint:disable:no-null */
|
||||
|
||||
namespace FourSlash {
|
||||
ts.disableIncrementalParsing = false;
|
||||
@@ -198,7 +197,7 @@ namespace FourSlash {
|
||||
public lastKnownMarker: string = "";
|
||||
|
||||
// The file that's currently 'opened'
|
||||
public activeFile: FourSlashFile = null;
|
||||
public activeFile: FourSlashFile;
|
||||
|
||||
// Whether or not we should format on keystrokes
|
||||
public enableFormatting = true;
|
||||
@@ -247,8 +246,8 @@ namespace FourSlash {
|
||||
// Create a new Services Adapter
|
||||
this.cancellationToken = new TestCancellationToken();
|
||||
const compilationOptions = convertGlobalOptionsToCompilerOptions(this.testData.globalOptions);
|
||||
if (compilationOptions.typesRoot) {
|
||||
compilationOptions.typesRoot = ts.getNormalizedAbsolutePath(compilationOptions.typesRoot, this.basePath);
|
||||
if (compilationOptions.typeRoots) {
|
||||
compilationOptions.typeRoots = compilationOptions.typeRoots.map(p => ts.getNormalizedAbsolutePath(p, this.basePath));
|
||||
}
|
||||
|
||||
const languageServiceAdapter = this.getLanguageServiceAdapter(testType, this.cancellationToken, compilationOptions);
|
||||
@@ -311,6 +310,7 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
this.formatCodeOptions = {
|
||||
BaseIndentSize: 0,
|
||||
IndentSize: 4,
|
||||
TabSize: 4,
|
||||
NewLineCharacter: Harness.IO.newLine(),
|
||||
@@ -362,14 +362,14 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
// Opens a file given its 0-based index or fileName
|
||||
public openFile(index: number, content?: string): void;
|
||||
public openFile(name: string, content?: string): void;
|
||||
public openFile(indexOrName: any, content?: string) {
|
||||
public openFile(index: number, content?: string, scriptKindName?: string): void;
|
||||
public openFile(name: string, content?: string, scriptKindName?: string): void;
|
||||
public openFile(indexOrName: any, content?: string, scriptKindName?: string) {
|
||||
const fileToOpen: FourSlashFile = this.findFile(indexOrName);
|
||||
fileToOpen.fileName = ts.normalizeSlashes(fileToOpen.fileName);
|
||||
this.activeFile = fileToOpen;
|
||||
// Let the host know that this file is now open
|
||||
this.languageServiceAdapterHost.openFile(fileToOpen.fileName, content);
|
||||
this.languageServiceAdapterHost.openFile(fileToOpen.fileName, content, scriptKindName);
|
||||
}
|
||||
|
||||
public verifyErrorExistsBetweenMarkers(startMarkerName: string, endMarkerName: string, negative: boolean) {
|
||||
@@ -655,7 +655,7 @@ namespace FourSlash {
|
||||
this.assertItemInCompletionList(completions.entries, symbol, text, documentation, kind);
|
||||
}
|
||||
else {
|
||||
this.raiseError(`No completions at position '${ this.currentCaretPosition }' when looking for '${ symbol }'.`);
|
||||
this.raiseError(`No completions at position '${this.currentCaretPosition}' when looking for '${symbol}'.`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -718,6 +718,8 @@ namespace FourSlash {
|
||||
public verifyCompletionEntryDetails(entryName: string, expectedText: string, expectedDocumentation?: string, kind?: string) {
|
||||
const details = this.getCompletionEntryDetails(entryName);
|
||||
|
||||
assert(details, "no completion entry available");
|
||||
|
||||
assert.equal(ts.displayPartsToString(details.displayParts), expectedText, this.assertionMessageAtLastKnownMarker("completion entry details text"));
|
||||
|
||||
if (expectedDocumentation !== undefined) {
|
||||
@@ -729,48 +731,66 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public verifyReferencesAtPositionListContains(fileName: string, start: number, end: number, isWriteAccess?: boolean) {
|
||||
const references = this.getReferencesAtCaret();
|
||||
public verifyReferencesAre(expectedReferences: Range[]) {
|
||||
const actualReferences = this.getReferencesAtCaret() || [];
|
||||
|
||||
if (!references || references.length === 0) {
|
||||
this.raiseError("verifyReferencesAtPositionListContains failed - found 0 references, expected at least one.");
|
||||
if (actualReferences.length > expectedReferences.length) {
|
||||
// Find the unaccounted-for reference.
|
||||
for (const actual of actualReferences) {
|
||||
if (!ts.forEach(expectedReferences, r => r.start === actual.textSpan.start)) {
|
||||
this.raiseError(`A reference ${stringify(actual)} is unaccounted for.`);
|
||||
}
|
||||
}
|
||||
// Probably will never reach here.
|
||||
this.raiseError(`There are ${actualReferences.length} references but only ${expectedReferences.length} were expected.`);
|
||||
}
|
||||
|
||||
for (const reference of expectedReferences) {
|
||||
const {fileName, start, end} = reference;
|
||||
if (reference.marker && reference.marker.data) {
|
||||
const {isWriteAccess, isDefinition} = reference.marker.data;
|
||||
this.verifyReferencesWorker(actualReferences, fileName, start, end, isWriteAccess, isDefinition);
|
||||
}
|
||||
else {
|
||||
this.verifyReferencesWorker(actualReferences, fileName, start, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public verifyReferencesOf({fileName, start}: Range, references: Range[]) {
|
||||
this.openFile(fileName);
|
||||
this.goToPosition(start);
|
||||
this.verifyReferencesAre(references);
|
||||
}
|
||||
|
||||
public verifyRangesReferenceEachOther(ranges?: Range[]) {
|
||||
ranges = ranges || this.getRanges();
|
||||
assert(ranges.length);
|
||||
for (const range of ranges) {
|
||||
this.verifyReferencesOf(range, ranges);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyRangesWithSameTextReferenceEachOther() {
|
||||
ts.forEachValue(this.rangesByText(), ranges => this.verifyRangesReferenceEachOther(ranges));
|
||||
}
|
||||
|
||||
private verifyReferencesWorker(references: ts.ReferenceEntry[], fileName: string, start: number, end: number, isWriteAccess?: boolean, isDefinition?: boolean) {
|
||||
for (let i = 0; i < references.length; i++) {
|
||||
const reference = references[i];
|
||||
if (reference && reference.fileName === fileName && reference.textSpan.start === start && ts.textSpanEnd(reference.textSpan) === end) {
|
||||
if (typeof isWriteAccess !== "undefined" && reference.isWriteAccess !== isWriteAccess) {
|
||||
this.raiseError(`verifyReferencesAtPositionListContains failed - item isWriteAccess value does not match, actual: ${reference.isWriteAccess}, expected: ${isWriteAccess}.`);
|
||||
}
|
||||
if (typeof isDefinition !== "undefined" && reference.isDefinition !== isDefinition) {
|
||||
this.raiseError(`verifyReferencesAtPositionListContains failed - item isDefinition value does not match, actual: ${reference.isDefinition}, expected: ${isDefinition}.`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const missingItem = { fileName: fileName, start: start, end: end, isWriteAccess: isWriteAccess };
|
||||
this.raiseError(`verifyReferencesAtPositionListContains failed - could not find the item: ${JSON.stringify(missingItem)} in the returned list: (${JSON.stringify(references)})`);
|
||||
}
|
||||
|
||||
public verifyReferencesCountIs(count: number, localFilesOnly = true) {
|
||||
const references = this.getReferencesAtCaret();
|
||||
let referencesCount = 0;
|
||||
|
||||
if (localFilesOnly) {
|
||||
const localFiles = this.testData.files.map<string>(file => file.fileName);
|
||||
// Count only the references in local files. Filter the ones in lib and other files.
|
||||
ts.forEach(references, entry => {
|
||||
if (localFiles.some((fileName) => fileName === entry.fileName)) {
|
||||
referencesCount++;
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
referencesCount = references && references.length || 0;
|
||||
}
|
||||
|
||||
if (referencesCount !== count) {
|
||||
const condition = localFilesOnly ? "excluding libs" : "including libs";
|
||||
this.raiseError("Expected references count (" + condition + ") to be " + count + ", but is actually " + referencesCount);
|
||||
}
|
||||
const missingItem = { fileName, start, end, isWriteAccess, isDefinition };
|
||||
this.raiseError(`verifyReferencesAtPositionListContains failed - could not find the item: ${stringify(missingItem)} in the returned list: (${stringify(references)})`);
|
||||
}
|
||||
|
||||
private getMemberListAtCaret() {
|
||||
@@ -801,7 +821,7 @@ namespace FourSlash {
|
||||
|
||||
private testDiagnostics(expected: string, diagnostics: ts.Diagnostic[]) {
|
||||
const realized = ts.realizeDiagnostics(diagnostics, "\r\n");
|
||||
const actual = JSON.stringify(realized, null, " ");
|
||||
const actual = stringify(realized);
|
||||
assert.equal(actual, expected);
|
||||
}
|
||||
|
||||
@@ -860,13 +880,13 @@ namespace FourSlash {
|
||||
assert.equal(getDisplayPartsJson(actualQuickInfo.documentation), getDisplayPartsJson(documentation), this.messageAtLastKnownMarker("QuickInfo documentation"));
|
||||
}
|
||||
|
||||
public verifyRenameLocations(findInStrings: boolean, findInComments: boolean) {
|
||||
public verifyRenameLocations(findInStrings: boolean, findInComments: boolean, ranges?: Range[]) {
|
||||
const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition);
|
||||
if (renameInfo.canRename) {
|
||||
let references = this.languageService.findRenameLocations(
|
||||
this.activeFile.fileName, this.currentCaretPosition, findInStrings, findInComments);
|
||||
|
||||
let ranges = this.getRanges();
|
||||
ranges = ranges || this.getRanges();
|
||||
|
||||
if (!references) {
|
||||
if (ranges.length !== 0) {
|
||||
@@ -876,7 +896,7 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
if (ranges.length !== references.length) {
|
||||
this.raiseError("Rename location count does not match result.\n\nExpected: " + JSON.stringify(ranges) + "\n\nActual:" + JSON.stringify(references));
|
||||
this.raiseError("Rename location count does not match result.\n\nExpected: " + stringify(ranges) + "\n\nActual:" + stringify(references));
|
||||
}
|
||||
|
||||
ranges = ranges.sort((r1, r2) => r1.start - r2.start);
|
||||
@@ -889,7 +909,7 @@ namespace FourSlash {
|
||||
if (reference.textSpan.start !== range.start ||
|
||||
ts.textSpanEnd(reference.textSpan) !== range.end) {
|
||||
|
||||
this.raiseError("Rename location results do not match.\n\nExpected: " + JSON.stringify(ranges) + "\n\nActual:" + JSON.stringify(references));
|
||||
this.raiseError("Rename location results do not match.\n\nExpected: " + stringify(ranges) + "\n\nActual:" + JSON.stringify(references));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -922,7 +942,7 @@ namespace FourSlash {
|
||||
|
||||
public verifyCurrentParameterIsletiable(isVariable: boolean) {
|
||||
const signature = this.getActiveSignatureHelpItem();
|
||||
assert.isNotNull(signature);
|
||||
assert.isOk(signature);
|
||||
assert.equal(isVariable, signature.isVariadic);
|
||||
}
|
||||
|
||||
@@ -973,7 +993,7 @@ namespace FourSlash {
|
||||
}
|
||||
else {
|
||||
if (actual) {
|
||||
this.raiseError(`Expected no signature help, but got "${JSON.stringify(actual)}"`);
|
||||
this.raiseError(`Expected no signature help, but got "${stringify(actual)}"`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1096,14 +1116,6 @@ namespace FourSlash {
|
||||
}
|
||||
addSpanInfoString();
|
||||
return resultString;
|
||||
|
||||
function repeatString(count: number, char: string) {
|
||||
let result = "";
|
||||
for (let i = 0; i < count; i++) {
|
||||
result += char;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public getBreakpointStatementLocation(pos: number) {
|
||||
@@ -1185,7 +1197,7 @@ namespace FourSlash {
|
||||
|
||||
public printCurrentParameterHelp() {
|
||||
const help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
|
||||
Harness.IO.log(JSON.stringify(help));
|
||||
Harness.IO.log(stringify(help));
|
||||
}
|
||||
|
||||
public printCurrentQuickInfo() {
|
||||
@@ -1227,7 +1239,7 @@ namespace FourSlash {
|
||||
|
||||
public printCurrentSignatureHelp() {
|
||||
const sigHelp = this.getActiveSignatureHelpItem();
|
||||
Harness.IO.log(JSON.stringify(sigHelp));
|
||||
Harness.IO.log(stringify(sigHelp));
|
||||
}
|
||||
|
||||
public printMemberListMembers() {
|
||||
@@ -1257,7 +1269,7 @@ namespace FourSlash {
|
||||
public printReferences() {
|
||||
const references = this.getReferencesAtCaret();
|
||||
ts.forEach(references, entry => {
|
||||
Harness.IO.log(JSON.stringify(entry));
|
||||
Harness.IO.log(stringify(entry));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1495,20 +1507,39 @@ namespace FourSlash {
|
||||
this.fixCaretPosition();
|
||||
}
|
||||
|
||||
public formatOnType(pos: number, key: string) {
|
||||
const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, pos, key, this.formatCodeOptions);
|
||||
this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true);
|
||||
this.fixCaretPosition();
|
||||
}
|
||||
|
||||
private updateMarkersForEdit(fileName: string, minChar: number, limChar: number, text: string) {
|
||||
for (let i = 0; i < this.testData.markers.length; i++) {
|
||||
const marker = this.testData.markers[i];
|
||||
for (const marker of this.testData.markers) {
|
||||
if (marker.fileName === fileName) {
|
||||
if (marker.position > minChar) {
|
||||
if (marker.position < limChar) {
|
||||
// Marker is inside the edit - mark it as invalidated (?)
|
||||
marker.position = -1;
|
||||
}
|
||||
else {
|
||||
// Move marker back/forward by the appropriate amount
|
||||
marker.position += (minChar - limChar) + text.length;
|
||||
}
|
||||
marker.position = updatePosition(marker.position);
|
||||
}
|
||||
}
|
||||
|
||||
for (const range of this.testData.ranges) {
|
||||
if (range.fileName === fileName) {
|
||||
range.start = updatePosition(range.start);
|
||||
range.end = updatePosition(range.end);
|
||||
}
|
||||
}
|
||||
|
||||
function updatePosition(position: number) {
|
||||
if (position > minChar) {
|
||||
if (position < limChar) {
|
||||
// Inside the edit - mark it as invalidated (?)
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
// Move marker back/forward by the appropriate amount
|
||||
return position + (minChar - limChar) + text.length;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1603,8 +1634,20 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
public getRanges(): Range[] {
|
||||
// Return a copy of the list
|
||||
return this.testData.ranges.slice(0);
|
||||
return this.testData.ranges;
|
||||
}
|
||||
|
||||
public rangesByText(): ts.Map<Range[]> {
|
||||
const result: ts.Map<Range[]> = {};
|
||||
for (const range of this.getRanges()) {
|
||||
const text = this.rangeText(range);
|
||||
(ts.getProperty(result, text) || (result[text] = [])).push(range);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private rangeText({fileName, start, end}: Range, more = false): string {
|
||||
return this.getFileContent(fileName).slice(start, end);
|
||||
}
|
||||
|
||||
public verifyCaretAtMarker(markerName = "") {
|
||||
@@ -1617,24 +1660,25 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
private getIndentation(fileName: string, position: number, indentStyle: ts.IndentStyle): number {
|
||||
private getIndentation(fileName: string, position: number, indentStyle: ts.IndentStyle, baseIndentSize: number): number {
|
||||
|
||||
const formatOptions = ts.clone(this.formatCodeOptions);
|
||||
formatOptions.IndentStyle = indentStyle;
|
||||
formatOptions.BaseIndentSize = baseIndentSize;
|
||||
|
||||
return this.languageService.getIndentationAtPosition(fileName, position, formatOptions);
|
||||
}
|
||||
|
||||
public verifyIndentationAtCurrentPosition(numberOfSpaces: number, indentStyle: ts.IndentStyle = ts.IndentStyle.Smart) {
|
||||
const actual = this.getIndentation(this.activeFile.fileName, this.currentCaretPosition, indentStyle);
|
||||
public verifyIndentationAtCurrentPosition(numberOfSpaces: number, indentStyle: ts.IndentStyle = ts.IndentStyle.Smart, baseIndentSize = 0) {
|
||||
const actual = this.getIndentation(this.activeFile.fileName, this.currentCaretPosition, indentStyle, baseIndentSize);
|
||||
const lineCol = this.getLineColStringAtPosition(this.currentCaretPosition);
|
||||
if (actual !== numberOfSpaces) {
|
||||
this.raiseError(`verifyIndentationAtCurrentPosition failed at ${lineCol} - expected: ${numberOfSpaces}, actual: ${actual}`);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyIndentationAtPosition(fileName: string, position: number, numberOfSpaces: number, indentStyle: ts.IndentStyle = ts.IndentStyle.Smart) {
|
||||
const actual = this.getIndentation(fileName, position, indentStyle);
|
||||
public verifyIndentationAtPosition(fileName: string, position: number, numberOfSpaces: number, indentStyle: ts.IndentStyle = ts.IndentStyle.Smart, baseIndentSize = 0) {
|
||||
const actual = this.getIndentation(fileName, position, indentStyle, baseIndentSize);
|
||||
const lineCol = this.getLineColStringAtPosition(position);
|
||||
if (actual !== numberOfSpaces) {
|
||||
this.raiseError(`verifyIndentationAtPosition failed at ${lineCol} - expected: ${numberOfSpaces}, actual: ${actual}`);
|
||||
@@ -1748,8 +1792,8 @@ namespace FourSlash {
|
||||
|
||||
function jsonMismatchString() {
|
||||
return Harness.IO.newLine() +
|
||||
"expected: '" + Harness.IO.newLine() + JSON.stringify(expected, (k, v) => v, 2) + "'" + Harness.IO.newLine() +
|
||||
"actual: '" + Harness.IO.newLine() + JSON.stringify(actual, (k, v) => v, 2) + "'";
|
||||
"expected: '" + Harness.IO.newLine() + stringify(expected) + "'" + Harness.IO.newLine() +
|
||||
"actual: '" + Harness.IO.newLine() + stringify(actual) + "'";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1758,13 +1802,13 @@ namespace FourSlash {
|
||||
const actual = (<ts.server.SessionClient>this.languageService).getProjectInfo(
|
||||
this.activeFile.fileName,
|
||||
/* needFileNameList */ true
|
||||
);
|
||||
);
|
||||
assert.equal(
|
||||
expected.join(","),
|
||||
actual.fileNames.map( file => {
|
||||
actual.fileNames.map(file => {
|
||||
return file.replace(this.basePath + "/", "");
|
||||
}).join(",")
|
||||
);
|
||||
}).join(",")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1850,6 +1894,37 @@ namespace FourSlash {
|
||||
});
|
||||
}
|
||||
|
||||
public verifyBraceCompletionAtPosition(negative: boolean, openingBrace: string) {
|
||||
|
||||
const openBraceMap: ts.Map<ts.CharacterCodes> = {
|
||||
"(": ts.CharacterCodes.openParen,
|
||||
"{": ts.CharacterCodes.openBrace,
|
||||
"[": ts.CharacterCodes.openBracket,
|
||||
"'": ts.CharacterCodes.singleQuote,
|
||||
'"': ts.CharacterCodes.doubleQuote,
|
||||
"`": ts.CharacterCodes.backtick,
|
||||
"<": ts.CharacterCodes.lessThan
|
||||
};
|
||||
|
||||
const charCode = openBraceMap[openingBrace];
|
||||
|
||||
if (!charCode) {
|
||||
this.raiseError(`Invalid openingBrace '${openingBrace}' specified.`);
|
||||
}
|
||||
|
||||
const position = this.currentCaretPosition;
|
||||
|
||||
const validBraceCompletion = this.languageService.isValidBraceCompletionAtPosition(this.activeFile.fileName, position, charCode);
|
||||
|
||||
if (!negative && !validBraceCompletion) {
|
||||
this.raiseError(`${position} is not a valid brace completion position for ${openingBrace}`);
|
||||
}
|
||||
|
||||
if (negative && validBraceCompletion) {
|
||||
this.raiseError(`${position} is a valid brace completion position for ${openingBrace}`);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyMatchingBracePosition(bracePosition: number, expectedMatchPosition: number) {
|
||||
const actual = this.languageService.getBraceMatchingAtPosition(this.activeFile.fileName, bracePosition);
|
||||
|
||||
@@ -1888,7 +1963,7 @@ namespace FourSlash {
|
||||
public verifyNavigationItemsCount(expected: number, searchValue: string, matchKind?: string) {
|
||||
const items = this.languageService.getNavigateToItems(searchValue);
|
||||
let actual = 0;
|
||||
let item: ts.NavigateToItem = null;
|
||||
let item: ts.NavigateToItem;
|
||||
|
||||
// Count only the match that match the same MatchKind
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
@@ -1933,61 +2008,29 @@ namespace FourSlash {
|
||||
// if there was an explicit match kind specified, then it should be validated.
|
||||
if (matchKind !== undefined) {
|
||||
const missingItem = { name: name, kind: kind, searchValue: searchValue, matchKind: matchKind, fileName: fileName, parentName: parentName };
|
||||
this.raiseError(`verifyNavigationItemsListContains failed - could not find the item: ${JSON.stringify(missingItem)} in the returned list: (${JSON.stringify(items)})`);
|
||||
this.raiseError(`verifyNavigationItemsListContains failed - could not find the item: ${stringify(missingItem)} in the returned list: (${stringify(items)})`);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyGetScriptLexicalStructureListCount(expected: number) {
|
||||
public verifyNavigationBar(json: any) {
|
||||
const items = this.languageService.getNavigationBarItems(this.activeFile.fileName);
|
||||
const actual = this.getNavigationBarItemsCount(items);
|
||||
|
||||
if (expected !== actual) {
|
||||
this.raiseError(`verifyGetScriptLexicalStructureListCount failed - found: ${actual} navigation items, expected: ${expected}.`);
|
||||
if (JSON.stringify(items, replacer) !== JSON.stringify(json)) {
|
||||
this.raiseError(`verifyNavigationBar failed - expected: ${stringify(json)}, got: ${stringify(items, replacer)}`);
|
||||
}
|
||||
}
|
||||
|
||||
private getNavigationBarItemsCount(items: ts.NavigationBarItem[]) {
|
||||
let result = 0;
|
||||
if (items) {
|
||||
for (let i = 0, n = items.length; i < n; i++) {
|
||||
result++;
|
||||
result += this.getNavigationBarItemsCount(items[i].childItems);
|
||||
// Make the data easier to read.
|
||||
function replacer(key: string, value: any) {
|
||||
switch (key) {
|
||||
case "spans":
|
||||
// We won't ever check this.
|
||||
return undefined;
|
||||
case "childItems":
|
||||
return value.length === 0 ? undefined : value;
|
||||
default:
|
||||
// Omit falsy values, those are presumed to be the default.
|
||||
return value || undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public verifyGetScriptLexicalStructureListContains(name: string, kind: string) {
|
||||
const items = this.languageService.getNavigationBarItems(this.activeFile.fileName);
|
||||
|
||||
if (!items || items.length === 0) {
|
||||
this.raiseError("verifyGetScriptLexicalStructureListContains failed - found 0 navigation items, expected at least one.");
|
||||
}
|
||||
|
||||
if (this.navigationBarItemsContains(items, name, kind)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const missingItem = { name: name, kind: kind };
|
||||
this.raiseError(`verifyGetScriptLexicalStructureListContains failed - could not find the item: ${JSON.stringify(missingItem)} in the returned list: (${JSON.stringify(items, null, " ")})`);
|
||||
}
|
||||
|
||||
private navigationBarItemsContains(items: ts.NavigationBarItem[], name: string, kind: string) {
|
||||
if (items) {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
if (item && item.text === name && item.kind === kind) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.navigationBarItemsContains(item.childItems, name, kind)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public printNavigationItems(searchValue: string) {
|
||||
@@ -2002,15 +2045,15 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public printScriptLexicalStructureItems() {
|
||||
public printNavigationBar() {
|
||||
const items = this.languageService.getNavigationBarItems(this.activeFile.fileName);
|
||||
const length = items && items.length;
|
||||
|
||||
Harness.IO.log(`NavigationItems list (${length} items)`);
|
||||
Harness.IO.log(`Navigation bar (${length} items)`);
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
const item = items[i];
|
||||
Harness.IO.log(`name: ${item.text}, kind: ${item.kind}`);
|
||||
Harness.IO.log(`${repeatString(item.indent, " ")}name: ${item.text}, kind: ${item.kind}, childItems: ${item.childItems.map(child => child.text)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2035,7 +2078,7 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
const missingItem = { fileName: fileName, start: start, end: end, isWriteAccess: isWriteAccess };
|
||||
this.raiseError(`verifyOccurrencesAtPositionListContains failed - could not find the item: ${JSON.stringify(missingItem)} in the returned list: (${JSON.stringify(occurrences)})`);
|
||||
this.raiseError(`verifyOccurrencesAtPositionListContains failed - could not find the item: ${stringify(missingItem)} in the returned list: (${stringify(occurrences)})`);
|
||||
}
|
||||
|
||||
public verifyOccurrencesAtPositionListCount(expectedCount: number) {
|
||||
@@ -2074,7 +2117,7 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
const missingItem = { fileName: fileName, start: start, end: end, kind: kind };
|
||||
this.raiseError(`verifyDocumentHighlightsAtPositionListContains failed - could not find the item: ${JSON.stringify(missingItem)} in the returned list: (${JSON.stringify(documentHighlights)})`);
|
||||
this.raiseError(`verifyDocumentHighlightsAtPositionListContains failed - could not find the item: ${stringify(missingItem)} in the returned list: (${stringify(documentHighlights)})`);
|
||||
}
|
||||
|
||||
public verifyDocumentHighlightsAtPositionListCount(expectedCount: number, fileNamesToSearch: string[]) {
|
||||
@@ -2140,13 +2183,13 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
const itemsString = items.map((item) => JSON.stringify({ name: item.name, kind: item.kind })).join(",\n");
|
||||
const itemsString = items.map(item => stringify({ name: item.name, kind: item.kind })).join(",\n");
|
||||
|
||||
this.raiseError(`Expected "${JSON.stringify({ name, text, documentation, kind })}" to be in list [${itemsString}]`);
|
||||
this.raiseError(`Expected "${stringify({ name, text, documentation, kind })}" to be in list [${itemsString}]`);
|
||||
}
|
||||
|
||||
private findFile(indexOrName: any) {
|
||||
let result: FourSlashFile = null;
|
||||
let result: FourSlashFile;
|
||||
if (typeof indexOrName === "number") {
|
||||
const index = <number>indexOrName;
|
||||
if (index >= this.testData.files.length) {
|
||||
@@ -2239,7 +2282,7 @@ namespace FourSlash {
|
||||
};
|
||||
|
||||
const host = Harness.Compiler.createCompilerHost(
|
||||
[ fourslashFile, testFile ],
|
||||
[fourslashFile, testFile],
|
||||
(fn, contents) => result = contents,
|
||||
ts.ScriptTarget.Latest,
|
||||
Harness.IO.useCaseSensitiveFileNames(),
|
||||
@@ -2264,7 +2307,7 @@ namespace FourSlash {
|
||||
function runCode(code: string, state: TestState): void {
|
||||
// Compile and execute the test
|
||||
const wrappedCode =
|
||||
`(function(test, goTo, verify, edit, debug, format, cancellation, classification, verifyOperationIsCancelled) {
|
||||
`(function(test, goTo, verify, edit, debug, format, cancellation, classification, verifyOperationIsCancelled) {
|
||||
${code}
|
||||
})`;
|
||||
try {
|
||||
@@ -2315,10 +2358,16 @@ ${code}
|
||||
const ranges: Range[] = [];
|
||||
|
||||
// Stuff related to the subfile we're parsing
|
||||
let currentFileContent: string = null;
|
||||
let currentFileContent: string = undefined;
|
||||
let currentFileName = fileName;
|
||||
let currentFileOptions: { [s: string]: string } = {};
|
||||
|
||||
function resetLocalData() {
|
||||
currentFileContent = undefined;
|
||||
currentFileOptions = {};
|
||||
currentFileName = fileName;
|
||||
}
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
let line = lines[i];
|
||||
const lineLength = line.length;
|
||||
@@ -2331,7 +2380,7 @@ ${code}
|
||||
// Subfile content line
|
||||
|
||||
// Append to the current subfile content, inserting a newline needed
|
||||
if (currentFileContent === null) {
|
||||
if (currentFileContent === undefined) {
|
||||
currentFileContent = "";
|
||||
}
|
||||
else {
|
||||
@@ -2363,10 +2412,7 @@ ${code}
|
||||
// Store result file
|
||||
files.push(file);
|
||||
|
||||
// Reset local data
|
||||
currentFileContent = null;
|
||||
currentFileOptions = {};
|
||||
currentFileName = fileName;
|
||||
resetLocalData();
|
||||
}
|
||||
|
||||
currentFileName = basePath + "/" + match[2];
|
||||
@@ -2378,7 +2424,7 @@ ${code}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: should be '==='?
|
||||
// TODO: should be '==='?
|
||||
}
|
||||
else if (line == "" || lineLength === 0) {
|
||||
// Previously blank lines between fourslash content caused it to be considered as 2 files,
|
||||
@@ -2393,10 +2439,7 @@ ${code}
|
||||
// Store result file
|
||||
files.push(file);
|
||||
|
||||
// Reset local data
|
||||
currentFileContent = null;
|
||||
currentFileOptions = {};
|
||||
currentFileName = fileName;
|
||||
resetLocalData();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2461,7 +2504,7 @@ ${code}
|
||||
|
||||
if (markerValue === undefined) {
|
||||
reportError(fileName, location.sourceLine, location.sourceColumn, "Object markers can not be empty");
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const marker: Marker = {
|
||||
@@ -2490,7 +2533,7 @@ ${code}
|
||||
if (markerMap[name] !== undefined) {
|
||||
const message = "Marker '" + name + "' is duplicated in the source file contents.";
|
||||
reportError(marker.fileName, location.sourceLine, location.sourceColumn, message);
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
else {
|
||||
markerMap[name] = marker;
|
||||
@@ -2509,7 +2552,7 @@ ${code}
|
||||
let output = "";
|
||||
|
||||
/// The current marker (or maybe multi-line comment?) we're parsing, possibly
|
||||
let openMarker: LocationInformation = null;
|
||||
let openMarker: LocationInformation = undefined;
|
||||
|
||||
/// A stack of the open range markers that are still unclosed
|
||||
const openRanges: RangeLocationInformation[] = [];
|
||||
@@ -2617,7 +2660,7 @@ ${code}
|
||||
difference += i + 1 - openMarker.sourcePosition;
|
||||
|
||||
// Reset the state
|
||||
openMarker = null;
|
||||
openMarker = undefined;
|
||||
state = State.none;
|
||||
}
|
||||
break;
|
||||
@@ -2639,7 +2682,7 @@ ${code}
|
||||
difference += i + 1 - openMarker.sourcePosition;
|
||||
|
||||
// Reset the state
|
||||
openMarker = null;
|
||||
openMarker = undefined;
|
||||
state = State.none;
|
||||
}
|
||||
else if (validMarkerChars.indexOf(currentChar) < 0) {
|
||||
@@ -2651,7 +2694,7 @@ ${code}
|
||||
// Bail out the text we've gathered so far back into the output
|
||||
flush(i);
|
||||
lastNormalCharPosition = i;
|
||||
openMarker = null;
|
||||
openMarker = undefined;
|
||||
|
||||
state = State.none;
|
||||
}
|
||||
@@ -2682,7 +2725,7 @@ ${code}
|
||||
reportError(fileName, openRange.sourceLine, openRange.sourceColumn, "Unterminated range.");
|
||||
}
|
||||
|
||||
if (openMarker !== null) {
|
||||
if (openMarker) {
|
||||
reportError(fileName, openMarker.sourceLine, openMarker.sourceColumn, "Unterminated marker.");
|
||||
}
|
||||
|
||||
@@ -2697,6 +2740,18 @@ ${code}
|
||||
fileName: fileName
|
||||
};
|
||||
}
|
||||
|
||||
function repeatString(count: number, char: string) {
|
||||
let result = "";
|
||||
for (let i = 0; i < count; i++) {
|
||||
result += char;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function stringify(data: any, replacer?: (key: string, value: any) => any): string {
|
||||
return JSON.stringify(data, replacer, 2);
|
||||
}
|
||||
}
|
||||
|
||||
namespace FourSlashInterface {
|
||||
@@ -2716,6 +2771,10 @@ namespace FourSlashInterface {
|
||||
return this.state.getRanges();
|
||||
}
|
||||
|
||||
public rangesByText(): ts.Map<FourSlash.Range[]> {
|
||||
return this.state.rangesByText();
|
||||
}
|
||||
|
||||
public markerByName(s: string): FourSlash.Marker {
|
||||
return this.state.getMarkerByName(s);
|
||||
}
|
||||
@@ -2759,10 +2818,10 @@ namespace FourSlashInterface {
|
||||
// Opens a file, given either its index as it
|
||||
// appears in the test source, or its filename
|
||||
// as specified in the test metadata
|
||||
public file(index: number, content?: string): void;
|
||||
public file(name: string, content?: string): void;
|
||||
public file(indexOrName: any, content?: string): void {
|
||||
this.state.openFile(indexOrName, content);
|
||||
public file(index: number, content?: string, scriptKindName?: string): void;
|
||||
public file(name: string, content?: string, scriptKindName?: string): void;
|
||||
public file(indexOrName: any, content?: string, scriptKindName?: string): void {
|
||||
this.state.openFile(indexOrName, content, scriptKindName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2823,14 +2882,6 @@ namespace FourSlashInterface {
|
||||
this.state.verifyMemberListIsEmpty(this.negative);
|
||||
}
|
||||
|
||||
public referencesCountIs(count: number) {
|
||||
this.state.verifyReferencesCountIs(count, /*localFilesOnly*/ false);
|
||||
}
|
||||
|
||||
public referencesAtPositionContains(range: FourSlash.Range, isWriteAccess?: boolean) {
|
||||
this.state.verifyReferencesAtPositionListContains(range.fileName, range.start, range.end, isWriteAccess);
|
||||
}
|
||||
|
||||
public signatureHelpPresent() {
|
||||
this.state.verifySignatureHelpPresent(!this.negative);
|
||||
}
|
||||
@@ -2870,6 +2921,10 @@ namespace FourSlashInterface {
|
||||
public verifyDefinitionsName(name: string, containerName: string) {
|
||||
this.state.verifyDefinitionsName(this.negative, name, containerName);
|
||||
}
|
||||
|
||||
public isValidBraceCompletionAtPosition(openingBrace: string) {
|
||||
this.state.verifyBraceCompletionAtPosition(this.negative, openingBrace);
|
||||
}
|
||||
}
|
||||
|
||||
export class Verify extends VerifyNegatable {
|
||||
@@ -2885,8 +2940,8 @@ namespace FourSlashInterface {
|
||||
this.state.verifyIndentationAtCurrentPosition(numberOfSpaces);
|
||||
}
|
||||
|
||||
public indentationAtPositionIs(fileName: string, position: number, numberOfSpaces: number, indentStyle = ts.IndentStyle.Smart) {
|
||||
this.state.verifyIndentationAtPosition(fileName, position, numberOfSpaces, indentStyle);
|
||||
public indentationAtPositionIs(fileName: string, position: number, numberOfSpaces: number, indentStyle = ts.IndentStyle.Smart, baseIndentSize = 0) {
|
||||
this.state.verifyIndentationAtPosition(fileName, position, numberOfSpaces, indentStyle, baseIndentSize);
|
||||
}
|
||||
|
||||
public textAtCaretIs(text: string) {
|
||||
@@ -2918,6 +2973,22 @@ namespace FourSlashInterface {
|
||||
this.state.verifyGetEmitOutputContentsForCurrentFile(expected);
|
||||
}
|
||||
|
||||
public referencesAre(ranges: FourSlash.Range[]) {
|
||||
this.state.verifyReferencesAre(ranges);
|
||||
}
|
||||
|
||||
public referencesOf(start: FourSlash.Range, references: FourSlash.Range[]) {
|
||||
this.state.verifyReferencesOf(start, references);
|
||||
}
|
||||
|
||||
public rangesReferenceEachOther(ranges?: FourSlash.Range[]) {
|
||||
this.state.verifyRangesReferenceEachOther(ranges);
|
||||
}
|
||||
|
||||
public rangesWithSameTextReferenceEachOther() {
|
||||
this.state.verifyRangesWithSameTextReferenceEachOther();
|
||||
}
|
||||
|
||||
public currentParameterHelpArgumentNameIs(name: string) {
|
||||
this.state.verifyCurrentParameterHelpName(name);
|
||||
}
|
||||
@@ -2994,19 +3065,8 @@ namespace FourSlashInterface {
|
||||
this.DocCommentTemplate(/*expectedText*/ undefined, /*expectedOffset*/ undefined, /*empty*/ true);
|
||||
}
|
||||
|
||||
public getScriptLexicalStructureListCount(count: number) {
|
||||
this.state.verifyGetScriptLexicalStructureListCount(count);
|
||||
}
|
||||
|
||||
// TODO: figure out what to do with the unused arguments.
|
||||
public getScriptLexicalStructureListContains(
|
||||
name: string,
|
||||
kind: string,
|
||||
fileName?: string,
|
||||
parentName?: string,
|
||||
isAdditionalSpan?: boolean,
|
||||
markerPosition?: number) {
|
||||
this.state.verifyGetScriptLexicalStructureListContains(name, kind);
|
||||
public navigationBar(json: any) {
|
||||
this.state.verifyNavigationBar(json);
|
||||
}
|
||||
|
||||
public navigationItemsListCount(count: number, searchValue: string, matchKind?: string) {
|
||||
@@ -3071,8 +3131,8 @@ namespace FourSlashInterface {
|
||||
this.state.verifyRenameInfoFailed(message);
|
||||
}
|
||||
|
||||
public renameLocations(findInStrings: boolean, findInComments: boolean) {
|
||||
this.state.verifyRenameLocations(findInStrings, findInComments);
|
||||
public renameLocations(findInStrings: boolean, findInComments: boolean, ranges?: FourSlash.Range[]) {
|
||||
this.state.verifyRenameLocations(findInStrings, findInComments, ranges);
|
||||
}
|
||||
|
||||
public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: { start: number; length: number; },
|
||||
@@ -3088,7 +3148,7 @@ namespace FourSlashInterface {
|
||||
this.state.getSemanticDiagnostics(expected);
|
||||
}
|
||||
|
||||
public ProjectInfo(expected: string []) {
|
||||
public ProjectInfo(expected: string[]) {
|
||||
this.state.verifyProjectInfo(expected);
|
||||
}
|
||||
}
|
||||
@@ -3199,8 +3259,8 @@ namespace FourSlashInterface {
|
||||
this.state.printNavigationItems(searchValue);
|
||||
}
|
||||
|
||||
public printScriptLexicalStructureItems() {
|
||||
this.state.printScriptLexicalStructureItems();
|
||||
public printNavigationBar() {
|
||||
this.state.printNavigationBar();
|
||||
}
|
||||
|
||||
public printReferences() {
|
||||
@@ -3232,6 +3292,10 @@ namespace FourSlashInterface {
|
||||
this.state.formatSelection(this.state.getMarkerByName(startMarker).position, this.state.getMarkerByName(endMarker).position);
|
||||
}
|
||||
|
||||
public onType(posMarker: string, key: string) {
|
||||
this.state.formatOnType(this.state.getMarkerByName(posMarker).position, key);
|
||||
}
|
||||
|
||||
public setOption(name: string, value: number): void;
|
||||
public setOption(name: string, value: string): void;
|
||||
public setOption(name: string, value: boolean): void;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
///<reference path="fourslash.ts" />
|
||||
///<reference path="harness.ts"/>
|
||||
///<reference path="runnerbase.ts" />
|
||||
/* tslint:disable:no-null */
|
||||
|
||||
const enum FourSlashTestType {
|
||||
Native,
|
||||
@@ -12,7 +11,7 @@ const enum FourSlashTestType {
|
||||
|
||||
class FourSlashRunner extends RunnerBase {
|
||||
protected basePath: string;
|
||||
protected testSuiteName: string;
|
||||
protected testSuiteName: TestRunnerKind;
|
||||
|
||||
constructor(private testType: FourSlashTestType) {
|
||||
super();
|
||||
@@ -36,9 +35,17 @@ class FourSlashRunner extends RunnerBase {
|
||||
}
|
||||
}
|
||||
|
||||
public enumerateTestFiles() {
|
||||
return this.enumerateFiles(this.basePath, /\.ts/i, { recursive: false });
|
||||
}
|
||||
|
||||
public kind() {
|
||||
return this.testSuiteName;
|
||||
}
|
||||
|
||||
public initializeTests() {
|
||||
if (this.tests.length === 0) {
|
||||
this.tests = this.enumerateFiles(this.basePath, /\.ts/i, { recursive: false });
|
||||
this.tests = this.enumerateTestFiles();
|
||||
}
|
||||
|
||||
describe(this.testSuiteName + " tests", () => {
|
||||
|
||||
+136
-61
@@ -1,7 +1,7 @@
|
||||
|
||||
//
|
||||
// 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
|
||||
@@ -23,7 +23,7 @@
|
||||
/// <reference path="external\chai.d.ts"/>
|
||||
/// <reference path="sourceMapRecorder.ts"/>
|
||||
/// <reference path="runnerbase.ts"/>
|
||||
/* tslint:disable:no-null */
|
||||
/// <reference path="virtualFileSystem.ts" />
|
||||
|
||||
// Block scoped definitions work poorly for global variables, temporarily enable var
|
||||
/* tslint:disable:no-var-keyword */
|
||||
@@ -32,7 +32,7 @@
|
||||
var _chai: typeof chai = require("chai");
|
||||
var assert: typeof _chai.assert = _chai.assert;
|
||||
declare var __dirname: string; // Node-specific
|
||||
var global = <any>Function("return this").call(null);
|
||||
var global = <any>Function("return this").call(undefined);
|
||||
/* tslint:enable:no-var-keyword */
|
||||
|
||||
namespace Utils {
|
||||
@@ -127,7 +127,7 @@ namespace Utils {
|
||||
export function memoize<T extends Function>(f: T): T {
|
||||
const cache: { [idx: string]: any } = {};
|
||||
|
||||
return <any>(function () {
|
||||
return <any>(function() {
|
||||
const key = Array.prototype.join.call(arguments);
|
||||
const cachedResult = cache[key];
|
||||
if (cachedResult) {
|
||||
@@ -222,6 +222,19 @@ namespace Utils {
|
||||
return k;
|
||||
}
|
||||
|
||||
// For some markers in SyntaxKind, we should print its original syntax name instead of
|
||||
// the marker name in tests.
|
||||
if (k === (<any>ts).SyntaxKind.FirstJSDocNode ||
|
||||
k === (<any>ts).SyntaxKind.LastJSDocNode ||
|
||||
k === (<any>ts).SyntaxKind.FirstJSDocTagNode ||
|
||||
k === (<any>ts).SyntaxKind.LastJSDocTagNode) {
|
||||
for (const kindName in (<any>ts).SyntaxKind) {
|
||||
if ((<any>ts).SyntaxKind[kindName] === k) {
|
||||
return kindName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (<any>ts).SyntaxKind[k];
|
||||
}
|
||||
|
||||
@@ -351,7 +364,7 @@ namespace Utils {
|
||||
assert.equal(node1.end, node2.end, "node1.end !== node2.end");
|
||||
assert.equal(node1.kind, node2.kind, "node1.kind !== node2.kind");
|
||||
|
||||
// call this on both nodes to ensure all propagated flags have been set (and thus can be
|
||||
// call this on both nodes to ensure all propagated flags have been set (and thus can be
|
||||
// compared).
|
||||
assert.equal(ts.containsParseError(node1), ts.containsParseError(node2));
|
||||
assert.equal(node1.flags, node2.flags, "node1.flags !== node2.flags");
|
||||
@@ -420,6 +433,7 @@ namespace Harness {
|
||||
readFile(path: string): string;
|
||||
writeFile(path: string, contents: string): void;
|
||||
directoryName(path: string): string;
|
||||
getDirectories(path: string): string[];
|
||||
createDirectory(path: string): void;
|
||||
fileExists(fileName: string): boolean;
|
||||
directoryExists(path: string): boolean;
|
||||
@@ -430,7 +444,7 @@ namespace Harness {
|
||||
args(): string[];
|
||||
getExecutingFilePath(): string;
|
||||
exit(exitCode?: number): void;
|
||||
readDirectory(path: string, extension?: string, exclude?: string[]): string[];
|
||||
readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[]): string[];
|
||||
}
|
||||
export var IO: IO;
|
||||
|
||||
@@ -465,10 +479,11 @@ namespace Harness {
|
||||
export const readFile: typeof IO.readFile = path => ts.sys.readFile(path);
|
||||
export const writeFile: typeof IO.writeFile = (path, content) => ts.sys.writeFile(path, content);
|
||||
export const directoryName: typeof IO.directoryName = fso.GetParentFolderName;
|
||||
export const getDirectories: typeof IO.getDirectories = dir => ts.sys.getDirectories(dir);
|
||||
export const directoryExists: typeof IO.directoryExists = fso.FolderExists;
|
||||
export const fileExists: typeof IO.fileExists = fso.FileExists;
|
||||
export const log: typeof IO.log = global.WScript && global.WScript.StdOut.WriteLine;
|
||||
export const readDirectory: typeof IO.readDirectory = (path, extension, exclude) => ts.sys.readDirectory(path, extension, exclude);
|
||||
export const readDirectory: typeof IO.readDirectory = (path, extension, exclude, include) => ts.sys.readDirectory(path, extension, exclude, include);
|
||||
|
||||
export function createDirectory(path: string) {
|
||||
if (directoryExists(path)) {
|
||||
@@ -531,13 +546,14 @@ namespace Harness {
|
||||
export const args = () => ts.sys.args;
|
||||
export const getExecutingFilePath = () => ts.sys.getExecutingFilePath();
|
||||
export const exit = (exitCode: number) => ts.sys.exit(exitCode);
|
||||
export const getDirectories: typeof IO.getDirectories = path => ts.sys.getDirectories(path);
|
||||
|
||||
export const readFile: typeof IO.readFile = path => ts.sys.readFile(path);
|
||||
export const writeFile: typeof IO.writeFile = (path, content) => ts.sys.writeFile(path, content);
|
||||
export const fileExists: typeof IO.fileExists = fs.existsSync;
|
||||
export const log: typeof IO.log = s => console.log(s);
|
||||
|
||||
export const readDirectory: typeof IO.readDirectory = (path, extension, exclude) => ts.sys.readDirectory(path, extension, exclude);
|
||||
export const readDirectory: typeof IO.readDirectory = (path, extension, exclude, include) => ts.sys.readDirectory(path, extension, exclude, include);
|
||||
|
||||
export function createDirectory(path: string) {
|
||||
if (!directoryExists(path)) {
|
||||
@@ -558,15 +574,9 @@ namespace Harness {
|
||||
}
|
||||
|
||||
export function directoryName(path: string) {
|
||||
let dirPath = pathModule.dirname(path);
|
||||
|
||||
const dirPath = pathModule.dirname(path);
|
||||
// Node will just continue to repeat the root path, rather than return null
|
||||
if (dirPath === path) {
|
||||
dirPath = null;
|
||||
}
|
||||
else {
|
||||
return dirPath;
|
||||
}
|
||||
return dirPath === path ? undefined : dirPath;
|
||||
}
|
||||
|
||||
export let listFiles: typeof IO.listFiles = (path, spec?, options?) => {
|
||||
@@ -609,7 +619,8 @@ namespace Harness {
|
||||
export const getCurrentDirectory = () => "";
|
||||
export const args = () => <string[]>[];
|
||||
export const getExecutingFilePath = () => "";
|
||||
export const exit = (exitCode: number) => {};
|
||||
export const exit = (exitCode: number) => { };
|
||||
export const getDirectories = () => <string[]>[];
|
||||
|
||||
export let log = (s: string) => console.log(s);
|
||||
|
||||
@@ -634,7 +645,7 @@ namespace Harness {
|
||||
xhr.send();
|
||||
}
|
||||
catch (e) {
|
||||
return { status: 404, responseText: null };
|
||||
return { status: 404, responseText: undefined };
|
||||
}
|
||||
|
||||
return waitForXHR(xhr);
|
||||
@@ -651,7 +662,7 @@ namespace Harness {
|
||||
}
|
||||
catch (e) {
|
||||
log(`XHR Error: ${e}`);
|
||||
return { status: 500, responseText: null };
|
||||
return { status: 500, responseText: undefined };
|
||||
}
|
||||
|
||||
return waitForXHR(xhr);
|
||||
@@ -663,7 +674,7 @@ namespace Harness {
|
||||
}
|
||||
|
||||
export function deleteFile(path: string) {
|
||||
Http.writeToServerSync(serverRoot + path, "DELETE", null);
|
||||
Http.writeToServerSync(serverRoot + path, "DELETE");
|
||||
}
|
||||
|
||||
export function directoryExists(path: string): boolean {
|
||||
@@ -674,7 +685,7 @@ namespace Harness {
|
||||
let dirPath = path;
|
||||
// root of the server
|
||||
if (dirPath.match(/localhost:\d+$/) || dirPath.match(/localhost:\d+\/$/)) {
|
||||
dirPath = null;
|
||||
dirPath = undefined;
|
||||
// path + fileName
|
||||
}
|
||||
else if (dirPath.indexOf(".") === -1) {
|
||||
@@ -722,7 +733,7 @@ namespace Harness {
|
||||
return response.responseText;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -730,8 +741,22 @@ namespace Harness {
|
||||
Http.writeToServerSync(serverRoot + path, "WRITE", contents);
|
||||
}
|
||||
|
||||
export function readDirectory(path: string, extension?: string, exclude?: string[]) {
|
||||
return listFiles(path).filter(f => !extension || ts.fileExtensionIs(f, extension));
|
||||
export function readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[]) {
|
||||
const fs = new Utils.VirtualFileSystem(path, useCaseSensitiveFileNames());
|
||||
for (const file in listFiles(path)) {
|
||||
fs.addFile(file);
|
||||
}
|
||||
return ts.matchFiles(path, extension, exclude, include, useCaseSensitiveFileNames(), getCurrentDirectory(), path => {
|
||||
const entry = fs.traversePath(path);
|
||||
if (entry && entry.isDirectory()) {
|
||||
const directory = <Utils.VirtualDirectory>entry;
|
||||
return {
|
||||
files: ts.map(directory.getFiles(), f => f.name),
|
||||
directories: ts.map(directory.getDirectories(), d => d.name)
|
||||
};
|
||||
}
|
||||
return { files: [], directories: [] };
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -758,7 +783,7 @@ namespace Harness {
|
||||
(emittedFile: string, emittedLine: number, emittedColumn: number, sourceFile: string, sourceLine: number, sourceColumn: number, sourceName: string): void;
|
||||
}
|
||||
|
||||
// Settings
|
||||
// Settings
|
||||
export let userSpecifiedRoot = "";
|
||||
export let lightMode = false;
|
||||
|
||||
@@ -797,7 +822,7 @@ namespace Harness {
|
||||
fileName: string,
|
||||
sourceText: string,
|
||||
languageVersion: ts.ScriptTarget) {
|
||||
// We'll only assert invariants outside of light mode.
|
||||
// We'll only assert invariants outside of light mode.
|
||||
const shouldAssertInvariants = !Harness.lightMode;
|
||||
|
||||
// Only set the parent nodes if we're asserting invariants. We don't need them otherwise.
|
||||
@@ -826,7 +851,7 @@ namespace Harness {
|
||||
}
|
||||
|
||||
if (!libFileNameSourceFileMap[fileName]) {
|
||||
libFileNameSourceFileMap[fileName] = createSourceFileAndAssertInvariants(fileName, IO.readFile(libFolder + fileName), ts.ScriptTarget.Latest);
|
||||
libFileNameSourceFileMap[fileName] = createSourceFileAndAssertInvariants(fileName, IO.readFile(libFolder + fileName), ts.ScriptTarget.Latest);
|
||||
}
|
||||
return libFileNameSourceFileMap[fileName];
|
||||
}
|
||||
@@ -855,13 +880,20 @@ namespace Harness {
|
||||
// Local get canonical file name function, that depends on passed in parameter for useCaseSensitiveFileNames
|
||||
const getCanonicalFileName = ts.createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
|
||||
const fileMap: ts.FileMap<ts.SourceFile> = ts.createFileMap<ts.SourceFile>();
|
||||
const realPathMap: ts.FileMap<string> = ts.createFileMap<string>();
|
||||
const fileMap: ts.FileMap<() => ts.SourceFile> = ts.createFileMap<() => ts.SourceFile>();
|
||||
for (const file of inputFiles) {
|
||||
if (file.content !== undefined) {
|
||||
const fileName = ts.normalizePath(file.unitName);
|
||||
const sourceFile = createSourceFileAndAssertInvariants(fileName, file.content, scriptTarget);
|
||||
const path = ts.toPath(file.unitName, currentDirectory, getCanonicalFileName);
|
||||
fileMap.set(path, sourceFile);
|
||||
if (file.fileOptions && file.fileOptions["symlink"]) {
|
||||
const link = file.fileOptions["symlink"];
|
||||
const linkPath = ts.toPath(link, currentDirectory, getCanonicalFileName);
|
||||
realPathMap.set(linkPath, fileName);
|
||||
fileMap.set(path, (): ts.SourceFile => { throw new Error("Symlinks should always be resolved to a realpath first"); });
|
||||
}
|
||||
const sourceFile = createSourceFileAndAssertInvariants(fileName, file.content, scriptTarget);
|
||||
fileMap.set(path, () => sourceFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -869,7 +901,7 @@ namespace Harness {
|
||||
fileName = ts.normalizePath(fileName);
|
||||
const path = ts.toPath(fileName, currentDirectory, getCanonicalFileName);
|
||||
if (fileMap.contains(path)) {
|
||||
return fileMap.get(path);
|
||||
return fileMap.get(path)();
|
||||
}
|
||||
else if (fileName === fourslashFileName) {
|
||||
const tsFn = "tests/cases/fourslash/" + fourslashFileName;
|
||||
@@ -898,10 +930,45 @@ namespace Harness {
|
||||
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
|
||||
getNewLine: () => newLine,
|
||||
fileExists: fileName => {
|
||||
return fileMap.contains(ts.toPath(fileName, currentDirectory, getCanonicalFileName));
|
||||
const path = ts.toPath(fileName, currentDirectory, getCanonicalFileName);
|
||||
return fileMap.contains(path) || (realPathMap && realPathMap.contains(path));
|
||||
},
|
||||
readFile: (fileName: string): string => {
|
||||
return fileMap.get(ts.toPath(fileName, currentDirectory, getCanonicalFileName)).getText();
|
||||
return fileMap.get(ts.toPath(fileName, currentDirectory, getCanonicalFileName))().getText();
|
||||
},
|
||||
realpath: realPathMap && ((f: string) => {
|
||||
const path = ts.toPath(f, currentDirectory, getCanonicalFileName);
|
||||
return realPathMap.contains(path) ? realPathMap.get(path) : path;
|
||||
}),
|
||||
directoryExists: dir => {
|
||||
let path = ts.toPath(dir, currentDirectory, getCanonicalFileName);
|
||||
// Strip trailing /, which may exist if the path is a drive root
|
||||
if (path[path.length - 1] === "/") {
|
||||
path = <ts.Path>path.substr(0, path.length - 1);
|
||||
}
|
||||
let exists = false;
|
||||
fileMap.forEachValue(key => {
|
||||
if (key.indexOf(path) === 0 && key[path.length] === "/") {
|
||||
exists = true;
|
||||
}
|
||||
});
|
||||
return exists;
|
||||
},
|
||||
getDirectories: d => {
|
||||
const path = ts.toPath(d, currentDirectory, getCanonicalFileName);
|
||||
const result: string[] = [];
|
||||
fileMap.forEachValue((key, value) => {
|
||||
if (key.indexOf(path) === 0 && key.lastIndexOf("/") > path.length) {
|
||||
let dirName = key.substr(path.length, key.indexOf("/", path.length + 1) - path.length);
|
||||
if (dirName[0] === "/") {
|
||||
dirName = dirName.substr(1);
|
||||
}
|
||||
if (result.indexOf(dirName) < 0) {
|
||||
result.push(dirName);
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -913,7 +980,7 @@ namespace Harness {
|
||||
libFiles?: string;
|
||||
}
|
||||
|
||||
// Additional options not already in ts.optionDeclarations
|
||||
// Additional options not already in ts.optionDeclarations
|
||||
const harnessOptionDeclarations: ts.CommandLineOption[] = [
|
||||
{ name: "allowNonTsExtensions", type: "boolean" },
|
||||
{ name: "useCaseSensitiveFileNames", type: "boolean" },
|
||||
@@ -923,7 +990,9 @@ namespace Harness {
|
||||
{ name: "libFiles", type: "string" },
|
||||
{ name: "noErrorTruncation", type: "boolean" },
|
||||
{ name: "suppressOutputPathCheck", type: "boolean" },
|
||||
{ name: "noImplicitReferences", type: "boolean" }
|
||||
{ name: "noImplicitReferences", type: "boolean" },
|
||||
{ name: "currentDirectory", type: "string" },
|
||||
{ name: "symlink", type: "string" }
|
||||
];
|
||||
|
||||
let optionsIndex: ts.Map<ts.CommandLineOption>;
|
||||
@@ -978,6 +1047,7 @@ namespace Harness {
|
||||
export interface TestFile {
|
||||
unitName: string;
|
||||
content: string;
|
||||
fileOptions?: any;
|
||||
}
|
||||
|
||||
export interface CompilationOutput {
|
||||
@@ -996,9 +1066,11 @@ namespace Harness {
|
||||
options.target = options.target || ts.ScriptTarget.ES3;
|
||||
options.newLine = options.newLine || ts.NewLineKind.CarriageReturnLineFeed;
|
||||
options.noErrorTruncation = true;
|
||||
options.skipDefaultLibCheck = true;
|
||||
options.skipDefaultLibCheck = typeof options.skipDefaultLibCheck === "undefined" ? true : options.skipDefaultLibCheck;
|
||||
|
||||
currentDirectory = currentDirectory || Harness.IO.getCurrentDirectory();
|
||||
if (typeof currentDirectory === "undefined") {
|
||||
currentDirectory = Harness.IO.getCurrentDirectory();
|
||||
}
|
||||
|
||||
// Parse settings
|
||||
if (harnessSettings) {
|
||||
@@ -1162,7 +1234,7 @@ namespace Harness {
|
||||
errLines.forEach(e => outputLines.push(e));
|
||||
|
||||
// do not count errors from lib.d.ts here, they are computed separately as numLibraryDiagnostics
|
||||
// if lib.d.ts is explicitly included in input files and there are some errors in it (i.e. because of duplicate identifiers)
|
||||
// if lib.d.ts is explicitly included in input files and there are some errors in it (i.e. because of duplicate identifiers)
|
||||
// then they will be added twice thus triggering 'total errors' assertion with condition
|
||||
// 'totalErrorsReportedInNonLibraryFiles + numLibraryDiagnostics + numTest262HarnessDiagnostics, diagnostics.length
|
||||
|
||||
@@ -1386,7 +1458,9 @@ namespace Harness {
|
||||
const opts: CompilerSettings = {};
|
||||
|
||||
let match: RegExpExecArray;
|
||||
while ((match = optionRegex.exec(content)) != null) {
|
||||
/* tslint:disable:no-null-keyword */
|
||||
while ((match = optionRegex.exec(content)) !== null) {
|
||||
/* tslint:enable:no-null-keyword */
|
||||
opts[match[1]] = match[2];
|
||||
}
|
||||
|
||||
@@ -1403,9 +1477,9 @@ namespace Harness {
|
||||
const lines = Utils.splitContentByNewlines(code);
|
||||
|
||||
// Stuff related to the subfile we're parsing
|
||||
let currentFileContent: string = null;
|
||||
let currentFileContent: string = undefined;
|
||||
let currentFileOptions: any = {};
|
||||
let currentFileName: any = null;
|
||||
let currentFileName: any = undefined;
|
||||
let refs: string[] = [];
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
@@ -1415,10 +1489,8 @@ namespace Harness {
|
||||
// Comment line, check for global/file @options and record them
|
||||
optionRegex.lastIndex = 0;
|
||||
const metaDataName = testMetaData[1].toLowerCase();
|
||||
if (metaDataName === "filename") {
|
||||
currentFileOptions[testMetaData[1]] = testMetaData[2];
|
||||
}
|
||||
else {
|
||||
currentFileOptions[testMetaData[1]] = testMetaData[2];
|
||||
if (metaDataName !== "filename") {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1426,16 +1498,16 @@ namespace Harness {
|
||||
if (currentFileName) {
|
||||
// Store result file
|
||||
const newTestFile = {
|
||||
content: currentFileContent,
|
||||
name: currentFileName,
|
||||
fileOptions: currentFileOptions,
|
||||
originalFilePath: fileName,
|
||||
references: refs
|
||||
};
|
||||
content: currentFileContent,
|
||||
name: currentFileName,
|
||||
fileOptions: currentFileOptions,
|
||||
originalFilePath: fileName,
|
||||
references: refs
|
||||
};
|
||||
testUnitData.push(newTestFile);
|
||||
|
||||
// Reset local data
|
||||
currentFileContent = null;
|
||||
currentFileContent = undefined;
|
||||
currentFileOptions = {};
|
||||
currentFileName = testMetaData[2];
|
||||
refs = [];
|
||||
@@ -1448,7 +1520,7 @@ namespace Harness {
|
||||
else {
|
||||
// Subfile content line
|
||||
// Append to the current subfile content, inserting a newline needed
|
||||
if (currentFileContent === null) {
|
||||
if (currentFileContent === undefined) {
|
||||
currentFileContent = "";
|
||||
}
|
||||
else {
|
||||
@@ -1472,9 +1544,11 @@ namespace Harness {
|
||||
};
|
||||
testUnitData.push(newTestFile2);
|
||||
|
||||
// unit tests always list files explicitly
|
||||
// unit tests always list files explicitly
|
||||
const parseConfigHost: ts.ParseConfigHost = {
|
||||
readDirectory: (name) => []
|
||||
useCaseSensitiveFileNames: false,
|
||||
readDirectory: (name) => [],
|
||||
fileExists: (name) => true
|
||||
};
|
||||
|
||||
// check if project has tsconfig.json in the list of files
|
||||
@@ -1529,10 +1603,10 @@ namespace Harness {
|
||||
|
||||
function baselinePath(fileName: string, type: string, baselineFolder: string, subfolder?: string) {
|
||||
if (subfolder !== undefined) {
|
||||
return Harness.userSpecifiedRoot + baselineFolder + "/" + subfolder + "/" + type + "/" + fileName;
|
||||
return Harness.userSpecifiedRoot + baselineFolder + "/" + subfolder + "/" + type + "/" + fileName;
|
||||
}
|
||||
else {
|
||||
return Harness.userSpecifiedRoot + baselineFolder + "/" + type + "/" + fileName;
|
||||
return Harness.userSpecifiedRoot + baselineFolder + "/" + type + "/" + fileName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1571,7 +1645,9 @@ namespace Harness {
|
||||
|
||||
// Store the content in the 'local' folder so we
|
||||
// can accept it later (manually)
|
||||
/* tslint:disable:no-null-keyword */
|
||||
if (actual !== null) {
|
||||
/* tslint:enable:no-null-keyword */
|
||||
IO.writeFile(actualFileName, actual);
|
||||
}
|
||||
|
||||
@@ -1588,7 +1664,9 @@ namespace Harness {
|
||||
|
||||
const refFileName = referencePath(relativeFileName, opts && opts.Baselinefolder, opts && opts.Subfolder);
|
||||
|
||||
/* tslint:disable:no-null-keyword */
|
||||
if (actual === null) {
|
||||
/* tslint:enable:no-null-keyword */
|
||||
actual = "<no content>";
|
||||
}
|
||||
|
||||
@@ -1601,7 +1679,7 @@ namespace Harness {
|
||||
}
|
||||
|
||||
function writeComparison(expected: string, actual: string, relativeFileName: string, actualFileName: string, descriptionForDescribe: string) {
|
||||
const encoded_actual = Utils.encodeString(actual);
|
||||
const encoded_actual = Utils.encodeString(actual);
|
||||
if (expected != encoded_actual) {
|
||||
// Overwrite & issue error
|
||||
const errMsg = "The baseline file " + relativeFileName + " has changed.";
|
||||
@@ -1650,6 +1728,3 @@ namespace Harness {
|
||||
|
||||
if (Error) (<any>Error).stackTraceLimit = 1;
|
||||
}
|
||||
|
||||
// TODO: not sure why Utils.evalFile isn't working with this, eventually will concat it like old compiler instead of eval
|
||||
eval(Harness.tcServicesFile);
|
||||
|
||||
@@ -163,7 +163,7 @@ namespace Harness.LanguageService {
|
||||
throw new Error("No script with name '" + fileName + "'");
|
||||
}
|
||||
|
||||
public openFile(fileName: string, content?: string): void {
|
||||
public openFile(fileName: string, content?: string, scriptKindName?: string): void {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,7 +172,7 @@ namespace Harness.LanguageService {
|
||||
*/
|
||||
public positionToLineAndCharacter(fileName: string, position: number): ts.LineAndCharacter {
|
||||
const script: ScriptInfo = this.fileNameToScript[fileName];
|
||||
assert.isNotNull(script);
|
||||
assert.isOk(script);
|
||||
|
||||
return ts.computeLineAndCharacterOfPosition(script.getLineMap(), position);
|
||||
}
|
||||
@@ -182,6 +182,7 @@ namespace Harness.LanguageService {
|
||||
class NativeLanguageServiceHost extends LanguageServiceAdapterHost implements ts.LanguageServiceHost {
|
||||
getCompilationSettings() { return this.settings; }
|
||||
getCancellationToken() { return this.cancellationToken; }
|
||||
getDirectories(path: string): string[] { return []; }
|
||||
getCurrentDirectory(): string { return ""; }
|
||||
getDefaultLibFileName(): string { return Harness.Compiler.defaultLibFileName; }
|
||||
getScriptFileNames(): string[] { return this.getFilenames(); }
|
||||
@@ -245,16 +246,21 @@ namespace Harness.LanguageService {
|
||||
};
|
||||
this.getTypeReferenceDirectiveResolutionsForFile = (fileName) => {
|
||||
const scriptInfo = this.getScriptInfo(fileName);
|
||||
const preprocessInfo = ts.preProcessFile(scriptInfo.content, /*readImportFiles*/ false);
|
||||
const resolutions: ts.Map<ts.ResolvedTypeReferenceDirective> = {};
|
||||
const settings = this.nativeHost.getCompilationSettings();
|
||||
for (const typeReferenceDirective of preprocessInfo.typeReferenceDirectives) {
|
||||
const resolutionInfo = ts.resolveTypeReferenceDirective(typeReferenceDirective.fileName, fileName, settings, moduleResolutionHost);
|
||||
if (resolutionInfo.resolvedTypeReferenceDirective.resolvedFileName) {
|
||||
resolutions[typeReferenceDirective.fileName] = resolutionInfo.resolvedTypeReferenceDirective;
|
||||
if (scriptInfo) {
|
||||
const preprocessInfo = ts.preProcessFile(scriptInfo.content, /*readImportFiles*/ false);
|
||||
const resolutions: ts.Map<ts.ResolvedTypeReferenceDirective> = {};
|
||||
const settings = this.nativeHost.getCompilationSettings();
|
||||
for (const typeReferenceDirective of preprocessInfo.typeReferenceDirectives) {
|
||||
const resolutionInfo = ts.resolveTypeReferenceDirective(typeReferenceDirective.fileName, fileName, settings, moduleResolutionHost);
|
||||
if (resolutionInfo.resolvedTypeReferenceDirective.resolvedFileName) {
|
||||
resolutions[typeReferenceDirective.fileName] = resolutionInfo.resolvedTypeReferenceDirective;
|
||||
}
|
||||
}
|
||||
return JSON.stringify(resolutions);
|
||||
}
|
||||
else {
|
||||
return "[]";
|
||||
}
|
||||
return JSON.stringify(resolutions);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -268,6 +274,7 @@ namespace Harness.LanguageService {
|
||||
getCompilationSettings(): string { return JSON.stringify(this.nativeHost.getCompilationSettings()); }
|
||||
getCancellationToken(): ts.HostCancellationToken { return this.nativeHost.getCancellationToken(); }
|
||||
getCurrentDirectory(): string { return this.nativeHost.getCurrentDirectory(); }
|
||||
getDirectories(path: string) { return this.nativeHost.getDirectories(path); }
|
||||
getDefaultLibFileName(): string { return this.nativeHost.getDefaultLibFileName(); }
|
||||
getScriptFileNames(): string { return JSON.stringify(this.nativeHost.getScriptFileNames()); }
|
||||
getScriptSnapshot(fileName: string): ts.ScriptSnapshotShim {
|
||||
@@ -281,6 +288,12 @@ namespace Harness.LanguageService {
|
||||
readDirectory(rootDir: string, extension: string): string {
|
||||
throw new Error("NYI");
|
||||
}
|
||||
readDirectoryNames(path: string): string {
|
||||
throw new Error("Not implemented.");
|
||||
}
|
||||
readFileNames(path: string): string {
|
||||
throw new Error("Not implemented.");
|
||||
}
|
||||
fileExists(fileName: string) { return this.getScriptInfo(fileName) !== undefined; }
|
||||
readFile(fileName: string) {
|
||||
const snapshot = this.nativeHost.getScriptSnapshot(fileName);
|
||||
@@ -437,6 +450,9 @@ namespace Harness.LanguageService {
|
||||
getDocCommentTemplateAtPosition(fileName: string, position: number): ts.TextInsertion {
|
||||
return unwrapJSONCallResult(this.shim.getDocCommentTemplateAtPosition(fileName, position));
|
||||
}
|
||||
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean {
|
||||
return unwrapJSONCallResult(this.shim.isValidBraceCompletionAtPosition(fileName, position, openingBrace));
|
||||
}
|
||||
getEmitOutput(fileName: string): ts.EmitOutput {
|
||||
return unwrapJSONCallResult(this.shim.getEmitOutput(fileName));
|
||||
}
|
||||
@@ -525,9 +541,9 @@ namespace Harness.LanguageService {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
openFile(fileName: string, content?: string): void {
|
||||
super.openFile(fileName, content);
|
||||
this.client.openFile(fileName, content);
|
||||
openFile(fileName: string, content?: string, scriptKindName?: "TS" | "JS" | "TSX" | "JSX"): void {
|
||||
super.openFile(fileName, content, scriptKindName);
|
||||
this.client.openFile(fileName, content, scriptKindName);
|
||||
}
|
||||
|
||||
editScript(fileName: string, start: number, end: number, newText: string) {
|
||||
@@ -597,7 +613,11 @@ namespace Harness.LanguageService {
|
||||
return this.host.getCurrentDirectory();
|
||||
}
|
||||
|
||||
readDirectory(path: string, extension?: string): string[] {
|
||||
getDirectories(path: string): string[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[]): string[] {
|
||||
throw new Error("Not implemented Yet.");
|
||||
}
|
||||
|
||||
@@ -638,6 +658,14 @@ namespace Harness.LanguageService {
|
||||
|
||||
startGroup(): void {
|
||||
}
|
||||
|
||||
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any {
|
||||
return setTimeout(callback, ms, args);
|
||||
}
|
||||
|
||||
clearTimeout(timeoutId: any): void {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
}
|
||||
|
||||
export class ServerLanguageServiceAdapter implements LanguageServiceAdapter {
|
||||
@@ -673,4 +701,3 @@ namespace Harness.LanguageService {
|
||||
getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { throw new Error("getPreProcessedFileInfo is not available using the server interface."); }
|
||||
}
|
||||
}
|
||||
|
||||
+20
-19
@@ -1,6 +1,6 @@
|
||||
declare var require: any, process: any;
|
||||
var fs: any = require('fs');
|
||||
var path: any = require('path');
|
||||
declare const require: any, process: any;
|
||||
const fs: any = require("fs");
|
||||
const path: any = require("path");
|
||||
|
||||
function instrumentForRecording(fn: string, tscPath: string) {
|
||||
instrument(tscPath, `
|
||||
@@ -14,31 +14,31 @@ ts.sys = Playback.wrapSystem(ts.sys);
|
||||
ts.sys.startReplay("${ logFilename }");`);
|
||||
}
|
||||
|
||||
function instrument(tscPath: string, prepareCode: string, cleanupCode: string = '') {
|
||||
var bak = tscPath + '.bak';
|
||||
function instrument(tscPath: string, prepareCode: string, cleanupCode = "") {
|
||||
const bak = `${tscPath}.bak`;
|
||||
fs.exists(bak, (backupExists: boolean) => {
|
||||
var filename = tscPath;
|
||||
let filename = tscPath;
|
||||
if (backupExists) {
|
||||
filename = bak;
|
||||
}
|
||||
|
||||
fs.readFile(filename, 'utf-8', (err: any, tscContent: string) => {
|
||||
fs.readFile(filename, "utf-8", (err: any, tscContent: string) => {
|
||||
if (err) throw err;
|
||||
|
||||
fs.writeFile(bak, tscContent, (err: any) => {
|
||||
if (err) throw err;
|
||||
|
||||
fs.readFile(path.resolve(path.dirname(tscPath) + '/loggedIO.js'), 'utf-8', (err: any, loggerContent: string) => {
|
||||
fs.readFile(path.resolve(path.dirname(tscPath) + "/loggedIO.js"), "utf-8", (err: any, loggerContent: string) => {
|
||||
if (err) throw err;
|
||||
|
||||
var invocationLine = 'ts.executeCommandLine(ts.sys.args);';
|
||||
var index1 = tscContent.indexOf(invocationLine);
|
||||
const invocationLine = "ts.executeCommandLine(ts.sys.args);";
|
||||
const index1 = tscContent.indexOf(invocationLine);
|
||||
if (index1 < 0) {
|
||||
throw new Error("Could not find " + invocationLine);
|
||||
throw new Error(`Could not find ${invocationLine}`);
|
||||
}
|
||||
|
||||
var index2 = index1 + invocationLine.length;
|
||||
var newContent = tscContent.substr(0, index1) + loggerContent + prepareCode + invocationLine + cleanupCode + tscContent.substr(index2) + '\r\n';
|
||||
const index2 = index1 + invocationLine.length;
|
||||
const newContent = tscContent.substr(0, index1) + loggerContent + prepareCode + invocationLine + cleanupCode + tscContent.substr(index2) + "\r\n";
|
||||
fs.writeFile(tscPath, newContent);
|
||||
});
|
||||
});
|
||||
@@ -46,15 +46,16 @@ function instrument(tscPath: string, prepareCode: string, cleanupCode: string =
|
||||
});
|
||||
}
|
||||
|
||||
var isJson = (arg: string) => arg.indexOf(".json") > 0;
|
||||
const isJson = (arg: string) => arg.indexOf(".json") > 0;
|
||||
|
||||
var record = process.argv.indexOf('record');
|
||||
var tscPath = process.argv[process.argv.length - 1];
|
||||
const record = process.argv.indexOf("record");
|
||||
const tscPath = process.argv[process.argv.length - 1];
|
||||
if (record >= 0) {
|
||||
console.log('Instrumenting ' + tscPath + ' for recording');
|
||||
console.log(`Instrumenting ${tscPath} for recording`);
|
||||
instrumentForRecording(process.argv[record + 1], tscPath);
|
||||
} else if (process.argv.some(isJson)) {
|
||||
var filename = process.argv.filter(isJson)[0];
|
||||
}
|
||||
else if (process.argv.some(isJson)) {
|
||||
const filename = process.argv.filter(isJson)[0];
|
||||
instrumentForReplay(filename, tscPath);
|
||||
}
|
||||
|
||||
|
||||
+10
-20
@@ -1,7 +1,6 @@
|
||||
/// <reference path="..\..\src\compiler\sys.ts" />
|
||||
/// <reference path="..\..\src\harness\harness.ts" />
|
||||
/// <reference path="..\..\src\harness\runnerbase.ts" />
|
||||
/* tslint:disable:no-null */
|
||||
|
||||
interface FileInformation {
|
||||
contents: string;
|
||||
@@ -62,8 +61,9 @@ interface IOLog {
|
||||
}[];
|
||||
directoriesRead: {
|
||||
path: string,
|
||||
extension: string,
|
||||
extension: string[],
|
||||
exclude: string[],
|
||||
include: string[],
|
||||
result: string[]
|
||||
}[];
|
||||
}
|
||||
@@ -94,7 +94,7 @@ namespace Playback {
|
||||
return lookup[s] = func(s);
|
||||
});
|
||||
run.reset = () => {
|
||||
lookup = null;
|
||||
lookup = undefined;
|
||||
};
|
||||
|
||||
return run;
|
||||
@@ -149,7 +149,7 @@ namespace Playback {
|
||||
recordLog = createEmptyLog();
|
||||
|
||||
if (typeof underlying.args !== "function") {
|
||||
recordLog.arguments = <string[]>underlying.args;
|
||||
recordLog.arguments = underlying.args;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -170,7 +170,8 @@ namespace Playback {
|
||||
path => callAndRecord(underlying.fileExists(path), recordLog.fileExists, { path }),
|
||||
memoize(path => {
|
||||
// If we read from the file, it must exist
|
||||
if (findResultByPath(wrapper, replayLog.filesRead, path, null) !== null) {
|
||||
const noResult = {};
|
||||
if (findResultByPath(wrapper, replayLog.filesRead, path, noResult) !== noResult) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
@@ -217,24 +218,13 @@ namespace Playback {
|
||||
memoize(path => findResultByPath(wrapper, replayLog.filesRead, path).contents));
|
||||
|
||||
wrapper.readDirectory = recordReplay(wrapper.readDirectory, underlying)(
|
||||
(path, extension, exclude) => {
|
||||
const result = (<ts.System>underlying).readDirectory(path, extension, exclude);
|
||||
const logEntry = { path, extension, exclude, result };
|
||||
(path, extension, exclude, include) => {
|
||||
const result = (<ts.System>underlying).readDirectory(path, extension, exclude, include);
|
||||
const logEntry = { path, extension, exclude, include, result };
|
||||
recordLog.directoriesRead.push(logEntry);
|
||||
return result;
|
||||
},
|
||||
(path, extension, exclude) => findResultByPath(wrapper,
|
||||
replayLog.directoriesRead.filter(
|
||||
d => {
|
||||
if (d.extension === extension) {
|
||||
if (d.exclude) {
|
||||
return ts.arrayIsEqualTo(d.exclude, exclude);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
), path));
|
||||
(path, extension, exclude) => findResultByPath(wrapper, replayLog.directoriesRead, path));
|
||||
|
||||
wrapper.writeFile = recordReplay(wrapper.writeFile, underlying)(
|
||||
(path: string, contents: string) => callAndRecord(underlying.writeFile(path, contents), recordLog.filesWritten, { path, contents, bom: false }),
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
///<reference path="harness.ts" />
|
||||
///<reference path="runnerbase.ts" />
|
||||
/* tslint:disable:no-null */
|
||||
|
||||
// Test case is json of below type in tests/cases/project/
|
||||
interface ProjectRunnerTestCase {
|
||||
@@ -37,11 +36,19 @@ interface BatchCompileProjectTestCaseResult extends CompileProjectFilesResult {
|
||||
}
|
||||
|
||||
class ProjectRunner extends RunnerBase {
|
||||
|
||||
public enumerateTestFiles() {
|
||||
return this.enumerateFiles("tests/cases/project", /\.json$/, { recursive: true });
|
||||
}
|
||||
|
||||
public kind(): TestRunnerKind {
|
||||
return "project";
|
||||
}
|
||||
|
||||
public initializeTests() {
|
||||
if (this.tests.length === 0) {
|
||||
const testFiles = this.enumerateFiles("tests/cases/project", /\.json$/, { recursive: true });
|
||||
const testFiles = this.enumerateTestFiles();
|
||||
testFiles.forEach(fn => {
|
||||
fn = fn.replace(/\\/g, "/");
|
||||
this.runProjectTestCase(fn);
|
||||
});
|
||||
}
|
||||
@@ -53,7 +60,7 @@ class ProjectRunner extends RunnerBase {
|
||||
private runProjectTestCase(testCaseFileName: string) {
|
||||
let testCase: ProjectRunnerTestCase & ts.CompilerOptions;
|
||||
|
||||
let testFileText: string = null;
|
||||
let testFileText: string;
|
||||
try {
|
||||
testFileText = Harness.IO.readFile(testCaseFileName);
|
||||
}
|
||||
@@ -178,7 +185,8 @@ class ProjectRunner extends RunnerBase {
|
||||
useCaseSensitiveFileNames: () => Harness.IO.useCaseSensitiveFileNames(),
|
||||
getNewLine: () => Harness.IO.newLine(),
|
||||
fileExists: fileName => fileName === Harness.Compiler.defaultLibFileName || getSourceFileText(fileName) !== undefined,
|
||||
readFile: fileName => Harness.IO.readFile(fileName)
|
||||
readFile: fileName => Harness.IO.readFile(fileName),
|
||||
getDirectories: path => Harness.IO.getDirectories(path)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -210,7 +218,12 @@ class ProjectRunner extends RunnerBase {
|
||||
}
|
||||
|
||||
const configObject = result.config;
|
||||
const configParseResult = ts.parseJsonConfigFileContent(configObject, { readDirectory }, ts.getDirectoryPath(configFileName), compilerOptions);
|
||||
const configParseHost: ts.ParseConfigHost = {
|
||||
useCaseSensitiveFileNames: Harness.IO.useCaseSensitiveFileNames(),
|
||||
fileExists,
|
||||
readDirectory,
|
||||
};
|
||||
const configParseResult = ts.parseJsonConfigFileContent(configObject, configParseHost, ts.getDirectoryPath(configFileName), compilerOptions);
|
||||
if (configParseResult.errors.length > 0) {
|
||||
return {
|
||||
moduleKind,
|
||||
@@ -237,7 +250,7 @@ class ProjectRunner extends RunnerBase {
|
||||
mapRoot: testCase.resolveMapRoot && testCase.mapRoot ? Harness.IO.resolvePath(testCase.mapRoot) : testCase.mapRoot,
|
||||
sourceRoot: testCase.resolveSourceRoot && testCase.sourceRoot ? Harness.IO.resolvePath(testCase.sourceRoot) : testCase.sourceRoot,
|
||||
module: moduleKind,
|
||||
moduleResolution: ts.ModuleResolutionKind.Classic, // currently all tests use classic module resolution kind, this will change in the future
|
||||
moduleResolution: ts.ModuleResolutionKind.Classic, // currently all tests use classic module resolution kind, this will change in the future
|
||||
};
|
||||
// Set the values specified using json
|
||||
const optionNameMap: ts.Map<ts.CommandLineOption> = {};
|
||||
@@ -268,8 +281,8 @@ class ProjectRunner extends RunnerBase {
|
||||
: ts.normalizeSlashes(testCase.projectRoot) + "/" + ts.normalizeSlashes(fileName);
|
||||
}
|
||||
|
||||
function readDirectory(rootDir: string, extension: string, exclude: string[]): string[] {
|
||||
const harnessReadDirectoryResult = Harness.IO.readDirectory(getFileNameInTheProjectTest(rootDir), extension, exclude);
|
||||
function readDirectory(rootDir: string, extension: string[], exclude: string[], include: string[]): string[] {
|
||||
const harnessReadDirectoryResult = Harness.IO.readDirectory(getFileNameInTheProjectTest(rootDir), extension, exclude, include);
|
||||
const result: string[] = [];
|
||||
for (let i = 0; i < harnessReadDirectoryResult.length; i++) {
|
||||
result[i] = ts.getRelativePathToDirectoryOrUrl(testCase.projectRoot, harnessReadDirectoryResult[i],
|
||||
|
||||
+118
-11
@@ -20,8 +20,6 @@
|
||||
/// <reference path="rwcRunner.ts" />
|
||||
/// <reference path="harness.ts" />
|
||||
|
||||
/* tslint:disable:no-null */
|
||||
|
||||
let runners: RunnerBase[] = [];
|
||||
let iterations = 1;
|
||||
|
||||
@@ -33,18 +31,90 @@ function runTests(runners: RunnerBase[]) {
|
||||
}
|
||||
}
|
||||
|
||||
// users can define tests to run in mytest.config that will override cmd line args, otherwise use cmd line args (test.config), otherwise no options
|
||||
let mytestconfig = "mytest.config";
|
||||
let testconfig = "test.config";
|
||||
let testConfigFile =
|
||||
Harness.IO.fileExists(mytestconfig) ? Harness.IO.readFile(mytestconfig) :
|
||||
(Harness.IO.fileExists(testconfig) ? Harness.IO.readFile(testconfig) : "");
|
||||
function tryGetConfig(args: string[]) {
|
||||
const prefix = "--config=";
|
||||
const configPath = ts.forEach(args, arg => arg.lastIndexOf(prefix, 0) === 0 && arg.substr(prefix.length));
|
||||
// strip leading and trailing quotes from the path (necessary on Windows since shell does not do it automatically)
|
||||
return configPath && configPath.replace(/(^[\"'])|([\"']$)/g, "");
|
||||
}
|
||||
|
||||
if (testConfigFile !== "") {
|
||||
const testConfig = JSON.parse(testConfigFile);
|
||||
function createRunner(kind: TestRunnerKind): RunnerBase {
|
||||
switch (kind) {
|
||||
case "conformance":
|
||||
return new CompilerBaselineRunner(CompilerTestType.Conformance);
|
||||
case "compiler":
|
||||
return new CompilerBaselineRunner(CompilerTestType.Regressions);
|
||||
case "fourslash":
|
||||
return new FourSlashRunner(FourSlashTestType.Native);
|
||||
case "fourslash-shims":
|
||||
return new FourSlashRunner(FourSlashTestType.Shims);
|
||||
case "fourslash-shims-pp":
|
||||
return new FourSlashRunner(FourSlashTestType.ShimsWithPreprocess);
|
||||
case "fourslash-server":
|
||||
return new FourSlashRunner(FourSlashTestType.Server);
|
||||
case "project":
|
||||
return new ProjectRunner();
|
||||
case "rwc":
|
||||
return new RWCRunner();
|
||||
case "test262":
|
||||
return new Test262BaselineRunner();
|
||||
}
|
||||
}
|
||||
|
||||
// users can define tests to run in mytest.config that will override cmd line args, otherwise use cmd line args (test.config), otherwise no options
|
||||
|
||||
const mytestconfigFileName = "mytest.config";
|
||||
const testconfigFileName = "test.config";
|
||||
|
||||
const customConfig = tryGetConfig(Harness.IO.args());
|
||||
let testConfigContent =
|
||||
customConfig && Harness.IO.fileExists(customConfig)
|
||||
? Harness.IO.readFile(customConfig)
|
||||
: Harness.IO.fileExists(mytestconfigFileName)
|
||||
? Harness.IO.readFile(mytestconfigFileName)
|
||||
: Harness.IO.fileExists(testconfigFileName) ? Harness.IO.readFile(testconfigFileName) : "";
|
||||
|
||||
let taskConfigsFolder: string;
|
||||
let workerCount: number;
|
||||
let runUnitTests = true;
|
||||
|
||||
interface TestConfig {
|
||||
light?: boolean;
|
||||
taskConfigsFolder?: string;
|
||||
workerCount?: number;
|
||||
tasks?: TaskSet[];
|
||||
test?: string[];
|
||||
runUnitTests?: boolean;
|
||||
}
|
||||
|
||||
interface TaskSet {
|
||||
runner: TestRunnerKind;
|
||||
files: string[];
|
||||
}
|
||||
|
||||
if (testConfigContent !== "") {
|
||||
const testConfig = <TestConfig>JSON.parse(testConfigContent);
|
||||
if (testConfig.light) {
|
||||
Harness.lightMode = true;
|
||||
}
|
||||
if (testConfig.taskConfigsFolder) {
|
||||
taskConfigsFolder = testConfig.taskConfigsFolder;
|
||||
}
|
||||
if (testConfig.runUnitTests !== undefined) {
|
||||
runUnitTests = testConfig.runUnitTests;
|
||||
}
|
||||
if (testConfig.workerCount) {
|
||||
workerCount = testConfig.workerCount;
|
||||
}
|
||||
if (testConfig.tasks) {
|
||||
for (const taskSet of testConfig.tasks) {
|
||||
const runner = createRunner(taskSet.runner);
|
||||
for (const file of taskSet.files) {
|
||||
runner.addTest(file);
|
||||
}
|
||||
runners.push(runner);
|
||||
}
|
||||
}
|
||||
|
||||
if (testConfig.test && testConfig.test.length > 0) {
|
||||
for (const option of testConfig.test) {
|
||||
@@ -108,4 +178,41 @@ if (runners.length === 0) {
|
||||
// runners.push(new GeneratedFourslashRunner());
|
||||
}
|
||||
|
||||
runTests(runners);
|
||||
if (taskConfigsFolder) {
|
||||
// this instance of mocha should only partition work but not run actual tests
|
||||
runUnitTests = false;
|
||||
const workerConfigs: TestConfig[] = [];
|
||||
for (let i = 0; i < workerCount; i++) {
|
||||
// pass light mode settings to workers
|
||||
workerConfigs.push({ light: Harness.lightMode, tasks: [] });
|
||||
}
|
||||
|
||||
for (const runner of runners) {
|
||||
const files = runner.enumerateTestFiles();
|
||||
const chunkSize = Math.floor(files.length / workerCount) + 1; // add extra 1 to prevent missing tests due to rounding
|
||||
for (let i = 0; i < workerCount; i++) {
|
||||
const startPos = i * chunkSize;
|
||||
const len = Math.min(chunkSize, files.length - startPos);
|
||||
if (len !== 0) {
|
||||
workerConfigs[i].tasks.push({
|
||||
runner: runner.kind(),
|
||||
files: files.slice(startPos, startPos + len)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < workerCount; i++) {
|
||||
const config = workerConfigs[i];
|
||||
// use last worker to run unit tests
|
||||
config.runUnitTests = i === workerCount - 1;
|
||||
Harness.IO.writeFile(ts.combinePaths(taskConfigsFolder, `task-config${i}.json`), JSON.stringify(workerConfigs[i]));
|
||||
}
|
||||
}
|
||||
else {
|
||||
runTests(runners);
|
||||
}
|
||||
if (!runUnitTests) {
|
||||
// patch `describe` to skip unit tests
|
||||
describe = <any>describe.skip;
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
/// <reference path="harness.ts" />
|
||||
|
||||
|
||||
type TestRunnerKind = CompilerTestKind | FourslashTestKind | "project" | "rwc" | "test262";
|
||||
type CompilerTestKind = "conformance" | "compiler";
|
||||
type FourslashTestKind = "fourslash" | "fourslash-shims" | "fourslash-shims-pp" | "fourslash-server";
|
||||
|
||||
abstract class RunnerBase {
|
||||
constructor() { }
|
||||
|
||||
@@ -12,10 +17,14 @@ abstract class RunnerBase {
|
||||
}
|
||||
|
||||
public enumerateFiles(folder: string, regex?: RegExp, options?: { recursive: boolean }): string[] {
|
||||
return Harness.IO.listFiles(Harness.userSpecifiedRoot + folder, regex, { recursive: (options ? options.recursive : false) });
|
||||
return ts.map(Harness.IO.listFiles(Harness.userSpecifiedRoot + folder, regex, { recursive: (options ? options.recursive : false) }), ts.normalizeSlashes);
|
||||
}
|
||||
|
||||
/** Setup the runner's tests so that they are ready to be executed by the harness
|
||||
abstract kind(): TestRunnerKind;
|
||||
|
||||
abstract enumerateTestFiles(): string[];
|
||||
|
||||
/** 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 abstract initializeTests(): void;
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
/// <reference path="runnerbase.ts" />
|
||||
/// <reference path="loggedIO.ts" />
|
||||
/// <reference path="..\compiler\commandLineParser.ts"/>
|
||||
/* tslint:disable:no-null */
|
||||
// In harness baselines, null is different than undefined. See `generateActual` in `harness.ts`.
|
||||
/* tslint:disable:no-null-keyword */
|
||||
|
||||
namespace RWC {
|
||||
function runWithIOLog(ioLog: IOLog, fn: (oldIO: Harness.IO) => void) {
|
||||
@@ -74,7 +75,12 @@ namespace RWC {
|
||||
if (tsconfigFile) {
|
||||
const tsconfigFileContents = getHarnessCompilerInputUnit(tsconfigFile.path);
|
||||
const parsedTsconfigFileContents = ts.parseConfigFileTextToJson(tsconfigFile.path, tsconfigFileContents.content);
|
||||
const configParseResult = ts.parseJsonConfigFileContent(parsedTsconfigFileContents.config, Harness.IO, ts.getDirectoryPath(tsconfigFile.path));
|
||||
const configParseHost: ts.ParseConfigHost = {
|
||||
useCaseSensitiveFileNames: Harness.IO.useCaseSensitiveFileNames(),
|
||||
fileExists: Harness.IO.fileExists,
|
||||
readDirectory: Harness.IO.readDirectory,
|
||||
};
|
||||
const configParseResult = ts.parseJsonConfigFileContent(parsedTsconfigFileContents.config, configParseHost, ts.getDirectoryPath(tsconfigFile.path));
|
||||
fileNames = configParseResult.fileNames;
|
||||
opts.options = ts.extend(opts.options, configParseResult.options);
|
||||
}
|
||||
@@ -123,7 +129,7 @@ namespace RWC {
|
||||
opts.options.noLib = true;
|
||||
|
||||
// Emit the results
|
||||
compilerOptions = null;
|
||||
compilerOptions = undefined;
|
||||
const output = Harness.Compiler.compileFiles(
|
||||
inputFiles,
|
||||
otherFiles,
|
||||
@@ -139,7 +145,7 @@ namespace RWC {
|
||||
|
||||
function getHarnessCompilerInputUnit(fileName: string): Harness.Compiler.TestFile {
|
||||
const unitName = ts.normalizeSlashes(Harness.IO.resolvePath(fileName));
|
||||
let content: string = null;
|
||||
let content: string;
|
||||
try {
|
||||
content = Harness.IO.readFile(unitName);
|
||||
}
|
||||
@@ -190,8 +196,9 @@ namespace RWC {
|
||||
if (compilerResult.errors.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Harness.Compiler.getErrorBaseline(inputFiles.concat(otherFiles), compilerResult.errors);
|
||||
// Do not include the library in the baselines to avoid noise
|
||||
const baselineFiles = inputFiles.concat(otherFiles).filter(f => !Harness.isDefaultLibraryFile(f.unitName));
|
||||
return Harness.Compiler.getErrorBaseline(baselineFiles, compilerResult.errors);
|
||||
}, false, baselineOpts);
|
||||
});
|
||||
|
||||
@@ -222,12 +229,20 @@ namespace RWC {
|
||||
class RWCRunner extends RunnerBase {
|
||||
private static sourcePath = "internal/cases/rwc/";
|
||||
|
||||
public enumerateTestFiles() {
|
||||
return Harness.IO.listFiles(RWCRunner.sourcePath, /.+\.json$/);
|
||||
}
|
||||
|
||||
public kind(): TestRunnerKind {
|
||||
return "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 {
|
||||
// Read in and evaluate the test list
|
||||
const testList = Harness.IO.listFiles(RWCRunner.sourcePath, /.+\.json$/);
|
||||
const testList = this.enumerateTestFiles();
|
||||
for (let i = 0; i < testList.length; i++) {
|
||||
this.runTest(testList[i]);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/// <reference path="harness.ts" />
|
||||
/// <reference path="runnerbase.ts" />
|
||||
/* tslint:disable:no-null */
|
||||
// In harness baselines, null is different than undefined. See `generateActual` in `harness.ts`.
|
||||
/* tslint:disable:no-null-keyword */
|
||||
|
||||
class Test262BaselineRunner extends RunnerBase {
|
||||
private static basePath = "internal/cases/test262";
|
||||
@@ -97,12 +98,20 @@ class Test262BaselineRunner extends RunnerBase {
|
||||
});
|
||||
}
|
||||
|
||||
public kind(): TestRunnerKind {
|
||||
return "test262";
|
||||
}
|
||||
|
||||
public enumerateTestFiles() {
|
||||
return ts.map(this.enumerateFiles(Test262BaselineRunner.basePath, Test262BaselineRunner.testFileExtensionRegex, { recursive: true }), ts.normalizePath);
|
||||
}
|
||||
|
||||
public initializeTests() {
|
||||
// this will set up a series of describe/it blocks to run between the setup and cleanup phases
|
||||
if (this.tests.length === 0) {
|
||||
const testFiles = this.enumerateFiles(Test262BaselineRunner.basePath, Test262BaselineRunner.testFileExtensionRegex, { recursive: true });
|
||||
const testFiles = this.enumerateTestFiles();
|
||||
testFiles.forEach(fn => {
|
||||
this.runTest(ts.normalizePath(fn));
|
||||
this.runTest(fn);
|
||||
});
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
/// <reference path="harness.ts" />
|
||||
/// <reference path="..\compiler\commandLineParser.ts"/>
|
||||
namespace Utils {
|
||||
export class VirtualFileSystemEntry {
|
||||
fileSystem: VirtualFileSystem;
|
||||
name: string;
|
||||
|
||||
constructor(fileSystem: VirtualFileSystem, name: string) {
|
||||
this.fileSystem = fileSystem;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
isDirectory() { return false; }
|
||||
isFile() { return false; }
|
||||
isFileSystem() { return false; }
|
||||
}
|
||||
|
||||
export class VirtualFile extends VirtualFileSystemEntry {
|
||||
content: string;
|
||||
isFile() { return true; }
|
||||
}
|
||||
|
||||
export abstract class VirtualFileSystemContainer extends VirtualFileSystemEntry {
|
||||
abstract getFileSystemEntries(): VirtualFileSystemEntry[];
|
||||
|
||||
getFileSystemEntry(name: string): VirtualFileSystemEntry {
|
||||
for (const entry of this.getFileSystemEntries()) {
|
||||
if (this.fileSystem.sameName(entry.name, name)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getDirectories(): VirtualDirectory[] {
|
||||
return <VirtualDirectory[]>ts.filter(this.getFileSystemEntries(), entry => entry.isDirectory());
|
||||
}
|
||||
|
||||
getFiles(): VirtualFile[] {
|
||||
return <VirtualFile[]>ts.filter(this.getFileSystemEntries(), entry => entry.isFile());
|
||||
}
|
||||
|
||||
getDirectory(name: string): VirtualDirectory {
|
||||
const entry = this.getFileSystemEntry(name);
|
||||
return entry.isDirectory() ? <VirtualDirectory>entry : undefined;
|
||||
}
|
||||
|
||||
getFile(name: string): VirtualFile {
|
||||
const entry = this.getFileSystemEntry(name);
|
||||
return entry.isFile() ? <VirtualFile>entry : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export class VirtualDirectory extends VirtualFileSystemContainer {
|
||||
private entries: VirtualFileSystemEntry[] = [];
|
||||
|
||||
isDirectory() { return true; }
|
||||
|
||||
getFileSystemEntries() { return this.entries.slice(); }
|
||||
|
||||
addDirectory(name: string): VirtualDirectory {
|
||||
const entry = this.getFileSystemEntry(name);
|
||||
if (entry === undefined) {
|
||||
const directory = new VirtualDirectory(this.fileSystem, name);
|
||||
this.entries.push(directory);
|
||||
return directory;
|
||||
}
|
||||
else if (entry.isDirectory()) {
|
||||
return <VirtualDirectory>entry;
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
addFile(name: string, content?: string): VirtualFile {
|
||||
const entry = this.getFileSystemEntry(name);
|
||||
if (entry === undefined) {
|
||||
const file = new VirtualFile(this.fileSystem, name);
|
||||
file.content = content;
|
||||
this.entries.push(file);
|
||||
return file;
|
||||
}
|
||||
else if (entry.isFile()) {
|
||||
const file = <VirtualFile>entry;
|
||||
file.content = content;
|
||||
return file;
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class VirtualFileSystem extends VirtualFileSystemContainer {
|
||||
private root: VirtualDirectory;
|
||||
|
||||
currentDirectory: string;
|
||||
useCaseSensitiveFileNames: boolean;
|
||||
|
||||
constructor(currentDirectory: string, useCaseSensitiveFileNames: boolean) {
|
||||
super(undefined, "");
|
||||
this.fileSystem = this;
|
||||
this.root = new VirtualDirectory(this, "");
|
||||
this.currentDirectory = currentDirectory;
|
||||
this.useCaseSensitiveFileNames = useCaseSensitiveFileNames;
|
||||
}
|
||||
|
||||
isFileSystem() { return true; }
|
||||
|
||||
getFileSystemEntries() { return this.root.getFileSystemEntries(); }
|
||||
|
||||
addDirectory(path: string) {
|
||||
const components = ts.getNormalizedPathComponents(path, this.currentDirectory);
|
||||
let directory: VirtualDirectory = this.root;
|
||||
for (const component of components) {
|
||||
directory = directory.addDirectory(component);
|
||||
if (directory === undefined) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return directory;
|
||||
}
|
||||
|
||||
addFile(path: string, content?: string) {
|
||||
const absolutePath = ts.getNormalizedAbsolutePath(path, this.currentDirectory);
|
||||
const fileName = ts.getBaseFileName(path);
|
||||
const directoryPath = ts.getDirectoryPath(absolutePath);
|
||||
const directory = this.addDirectory(directoryPath);
|
||||
return directory ? directory.addFile(fileName, content) : undefined;
|
||||
}
|
||||
|
||||
fileExists(path: string) {
|
||||
const entry = this.traversePath(path);
|
||||
return entry !== undefined && entry.isFile();
|
||||
}
|
||||
|
||||
sameName(a: string, b: string) {
|
||||
return this.useCaseSensitiveFileNames ? a === b : a.toLowerCase() === b.toLowerCase();
|
||||
}
|
||||
|
||||
traversePath(path: string) {
|
||||
let directory: VirtualDirectory = this.root;
|
||||
for (const component of ts.getNormalizedPathComponents(path, this.currentDirectory)) {
|
||||
const entry = directory.getFileSystemEntry(component);
|
||||
if (entry === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
else if (entry.isDirectory()) {
|
||||
directory = <VirtualDirectory>entry;
|
||||
}
|
||||
else {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
return directory;
|
||||
}
|
||||
}
|
||||
|
||||
export class MockParseConfigHost extends VirtualFileSystem implements ts.ParseConfigHost {
|
||||
constructor(currentDirectory: string, ignoreCase: boolean, files: string[]) {
|
||||
super(currentDirectory, ignoreCase);
|
||||
for (const file of files) {
|
||||
this.addFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
readDirectory(path: string, extensions: string[], excludes: string[], includes: string[]) {
|
||||
return ts.matchFiles(path, extensions, excludes, includes, this.useCaseSensitiveFileNames, this.currentDirectory, (path: string) => this.getAccessibleFileSystemEntries(path));
|
||||
}
|
||||
|
||||
getAccessibleFileSystemEntries(path: string) {
|
||||
const entry = this.traversePath(path);
|
||||
if (entry && entry.isDirectory()) {
|
||||
const directory = <VirtualDirectory>entry;
|
||||
return {
|
||||
files: ts.map(directory.getFiles(), f => f.name),
|
||||
directories: ts.map(directory.getDirectories(), d => d.name)
|
||||
};
|
||||
}
|
||||
return { files: [], directories: [] };
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+1139
-601
File diff suppressed because it is too large
Load Diff
Vendored
+8
-17
@@ -4,13 +4,13 @@ interface Map<K, V> {
|
||||
forEach(callbackfn: (value: V, index: K, map: Map<K, V>) => void, thisArg?: any): void;
|
||||
get(key: K): V | undefined;
|
||||
has(key: K): boolean;
|
||||
set(key: K, value?: V): Map<K, V>;
|
||||
set(key: K, value?: V): this;
|
||||
readonly size: number;
|
||||
}
|
||||
|
||||
interface MapConstructor {
|
||||
new (): Map<any, any>;
|
||||
new <K, V>(): Map<K, V>;
|
||||
new <K, V>(entries?: [K, V][]): Map<K, V>;
|
||||
readonly prototype: Map<any, any>;
|
||||
}
|
||||
declare var Map: MapConstructor;
|
||||
@@ -20,51 +20,42 @@ interface WeakMap<K, V> {
|
||||
delete(key: K): boolean;
|
||||
get(key: K): V | undefined;
|
||||
has(key: K): boolean;
|
||||
set(key: K, value?: V): WeakMap<K, V>;
|
||||
|
||||
set(key: K, value?: V): this;
|
||||
}
|
||||
|
||||
interface WeakMapConstructor {
|
||||
new (): WeakMap<any, any>;
|
||||
new <K, V>(): WeakMap<K, V>;
|
||||
new <K, V>(entries?: [K, V][]): WeakMap<K, V>;
|
||||
readonly prototype: WeakMap<any, any>;
|
||||
}
|
||||
declare var WeakMap: WeakMapConstructor;
|
||||
|
||||
interface Set<T> {
|
||||
add(value: T): Set<T>;
|
||||
add(value: T): this;
|
||||
clear(): void;
|
||||
delete(value: T): boolean;
|
||||
entries(): IterableIterator<[T, T]>;
|
||||
forEach(callbackfn: (value: T, index: T, set: Set<T>) => void, thisArg?: any): void;
|
||||
has(value: T): boolean;
|
||||
keys(): IterableIterator<T>;
|
||||
readonly size: number;
|
||||
values(): IterableIterator<T>;
|
||||
[Symbol.iterator]():IterableIterator<T>;
|
||||
readonly [Symbol.toStringTag]: "Set";
|
||||
}
|
||||
|
||||
interface SetConstructor {
|
||||
new (): Set<any>;
|
||||
new <T>(): Set<T>;
|
||||
new <T>(iterable: Iterable<T>): Set<T>;
|
||||
new <T>(values?: T[]): Set<T>;
|
||||
readonly prototype: Set<any>;
|
||||
}
|
||||
declare var Set: SetConstructor;
|
||||
|
||||
interface WeakSet<T> {
|
||||
add(value: T): WeakSet<T>;
|
||||
add(value: T): this;
|
||||
clear(): void;
|
||||
delete(value: T): boolean;
|
||||
has(value: T): boolean;
|
||||
readonly [Symbol.toStringTag]: "WeakSet";
|
||||
}
|
||||
|
||||
interface WeakSetConstructor {
|
||||
new (): WeakSet<any>;
|
||||
new <T>(): WeakSet<T>;
|
||||
new <T>(iterable: Iterable<T>): WeakSet<T>;
|
||||
new <T>(values?: T[]): WeakSet<T>;
|
||||
readonly prototype: WeakSet<any>;
|
||||
}
|
||||
declare var WeakSet: WeakSetConstructor;
|
||||
|
||||
Vendored
+80
-67
@@ -1,48 +1,48 @@
|
||||
declare type PropertyKey = string | number | symbol;
|
||||
|
||||
interface Array<T> {
|
||||
/**
|
||||
* Returns the value of the first element in the array where predicate is true, and undefined
|
||||
/**
|
||||
* Returns the value of the first element in the array where predicate is true, and undefined
|
||||
* otherwise.
|
||||
* @param predicate find calls predicate once for each element of the array, in ascending
|
||||
* order, until it finds one where predicate returns true. If such an element is found, find
|
||||
* @param predicate find calls predicate once for each element of the array, in ascending
|
||||
* order, until it finds one where predicate returns true. If such an element is found, find
|
||||
* immediately returns that element value. Otherwise, find returns undefined.
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: T, index: number, obj: Array<T>) => boolean, thisArg?: any): T | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and undefined
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and undefined
|
||||
* otherwise.
|
||||
* @param predicate find calls predicate once for each element of the array, in ascending
|
||||
* order, until it finds one where predicate returns true. If such an element is found, find
|
||||
* immediately returns that element value. Otherwise, find returns undefined.
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* @param predicate find calls predicate once for each element of the array, in ascending
|
||||
* order, until it finds one where predicate returns true. If such an element is found,
|
||||
* findIndex immediately returns that element index. Otherwise, findIndex returns -1.
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: T) => boolean, thisArg?: any): number | undefined;
|
||||
findIndex(predicate: (value: T) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Returns the this object after filling the section identified by start and end with value
|
||||
* @param value value to fill array section with
|
||||
* @param start index to start filling the array at. If start is negative, it is treated as
|
||||
* length+start where length is the length of the array.
|
||||
* @param end index to stop filling the array at. If end is negative, it is treated as
|
||||
* @param start index to start filling the array at. If start is negative, it is treated as
|
||||
* length+start where length is the length of the array.
|
||||
* @param end index to stop filling the array at. If end is negative, it is treated as
|
||||
* length+end.
|
||||
*/
|
||||
fill(value: T, start?: number, end?: number): T[];
|
||||
fill(value: T, start?: number, end?: number): this;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns the this object after copying a section of the array identified by start and end
|
||||
* to the same array starting at position target
|
||||
* @param target If target is negative, it is treated as length+target where length is the
|
||||
* length of the array.
|
||||
* @param start If start is negative, it is treated as length+start. If end is negative, it
|
||||
* @param target If target is negative, it is treated as length+target where length is the
|
||||
* length of the array.
|
||||
* @param start If start is negative, it is treated as length+start. If end is negative, it
|
||||
* is treated as length+end.
|
||||
* @param end If not specified, length of the this object is used as its default value.
|
||||
* @param end If not specified, length of the this object is used as its default value.
|
||||
*/
|
||||
copyWithin(target: number, start: number, end?: number): T[];
|
||||
copyWithin(target: number, start: number, end?: number): this;
|
||||
}
|
||||
|
||||
interface ArrayConstructor {
|
||||
@@ -114,7 +114,7 @@ interface Math {
|
||||
log1p(x: number): number;
|
||||
|
||||
/**
|
||||
* Returns the result of (e^x - 1) of x (e raised to the power of x, where e is the base of
|
||||
* Returns the result of (e^x - 1) of x (e raised to the power of x, where e is the base of
|
||||
* the natural logarithms).
|
||||
* @param x A numeric expression.
|
||||
*/
|
||||
@@ -190,14 +190,14 @@ interface Math {
|
||||
interface NumberConstructor {
|
||||
/**
|
||||
* The value of Number.EPSILON is the difference between 1 and the smallest value greater than 1
|
||||
* that is representable as a Number value, which is approximately:
|
||||
* that is representable as a Number value, which is approximately:
|
||||
* 2.2204460492503130808472633361816 x 10−16.
|
||||
*/
|
||||
readonly EPSILON: number;
|
||||
|
||||
/**
|
||||
* Returns true if passed value is finite.
|
||||
* Unlike the global isFininte, Number.isFinite doesn't forcibly convert the parameter to a
|
||||
* Unlike the global isFininte, Number.isFinite doesn't forcibly convert the parameter to a
|
||||
* number. Only finite values of the type number, result in true.
|
||||
* @param number A numeric value.
|
||||
*/
|
||||
@@ -210,7 +210,7 @@ interface NumberConstructor {
|
||||
isInteger(number: number): boolean;
|
||||
|
||||
/**
|
||||
* Returns a Boolean value that indicates whether a value is the reserved value NaN (not a
|
||||
* Returns a Boolean value that indicates whether a value is the reserved value NaN (not a
|
||||
* number). Unlike the global isNaN(), Number.isNaN() doesn't forcefully convert the parameter
|
||||
* to a number. Only values of the type number, that are also NaN, result in true.
|
||||
* @param number A numeric value.
|
||||
@@ -223,30 +223,30 @@ interface NumberConstructor {
|
||||
*/
|
||||
isSafeInteger(number: number): boolean;
|
||||
|
||||
/**
|
||||
* The value of the largest integer n such that n and n + 1 are both exactly representable as
|
||||
* a Number value.
|
||||
/**
|
||||
* The value of the largest integer n such that n and n + 1 are both exactly representable as
|
||||
* a Number value.
|
||||
* The value of Number.MIN_SAFE_INTEGER is 9007199254740991 2^53 − 1.
|
||||
*/
|
||||
readonly MAX_SAFE_INTEGER: number;
|
||||
|
||||
/**
|
||||
* The value of the smallest integer n such that n and n − 1 are both exactly representable as
|
||||
* a Number value.
|
||||
/**
|
||||
* The value of the smallest integer n such that n and n − 1 are both exactly representable as
|
||||
* a Number value.
|
||||
* The value of Number.MIN_SAFE_INTEGER is −9007199254740991 (−(2^53 − 1)).
|
||||
*/
|
||||
readonly MIN_SAFE_INTEGER: number;
|
||||
|
||||
/**
|
||||
* Converts a string to a floating-point number.
|
||||
* @param string A string that contains a floating-point number.
|
||||
* Converts a string to a floating-point number.
|
||||
* @param string A string that contains a floating-point number.
|
||||
*/
|
||||
parseFloat(string: string): number;
|
||||
|
||||
/**
|
||||
* Converts A string to an integer.
|
||||
* @param s A string to convert into a number.
|
||||
* @param radix A value between 2 and 36 that specifies the base of the number in numString.
|
||||
* @param radix A value between 2 and 36 that specifies the base of the number in numString.
|
||||
* If this argument is not supplied, strings with a prefix of '0x' are considered hexadecimal.
|
||||
* All other strings are considered decimal.
|
||||
*/
|
||||
@@ -255,12 +255,12 @@ interface NumberConstructor {
|
||||
|
||||
interface Object {
|
||||
/**
|
||||
* Determines whether an object has a property with the specified name.
|
||||
* Determines whether an object has a property with the specified name.
|
||||
* @param v A property name.
|
||||
*/
|
||||
hasOwnProperty(v: PropertyKey): boolean
|
||||
|
||||
/**
|
||||
/**
|
||||
* Determines whether a specified property is enumerable.
|
||||
* @param v A property name.
|
||||
*/
|
||||
@@ -269,7 +269,7 @@ interface Object {
|
||||
|
||||
interface ObjectConstructor {
|
||||
/**
|
||||
* Copy the values of all of the enumerable own properties from one or more source objects to a
|
||||
* Copy the values of all of the enumerable own properties from one or more source objects to a
|
||||
* target object. Returns the target object.
|
||||
* @param target The target object to copy to.
|
||||
* @param source The source object from which to copy properties.
|
||||
@@ -277,7 +277,7 @@ interface ObjectConstructor {
|
||||
assign<T, U>(target: T, source: U): T & U;
|
||||
|
||||
/**
|
||||
* Copy the values of all of the enumerable own properties from one or more source objects to a
|
||||
* Copy the values of all of the enumerable own properties from one or more source objects to a
|
||||
* target object. Returns the target object.
|
||||
* @param target The target object to copy to.
|
||||
* @param source1 The first source object from which to copy properties.
|
||||
@@ -286,7 +286,7 @@ interface ObjectConstructor {
|
||||
assign<T, U, V>(target: T, source1: U, source2: V): T & U & V;
|
||||
|
||||
/**
|
||||
* Copy the values of all of the enumerable own properties from one or more source objects to a
|
||||
* Copy the values of all of the enumerable own properties from one or more source objects to a
|
||||
* target object. Returns the target object.
|
||||
* @param target The target object to copy to.
|
||||
* @param source1 The first source object from which to copy properties.
|
||||
@@ -296,7 +296,7 @@ interface ObjectConstructor {
|
||||
assign<T, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W;
|
||||
|
||||
/**
|
||||
* Copy the values of all of the enumerable own properties from one or more source objects to a
|
||||
* Copy the values of all of the enumerable own properties from one or more source objects to a
|
||||
* target object. Returns the target object.
|
||||
* @param target The target object to copy to.
|
||||
* @param sources One or more source objects from which to copy properties
|
||||
@@ -324,17 +324,17 @@ interface ObjectConstructor {
|
||||
setPrototypeOf(o: any, proto: any): any;
|
||||
|
||||
/**
|
||||
* Gets the own property descriptor of the specified object.
|
||||
* An own property descriptor is one that is defined directly on the object and is not
|
||||
* inherited from the object's prototype.
|
||||
* Gets the own property descriptor of the specified object.
|
||||
* An own property descriptor is one that is defined directly on the object and is not
|
||||
* inherited from the object's prototype.
|
||||
* @param o Object that contains the property.
|
||||
* @param p Name of the property.
|
||||
*/
|
||||
getOwnPropertyDescriptor(o: any, propertyKey: PropertyKey): PropertyDescriptor;
|
||||
|
||||
/**
|
||||
* Adds a property to an object, or modifies attributes of an existing property.
|
||||
* @param o Object on which to add or modify the property. This can be a native JavaScript
|
||||
* Adds a property to an object, or modifies attributes of an existing property.
|
||||
* @param o Object on which to add or modify the property. This can be a native JavaScript
|
||||
* object (that is, a user-defined object or a built in object) or a DOM object.
|
||||
* @param p The property name.
|
||||
* @param attributes Descriptor for the property. It can be for a data property or an accessor
|
||||
@@ -358,47 +358,60 @@ interface RegExp {
|
||||
*/
|
||||
readonly flags: string;
|
||||
|
||||
/**
|
||||
* Returns a Boolean value indicating the state of the sticky flag (y) used with a regular
|
||||
* expression. Default is false. Read-only.
|
||||
/**
|
||||
* Returns a Boolean value indicating the state of the sticky flag (y) used with a regular
|
||||
* expression. Default is false. Read-only.
|
||||
*/
|
||||
readonly sticky: boolean;
|
||||
|
||||
/**
|
||||
* Returns a Boolean value indicating the state of the Unicode flag (u) used with a regular
|
||||
* expression. Default is false. Read-only.
|
||||
/**
|
||||
* Returns a Boolean value indicating the state of the Unicode flag (u) used with a regular
|
||||
* expression. Default is false. Read-only.
|
||||
*/
|
||||
readonly unicode: boolean;
|
||||
}
|
||||
|
||||
interface RegExpConstructor {
|
||||
new (pattern: RegExp, flags?: string): RegExp;
|
||||
(pattern: RegExp, flags?: string): RegExp;
|
||||
}
|
||||
|
||||
interface String {
|
||||
/**
|
||||
* Returns a nonnegative integer Number less than 1114112 (0x110000) that is the code point
|
||||
* value of the UTF-16 encoded code point starting at the string element at position pos in
|
||||
* the String resulting from converting this object to a String.
|
||||
* If there is no element at that position, the result is undefined.
|
||||
* Returns a nonnegative integer Number less than 1114112 (0x110000) that is the code point
|
||||
* value of the UTF-16 encoded code point starting at the string element at position pos in
|
||||
* the String resulting from converting this object to a String.
|
||||
* If there is no element at that position, the result is undefined.
|
||||
* If a valid UTF-16 surrogate pair does not begin at pos, the result is the code unit at pos.
|
||||
*/
|
||||
codePointAt(pos: number): number | undefined;
|
||||
|
||||
/**
|
||||
* Returns true if searchString appears as a substring of the result of converting this
|
||||
* object to a String, at one or more positions that are
|
||||
* Returns true if searchString appears as a substring of the result of converting this
|
||||
* object to a String, at one or more positions that are
|
||||
* greater than or equal to position; otherwise, returns false.
|
||||
* @param searchString search string
|
||||
* @param searchString search string
|
||||
* @param position If position is undefined, 0 is assumed, so as to search all of the String.
|
||||
*/
|
||||
includes(searchString: string, position?: number): boolean;
|
||||
|
||||
/**
|
||||
* Returns true if the sequence of elements of searchString converted to a String is the
|
||||
* same as the corresponding elements of this object (converted to a String) starting at
|
||||
* Returns true if the sequence of elements of searchString converted to a String is the
|
||||
* same as the corresponding elements of this object (converted to a String) starting at
|
||||
* endPosition – length(this). Otherwise returns false.
|
||||
*/
|
||||
endsWith(searchString: string, endPosition?: number): boolean;
|
||||
|
||||
/**
|
||||
* Returns the String value result of normalizing the string into the normalization form
|
||||
* Returns the String value result of normalizing the string into the normalization form
|
||||
* named by form as specified in Unicode Standard Annex #15, Unicode Normalization Forms.
|
||||
* @param form Applicable values: "NFC", "NFD", "NFKC", or "NFKD", If not specified default
|
||||
* is "NFC"
|
||||
*/
|
||||
normalize(form: "NFC" | "NFD" | "NFKC" | "NFKD"): string;
|
||||
|
||||
/**
|
||||
* Returns the String value result of normalizing the string into the normalization form
|
||||
* named by form as specified in Unicode Standard Annex #15, Unicode Normalization Forms.
|
||||
* @param form Applicable values: "NFC", "NFD", "NFKC", or "NFKD", If not specified default
|
||||
* is "NFC"
|
||||
@@ -406,15 +419,15 @@ interface String {
|
||||
normalize(form?: string): string;
|
||||
|
||||
/**
|
||||
* Returns a String value that is made from count copies appended together. If count is 0,
|
||||
* Returns a String value that is made from count copies appended together. If count is 0,
|
||||
* T is the empty String is returned.
|
||||
* @param count number of copies to append
|
||||
*/
|
||||
repeat(count: number): string;
|
||||
|
||||
/**
|
||||
* Returns true if the sequence of elements of searchString converted to a String is the
|
||||
* same as the corresponding elements of this object (converted to a String) starting at
|
||||
* Returns true if the sequence of elements of searchString converted to a String is the
|
||||
* same as the corresponding elements of this object (converted to a String) starting at
|
||||
* position. Otherwise returns false.
|
||||
*/
|
||||
startsWith(searchString: string, position?: number): boolean;
|
||||
@@ -474,10 +487,10 @@ interface StringConstructor {
|
||||
|
||||
/**
|
||||
* String.raw is intended for use as a tag function of a Tagged Template String. When called
|
||||
* as such the first argument will be a well formed template call site object and the rest
|
||||
* as such the first argument will be a well formed template call site object and the rest
|
||||
* parameter will contain the substitution values.
|
||||
* @param template A well-formed template string call site representation.
|
||||
* @param substitutions A set of substitution values.
|
||||
*/
|
||||
raw(template: TemplateStringsArray, ...substitutions: any[]): string;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+55
-3
@@ -1,8 +1,16 @@
|
||||
/// <reference path="lib.es2015.symbol.d.ts" />
|
||||
|
||||
interface SymbolConstructor {
|
||||
/**
|
||||
* A method that returns the default iterator for an object. Called by the semantics of the
|
||||
* for-of statement.
|
||||
*/
|
||||
readonly iterator: symbol;
|
||||
}
|
||||
|
||||
interface IteratorResult<T> {
|
||||
done: boolean;
|
||||
value?: T;
|
||||
value: T;
|
||||
}
|
||||
|
||||
interface Iterator<T> {
|
||||
@@ -11,11 +19,18 @@ interface Iterator<T> {
|
||||
throw?(e?: any): IteratorResult<T>;
|
||||
}
|
||||
|
||||
interface Iterable<T> { }
|
||||
interface Iterable<T> {
|
||||
[Symbol.iterator](): Iterator<T>;
|
||||
}
|
||||
|
||||
interface IterableIterator<T> extends Iterator<T> { }
|
||||
interface IterableIterator<T> extends Iterator<T> {
|
||||
[Symbol.iterator](): IterableIterator<T>;
|
||||
}
|
||||
|
||||
interface Array<T> {
|
||||
/** Iterator */
|
||||
[Symbol.iterator](): IterableIterator<T>;
|
||||
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
@@ -48,7 +63,13 @@ interface ArrayConstructor {
|
||||
from<T>(iterable: Iterable<T>): Array<T>;
|
||||
}
|
||||
|
||||
interface IArguments {
|
||||
/** Iterator */
|
||||
[Symbol.iterator](): IterableIterator<any>;
|
||||
}
|
||||
|
||||
interface Map<K, V> {
|
||||
[Symbol.iterator](): IterableIterator<[K,V]>;
|
||||
entries(): IterableIterator<[K, V]>;
|
||||
keys(): IterableIterator<K>;
|
||||
values(): IterableIterator<V>;
|
||||
@@ -64,6 +85,23 @@ interface WeakMapConstructor {
|
||||
new <K, V>(iterable: Iterable<[K, V]>): WeakMap<K, V>;
|
||||
}
|
||||
|
||||
interface Set<T> {
|
||||
[Symbol.iterator](): IterableIterator<T>;
|
||||
entries(): IterableIterator<[T, T]>;
|
||||
keys(): IterableIterator<T>;
|
||||
values(): IterableIterator<T>;
|
||||
}
|
||||
|
||||
interface SetConstructor {
|
||||
new <T>(iterable: Iterable<T>): Set<T>;
|
||||
}
|
||||
|
||||
interface WeakSet<T> { }
|
||||
|
||||
interface WeakSetConstructor {
|
||||
new <T>(iterable: Iterable<T>): WeakSet<T>;
|
||||
}
|
||||
|
||||
interface Promise<T> { }
|
||||
|
||||
interface PromiseConstructor {
|
||||
@@ -88,11 +126,17 @@ declare namespace Reflect {
|
||||
function enumerate(target: any): IterableIterator<any>;
|
||||
}
|
||||
|
||||
interface String {
|
||||
/** Iterator */
|
||||
[Symbol.iterator](): IterableIterator<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit integer values. The contents are initialized to 0. If the requested
|
||||
* number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int8Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
@@ -124,6 +168,7 @@ interface Int8ArrayConstructor {
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint8Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
@@ -155,6 +200,7 @@ interface Uint8ArrayConstructor {
|
||||
* If the requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint8ClampedArray {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
@@ -189,6 +235,7 @@ interface Uint8ClampedArrayConstructor {
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int16Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
@@ -222,6 +269,7 @@ interface Int16ArrayConstructor {
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint16Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
@@ -253,6 +301,7 @@ interface Uint16ArrayConstructor {
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int32Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
@@ -284,6 +333,7 @@ interface Int32ArrayConstructor {
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint32Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
@@ -315,6 +365,7 @@ interface Uint32ArrayConstructor {
|
||||
* of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Float32Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
@@ -346,6 +397,7 @@ interface Float32ArrayConstructor {
|
||||
* number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Float64Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the array
|
||||
*/
|
||||
|
||||
Vendored
+105
-15
@@ -3,59 +3,149 @@
|
||||
*/
|
||||
interface Promise<T> {
|
||||
/**
|
||||
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
||||
* @param onfulfilled The callback to execute when the Promise is resolved.
|
||||
* @param onrejected The callback to execute when the Promise is rejected.
|
||||
* @returns A Promise for the completion of which ever callback is executed.
|
||||
*/
|
||||
then<TResult>(onfulfilled?: (value: T) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => TResult | PromiseLike<TResult>): Promise<TResult>;
|
||||
then<TResult>(onfulfilled?: (value: T) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => void): Promise<TResult>;
|
||||
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
||||
* @param onfulfilled The callback to execute when the Promise is resolved.
|
||||
* @param onrejected The callback to execute when the Promise is rejected.
|
||||
* @returns A Promise for the completion of which ever callback is executed.
|
||||
*/
|
||||
then<TResult1, TResult2>(onfulfilled: (value: T) => TResult1 | PromiseLike<TResult1>, onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>): Promise<TResult1 | TResult2>;
|
||||
|
||||
/**
|
||||
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
||||
* @param onfulfilled The callback to execute when the Promise is resolved.
|
||||
* @param onrejected The callback to execute when the Promise is rejected.
|
||||
* @returns A Promise for the completion of which ever callback is executed.
|
||||
*/
|
||||
then<TResult>(onfulfilled: (value: T) => TResult | PromiseLike<TResult>, onrejected: (reason: any) => TResult | PromiseLike<TResult>): Promise<TResult>;
|
||||
|
||||
/**
|
||||
* Attaches callbacks for the resolution and/or rejection of the Promise.
|
||||
* @param onfulfilled The callback to execute when the Promise is resolved.
|
||||
* @returns A Promise for the completion of which ever callback is executed.
|
||||
*/
|
||||
then<TResult>(onfulfilled: (value: T) => TResult | PromiseLike<TResult>): Promise<TResult>;
|
||||
|
||||
/**
|
||||
* Creates a new Promise with the same internal state of this Promise.
|
||||
* @returns A Promise.
|
||||
*/
|
||||
then(): Promise<T>;
|
||||
|
||||
/**
|
||||
* Attaches a callback for only the rejection of the Promise.
|
||||
* @param onrejected The callback to execute when the Promise is rejected.
|
||||
* @returns A Promise for the completion of the callback.
|
||||
*/
|
||||
catch(onrejected?: (reason: any) => T | PromiseLike<T>): Promise<T>;
|
||||
catch(onrejected?: (reason: any) => void): Promise<T>;
|
||||
catch<TResult>(onrejected: (reason: any) => TResult | PromiseLike<TResult>): Promise<T | TResult>;
|
||||
|
||||
/**
|
||||
* Attaches a callback for only the rejection of the Promise.
|
||||
* @param onrejected The callback to execute when the Promise is rejected.
|
||||
* @returns A Promise for the completion of the callback.
|
||||
*/
|
||||
catch(onrejected: (reason: any) => T | PromiseLike<T>): Promise<T>;
|
||||
}
|
||||
|
||||
interface PromiseConstructor {
|
||||
/**
|
||||
* A reference to the prototype.
|
||||
/**
|
||||
* A reference to the prototype.
|
||||
*/
|
||||
readonly prototype: Promise<any>;
|
||||
|
||||
/**
|
||||
* Creates a new Promise.
|
||||
* @param executor A callback used to initialize the promise. This callback is passed two arguments:
|
||||
* a resolve callback used resolve the promise with a value or the result of another promise,
|
||||
* @param executor A callback used to initialize the promise. This callback is passed two arguments:
|
||||
* a resolve callback used resolve the promise with a value or the result of another promise,
|
||||
* and a reject callback used to reject the promise with a provided reason or error.
|
||||
*/
|
||||
new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>, T10 | PromiseLike<T10>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2, T3, T4, T5, T6, T7, T8, T9>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2, T3, T4, T5, T6, T7, T8>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2, T3, T4, T5, T6, T7>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>]): Promise<[T1, T2, T3, T4, T5, T6, T7]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2, T3, T4, T5, T6>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>]): Promise<[T1, T2, T3, T4, T5, T6]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2, T3, T4, T5>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>]): Promise<[T1, T2, T3, T4, T5]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2, T3, T4>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>]): Promise<[T1, T2, T3, T4]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2, T3>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>]): Promise<[T1, T2, T3]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<[T1, T2]>;
|
||||
|
||||
/**
|
||||
* Creates a Promise that is resolved with an array of results when all of the provided Promises
|
||||
* resolve, or rejected when any Promise is rejected.
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T>(values: (T | PromiseLike<T>)[]): Promise<T[]>;
|
||||
|
||||
/**
|
||||
* Creates a new rejected promise for the provided reason.
|
||||
* @param reason The reason the promise was rejected.
|
||||
* @returns A new rejected Promise.
|
||||
*/
|
||||
reject(reason: any): Promise<void>;
|
||||
reject(reason: any): Promise<never>;
|
||||
|
||||
/**
|
||||
* Creates a new rejected promise for the provided reason.
|
||||
|
||||
Vendored
+8
-37
@@ -13,12 +13,6 @@ interface SymbolConstructor {
|
||||
*/
|
||||
readonly isConcatSpreadable: symbol;
|
||||
|
||||
/**
|
||||
* A method that returns the default iterator for an object. Called by the semantics of the
|
||||
* for-of statement.
|
||||
*/
|
||||
readonly iterator: symbol;
|
||||
|
||||
/**
|
||||
* A regular expression method that matches the regular expression against a string. Called
|
||||
* by the String.prototype.match method.
|
||||
@@ -73,9 +67,6 @@ interface Symbol {
|
||||
}
|
||||
|
||||
interface Array<T> {
|
||||
/** Iterator */
|
||||
[Symbol.iterator](): IterableIterator<T>;
|
||||
|
||||
/**
|
||||
* Returns an object whose properties have the value 'true'
|
||||
* when they will be absent when used in a 'with' statement.
|
||||
@@ -116,7 +107,6 @@ interface Date {
|
||||
}
|
||||
|
||||
interface Map<K, V> {
|
||||
[Symbol.iterator]():IterableIterator<[K,V]>;
|
||||
readonly [Symbol.toStringTag]: "Map";
|
||||
}
|
||||
|
||||
@@ -124,6 +114,14 @@ interface WeakMap<K, V>{
|
||||
readonly [Symbol.toStringTag]: "WeakMap";
|
||||
}
|
||||
|
||||
interface Set<T> {
|
||||
readonly [Symbol.toStringTag]: "Set";
|
||||
}
|
||||
|
||||
interface WeakSet<T> {
|
||||
readonly [Symbol.toStringTag]: "WeakSet";
|
||||
}
|
||||
|
||||
interface JSON {
|
||||
readonly [Symbol.toStringTag]: "JSON";
|
||||
}
|
||||
@@ -143,21 +141,6 @@ interface GeneratorFunction extends Function {
|
||||
readonly [Symbol.toStringTag]: "GeneratorFunction";
|
||||
}
|
||||
|
||||
interface IArguments {
|
||||
/** Iterator */
|
||||
[Symbol.iterator](): IterableIterator<any>;
|
||||
}
|
||||
|
||||
interface Iterator<T> { }
|
||||
|
||||
interface Iterable<T> {
|
||||
[Symbol.iterator](): Iterator<T>;
|
||||
}
|
||||
|
||||
interface IterableIterator<T> extends Iterator<T> {
|
||||
[Symbol.iterator](): IterableIterator<T>;
|
||||
}
|
||||
|
||||
interface Math {
|
||||
readonly [Symbol.toStringTag]: "Math";
|
||||
}
|
||||
@@ -223,9 +206,6 @@ interface RegExpConstructor {
|
||||
}
|
||||
|
||||
interface String {
|
||||
/** Iterator */
|
||||
[Symbol.iterator](): IterableIterator<string>;
|
||||
|
||||
/**
|
||||
* Matches a string an object that supports being matched against, and returns an array containing the results of that search.
|
||||
* @param matcher An object that supports being matched against.
|
||||
@@ -279,7 +259,6 @@ interface DataView {
|
||||
* number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int8Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
readonly [Symbol.toStringTag]: "Int8Array";
|
||||
}
|
||||
|
||||
@@ -288,7 +267,6 @@ interface Int8Array {
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint8Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
readonly [Symbol.toStringTag]: "UInt8Array";
|
||||
}
|
||||
|
||||
@@ -297,7 +275,6 @@ interface Uint8Array {
|
||||
* If the requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint8ClampedArray {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
readonly [Symbol.toStringTag]: "Uint8ClampedArray";
|
||||
}
|
||||
|
||||
@@ -306,7 +283,6 @@ interface Uint8ClampedArray {
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int16Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
readonly [Symbol.toStringTag]: "Int16Array";
|
||||
}
|
||||
|
||||
@@ -315,7 +291,6 @@ interface Int16Array {
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint16Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
readonly [Symbol.toStringTag]: "Uint16Array";
|
||||
}
|
||||
|
||||
@@ -324,7 +299,6 @@ interface Uint16Array {
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Int32Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
readonly [Symbol.toStringTag]: "Int32Array";
|
||||
}
|
||||
|
||||
@@ -333,7 +307,6 @@ interface Int32Array {
|
||||
* requested number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Uint32Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
readonly [Symbol.toStringTag]: "Uint32Array";
|
||||
}
|
||||
|
||||
@@ -342,7 +315,6 @@ interface Uint32Array {
|
||||
* of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Float32Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
readonly [Symbol.toStringTag]: "Float32Array";
|
||||
}
|
||||
|
||||
@@ -351,6 +323,5 @@ interface Float32Array {
|
||||
* number of bytes could not be allocated an exception is raised.
|
||||
*/
|
||||
interface Float64Array {
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
readonly [Symbol.toStringTag]: "Float64Array";
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
/// <reference path="lib.es2016.d.ts" />
|
||||
/// <reference path="lib.es2017.object.d.ts" />
|
||||
/// <reference path="lib.es2017.sharedmemory.d.ts" />
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
interface ObjectConstructor {
|
||||
/**
|
||||
* Returns an array of values of the enumerable properties of an object
|
||||
* @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
|
||||
*/
|
||||
values<T>(o: { [s: string]: T }): T[];
|
||||
values(o: any): any[];
|
||||
/**
|
||||
* Returns an array of key/values of the enumerable properties of an object
|
||||
* @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
|
||||
*/
|
||||
entries<T>(o: { [s: string]: T }): [string, T][];
|
||||
entries(o: any): [string, any][];
|
||||
}
|
||||
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
/// <reference path="lib.es2015.symbol.d.ts" />
|
||||
/// <reference path="lib.es2015.symbol.wellknown.d.ts" />
|
||||
|
||||
interface SharedArrayBuffer {
|
||||
/**
|
||||
* Read-only. The length of the ArrayBuffer (in bytes).
|
||||
*/
|
||||
readonly byteLength: number;
|
||||
|
||||
/*
|
||||
* The SharedArrayBuffer constructor's length property whose value is 1.
|
||||
*/
|
||||
length: number;
|
||||
/**
|
||||
* Returns a section of an SharedArrayBuffer.
|
||||
*/
|
||||
slice(begin:number, end?:number): SharedArrayBuffer;
|
||||
readonly [Symbol.species]: SharedArrayBuffer;
|
||||
readonly [Symbol.toStringTag]: "SharedArrayBuffer";
|
||||
}
|
||||
|
||||
interface SharedArrayBufferConstructor {
|
||||
readonly prototype: SharedArrayBuffer;
|
||||
new (byteLength: number): SharedArrayBuffer;
|
||||
}
|
||||
|
||||
declare var SharedArrayBuffer: SharedArrayBufferConstructor;
|
||||
Vendored
+851
-835
File diff suppressed because it is too large
Load Diff
Vendored
+229
-19
@@ -3,11 +3,29 @@
|
||||
/// IE Worker APIs
|
||||
/////////////////////////////
|
||||
|
||||
interface Algorithm {
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface EventInit {
|
||||
bubbles?: boolean;
|
||||
cancelable?: boolean;
|
||||
}
|
||||
|
||||
interface IDBIndexParameters {
|
||||
multiEntry?: boolean;
|
||||
unique?: boolean;
|
||||
}
|
||||
|
||||
interface IDBObjectStoreParameters {
|
||||
autoIncrement?: boolean;
|
||||
keyPath?: IDBKeyPath;
|
||||
}
|
||||
|
||||
interface KeyAlgorithm {
|
||||
name?: string;
|
||||
}
|
||||
|
||||
interface EventListener {
|
||||
(evt: Event): void;
|
||||
}
|
||||
@@ -84,12 +102,12 @@ declare var Console: {
|
||||
|
||||
interface Coordinates {
|
||||
readonly accuracy: number;
|
||||
readonly altitude: number;
|
||||
readonly altitudeAccuracy: number;
|
||||
readonly heading: number;
|
||||
readonly altitude: number | null;
|
||||
readonly altitudeAccuracy: number | null;
|
||||
readonly heading: number | null;
|
||||
readonly latitude: number;
|
||||
readonly longitude: number;
|
||||
readonly speed: number;
|
||||
readonly speed: number | null;
|
||||
}
|
||||
|
||||
declare var Coordinates: {
|
||||
@@ -97,6 +115,18 @@ declare var Coordinates: {
|
||||
new(): Coordinates;
|
||||
}
|
||||
|
||||
interface CryptoKey {
|
||||
readonly algorithm: KeyAlgorithm;
|
||||
readonly extractable: boolean;
|
||||
readonly type: string;
|
||||
readonly usages: string[];
|
||||
}
|
||||
|
||||
declare var CryptoKey: {
|
||||
prototype: CryptoKey;
|
||||
new(): CryptoKey;
|
||||
}
|
||||
|
||||
interface DOMError {
|
||||
readonly name: string;
|
||||
toString(): string;
|
||||
@@ -176,7 +206,7 @@ declare var DOMException: {
|
||||
interface DOMStringList {
|
||||
readonly length: number;
|
||||
contains(str: string): boolean;
|
||||
item(index: number): string;
|
||||
item(index: number): string | null;
|
||||
[index: number]: string;
|
||||
}
|
||||
|
||||
@@ -313,7 +343,7 @@ interface IDBDatabase extends EventTarget {
|
||||
readonly name: string;
|
||||
readonly objectStoreNames: DOMStringList;
|
||||
onabort: (ev: Event) => any;
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
version: number;
|
||||
onversionchange: (ev: IDBVersionChangeEvent) => any;
|
||||
close(): void;
|
||||
@@ -416,7 +446,7 @@ declare var IDBOpenDBRequest: {
|
||||
|
||||
interface IDBRequest extends EventTarget {
|
||||
readonly error: DOMError;
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
onsuccess: (ev: Event) => any;
|
||||
readonly readyState: string;
|
||||
readonly result: any;
|
||||
@@ -438,7 +468,7 @@ interface IDBTransaction extends EventTarget {
|
||||
readonly mode: string;
|
||||
onabort: (ev: Event) => any;
|
||||
oncomplete: (ev: Event) => any;
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
abort(): void;
|
||||
objectStore(name: string): IDBObjectStore;
|
||||
readonly READ_ONLY: string;
|
||||
@@ -459,7 +489,7 @@ declare var IDBTransaction: {
|
||||
}
|
||||
|
||||
interface IDBVersionChangeEvent extends Event {
|
||||
readonly newVersion: number;
|
||||
readonly newVersion: number | null;
|
||||
readonly oldVersion: number;
|
||||
}
|
||||
|
||||
@@ -506,7 +536,7 @@ declare var MSApp: MSApp;
|
||||
interface MSAppAsyncOperation extends EventTarget {
|
||||
readonly error: DOMError;
|
||||
oncomplete: (ev: Event) => any;
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
readonly readyState: number;
|
||||
readonly result: any;
|
||||
start(): void;
|
||||
@@ -655,7 +685,7 @@ interface WebSocket extends EventTarget {
|
||||
readonly bufferedAmount: number;
|
||||
readonly extensions: string;
|
||||
onclose: (ev: CloseEvent) => any;
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
onmessage: (ev: MessageEvent) => any;
|
||||
onopen: (ev: Event) => any;
|
||||
readonly protocol: string;
|
||||
@@ -698,7 +728,6 @@ declare var Worker: {
|
||||
}
|
||||
|
||||
interface XMLHttpRequest extends EventTarget, XMLHttpRequestEventTarget {
|
||||
msCaching: string;
|
||||
onreadystatechange: (ev: ProgressEvent) => any;
|
||||
readonly readyState: number;
|
||||
readonly response: any;
|
||||
@@ -710,9 +739,10 @@ interface XMLHttpRequest extends EventTarget, XMLHttpRequestEventTarget {
|
||||
timeout: number;
|
||||
readonly upload: XMLHttpRequestUpload;
|
||||
withCredentials: boolean;
|
||||
msCaching?: string;
|
||||
abort(): void;
|
||||
getAllResponseHeaders(): string;
|
||||
getResponseHeader(header: string): string;
|
||||
getResponseHeader(header: string): string | null;
|
||||
msCachingEnabled(): boolean;
|
||||
open(method: string, url: string, async?: boolean, user?: string, password?: string): void;
|
||||
overrideMimeType(mime: string): void;
|
||||
@@ -756,14 +786,14 @@ declare var XMLHttpRequestUpload: {
|
||||
}
|
||||
|
||||
interface AbstractWorker {
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
|
||||
}
|
||||
|
||||
interface MSBaseReader {
|
||||
onabort: (ev: Event) => any;
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
onload: (ev: Event) => any;
|
||||
onloadend: (ev: ProgressEvent) => any;
|
||||
onloadstart: (ev: Event) => any;
|
||||
@@ -809,7 +839,7 @@ interface WindowConsole {
|
||||
|
||||
interface XMLHttpRequestEventTarget {
|
||||
onabort: (ev: Event) => any;
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
onload: (ev: Event) => any;
|
||||
onloadend: (ev: ProgressEvent) => any;
|
||||
onloadstart: (ev: Event) => any;
|
||||
@@ -839,7 +869,7 @@ declare var FileReaderSync: {
|
||||
|
||||
interface WorkerGlobalScope extends EventTarget, WorkerUtils, DedicatedWorkerGlobalScope, WindowConsole {
|
||||
readonly location: WorkerLocation;
|
||||
onerror: (ev: Event) => any;
|
||||
onerror: (ev: ErrorEvent) => any;
|
||||
readonly self: WorkerGlobalScope;
|
||||
close(): void;
|
||||
msWriteProfilerMark(profilerMarkName: string): void;
|
||||
@@ -895,8 +925,11 @@ interface WorkerUtils extends Object, WindowBase64 {
|
||||
clearInterval(handle: number): void;
|
||||
clearTimeout(handle: number): void;
|
||||
importScripts(...urls: string[]): void;
|
||||
setImmediate(handler: (...args: any[]) => void): number;
|
||||
setImmediate(handler: any, ...args: any[]): number;
|
||||
setInterval(handler: (...args: any[]) => void, timeout: number): number;
|
||||
setInterval(handler: any, timeout?: any, ...args: any[]): number;
|
||||
setTimeout(handler: (...args: any[]) => void, timeout: number): number;
|
||||
setTimeout(handler: any, timeout?: any, ...args: any[]): number;
|
||||
}
|
||||
|
||||
@@ -932,6 +965,177 @@ interface ProgressEventInit extends EventInit {
|
||||
interface IDBArrayKey extends Array<IDBValidKey> {
|
||||
}
|
||||
|
||||
interface RsaKeyGenParams extends Algorithm {
|
||||
modulusLength: number;
|
||||
publicExponent: Uint8Array;
|
||||
}
|
||||
|
||||
interface RsaHashedKeyGenParams extends RsaKeyGenParams {
|
||||
hash: AlgorithmIdentifier;
|
||||
}
|
||||
|
||||
interface RsaKeyAlgorithm extends KeyAlgorithm {
|
||||
modulusLength: number;
|
||||
publicExponent: Uint8Array;
|
||||
}
|
||||
|
||||
interface RsaHashedKeyAlgorithm extends RsaKeyAlgorithm {
|
||||
hash: AlgorithmIdentifier;
|
||||
}
|
||||
|
||||
interface RsaHashedImportParams {
|
||||
hash: AlgorithmIdentifier;
|
||||
}
|
||||
|
||||
interface RsaPssParams {
|
||||
saltLength: number;
|
||||
}
|
||||
|
||||
interface RsaOaepParams extends Algorithm {
|
||||
label?: BufferSource;
|
||||
}
|
||||
|
||||
interface EcdsaParams extends Algorithm {
|
||||
hash: AlgorithmIdentifier;
|
||||
}
|
||||
|
||||
interface EcKeyGenParams extends Algorithm {
|
||||
typedCurve: string;
|
||||
}
|
||||
|
||||
interface EcKeyAlgorithm extends KeyAlgorithm {
|
||||
typedCurve: string;
|
||||
}
|
||||
|
||||
interface EcKeyImportParams {
|
||||
namedCurve: string;
|
||||
}
|
||||
|
||||
interface EcdhKeyDeriveParams extends Algorithm {
|
||||
public: CryptoKey;
|
||||
}
|
||||
|
||||
interface AesCtrParams extends Algorithm {
|
||||
counter: BufferSource;
|
||||
length: number;
|
||||
}
|
||||
|
||||
interface AesKeyAlgorithm extends KeyAlgorithm {
|
||||
length: number;
|
||||
}
|
||||
|
||||
interface AesKeyGenParams extends Algorithm {
|
||||
length: number;
|
||||
}
|
||||
|
||||
interface AesDerivedKeyParams extends Algorithm {
|
||||
length: number;
|
||||
}
|
||||
|
||||
interface AesCbcParams extends Algorithm {
|
||||
iv: BufferSource;
|
||||
}
|
||||
|
||||
interface AesCmacParams extends Algorithm {
|
||||
length: number;
|
||||
}
|
||||
|
||||
interface AesGcmParams extends Algorithm {
|
||||
iv: BufferSource;
|
||||
additionalData?: BufferSource;
|
||||
tagLength?: number;
|
||||
}
|
||||
|
||||
interface AesCfbParams extends Algorithm {
|
||||
iv: BufferSource;
|
||||
}
|
||||
|
||||
interface HmacImportParams extends Algorithm {
|
||||
hash?: AlgorithmIdentifier;
|
||||
length?: number;
|
||||
}
|
||||
|
||||
interface HmacKeyAlgorithm extends KeyAlgorithm {
|
||||
hash: AlgorithmIdentifier;
|
||||
length: number;
|
||||
}
|
||||
|
||||
interface HmacKeyGenParams extends Algorithm {
|
||||
hash: AlgorithmIdentifier;
|
||||
length?: number;
|
||||
}
|
||||
|
||||
interface DhKeyGenParams extends Algorithm {
|
||||
prime: Uint8Array;
|
||||
generator: Uint8Array;
|
||||
}
|
||||
|
||||
interface DhKeyAlgorithm extends KeyAlgorithm {
|
||||
prime: Uint8Array;
|
||||
generator: Uint8Array;
|
||||
}
|
||||
|
||||
interface DhKeyDeriveParams extends Algorithm {
|
||||
public: CryptoKey;
|
||||
}
|
||||
|
||||
interface DhImportKeyParams extends Algorithm {
|
||||
prime: Uint8Array;
|
||||
generator: Uint8Array;
|
||||
}
|
||||
|
||||
interface ConcatParams extends Algorithm {
|
||||
hash?: AlgorithmIdentifier;
|
||||
algorithmId: Uint8Array;
|
||||
partyUInfo: Uint8Array;
|
||||
partyVInfo: Uint8Array;
|
||||
publicInfo?: Uint8Array;
|
||||
privateInfo?: Uint8Array;
|
||||
}
|
||||
|
||||
interface HkdfCtrParams extends Algorithm {
|
||||
hash: AlgorithmIdentifier;
|
||||
label: BufferSource;
|
||||
context: BufferSource;
|
||||
}
|
||||
|
||||
interface Pbkdf2Params extends Algorithm {
|
||||
salt: BufferSource;
|
||||
iterations: number;
|
||||
hash: AlgorithmIdentifier;
|
||||
}
|
||||
|
||||
interface RsaOtherPrimesInfo {
|
||||
r: string;
|
||||
d: string;
|
||||
t: string;
|
||||
}
|
||||
|
||||
interface JsonWebKey {
|
||||
kty: string;
|
||||
use?: string;
|
||||
key_ops?: string[];
|
||||
alg?: string;
|
||||
kid?: string;
|
||||
x5u?: string;
|
||||
x5c?: string;
|
||||
x5t?: string;
|
||||
ext?: boolean;
|
||||
crv?: string;
|
||||
x?: string;
|
||||
y?: string;
|
||||
d?: string;
|
||||
n?: string;
|
||||
e?: string;
|
||||
p?: string;
|
||||
q?: string;
|
||||
dp?: string;
|
||||
dq?: string;
|
||||
qi?: string;
|
||||
oth?: RsaOtherPrimesInfo[];
|
||||
k?: string;
|
||||
}
|
||||
|
||||
declare type EventListenerOrEventListenerObject = EventListener | EventListenerObject;
|
||||
|
||||
interface ErrorEventHandler {
|
||||
@@ -965,7 +1169,7 @@ interface FunctionStringCallback {
|
||||
(data: string): void;
|
||||
}
|
||||
declare var location: WorkerLocation;
|
||||
declare var onerror: (ev: Event) => any;
|
||||
declare var onerror: (ev: ErrorEvent) => any;
|
||||
declare var self: WorkerGlobalScope;
|
||||
declare function close(): void;
|
||||
declare function msWriteProfilerMark(profilerMarkName: string): void;
|
||||
@@ -980,8 +1184,11 @@ declare function clearImmediate(handle: number): void;
|
||||
declare function clearInterval(handle: number): void;
|
||||
declare function clearTimeout(handle: number): void;
|
||||
declare function importScripts(...urls: string[]): void;
|
||||
declare function setImmediate(handler: (...args: any[]) => void): number;
|
||||
declare function setImmediate(handler: any, ...args: any[]): number;
|
||||
declare function setInterval(handler: (...args: any[]) => void, timeout: number): number;
|
||||
declare function setInterval(handler: any, timeout?: any, ...args: any[]): number;
|
||||
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): number;
|
||||
declare function setTimeout(handler: any, timeout?: any, ...args: any[]): number;
|
||||
declare function atob(encodedString: string): string;
|
||||
declare function btoa(rawString: string): string;
|
||||
@@ -991,4 +1198,7 @@ declare var console: Console;
|
||||
declare function addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void;
|
||||
declare function addEventListener(type: "message", listener: (ev: MessageEvent) => any, useCapture?: boolean): void;
|
||||
declare function addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
|
||||
type IDBValidKey = number | string | Date | IDBArrayKey;
|
||||
type AlgorithmIdentifier = string | Algorithm;
|
||||
type IDBKeyPath = string;
|
||||
type IDBValidKey = number | string | Date | IDBArrayKey;
|
||||
type BufferSource = ArrayBuffer | ArrayBufferView;
|
||||
+184
-160
@@ -1,5 +1,5 @@
|
||||
/// <reference path="session.ts" />
|
||||
|
||||
|
||||
namespace ts.server {
|
||||
|
||||
export interface SessionClientHost extends LanguageServiceHost {
|
||||
@@ -21,37 +21,37 @@ namespace ts.server {
|
||||
|
||||
export class SessionClient implements LanguageService {
|
||||
private sequence: number = 0;
|
||||
private fileMapping: ts.Map<string> = {};
|
||||
private lineMaps: ts.Map<number[]> = {};
|
||||
private messages: string[] = [];
|
||||
private lastRenameEntry: RenameEntry;
|
||||
|
||||
|
||||
constructor(private host: SessionClientHost) {
|
||||
}
|
||||
|
||||
public onMessage(message: string): void {
|
||||
public onMessage(message: string): void {
|
||||
this.messages.push(message);
|
||||
}
|
||||
|
||||
private writeMessage(message: string): void {
|
||||
private writeMessage(message: string): void {
|
||||
this.host.writeMessage(message);
|
||||
}
|
||||
|
||||
private getLineMap(fileName: string): number[] {
|
||||
var lineMap = ts.lookUp(this.lineMaps, fileName);
|
||||
private getLineMap(fileName: string): number[] {
|
||||
let lineMap = ts.lookUp(this.lineMaps, fileName);
|
||||
if (!lineMap) {
|
||||
var scriptSnapshot = this.host.getScriptSnapshot(fileName);
|
||||
lineMap = this.lineMaps[fileName] = ts.computeLineStarts(scriptSnapshot.getText(0, scriptSnapshot.getLength()));
|
||||
const scriptSnapshot = this.host.getScriptSnapshot(fileName);
|
||||
lineMap = this.lineMaps[fileName] = ts.computeLineStarts(scriptSnapshot.getText(0, scriptSnapshot.getLength()));
|
||||
}
|
||||
return lineMap;
|
||||
}
|
||||
|
||||
private lineOffsetToPosition(fileName: string, lineOffset: protocol.Location): number {
|
||||
return ts.computePositionOfLineAndCharacter(this.getLineMap(fileName), lineOffset.line - 1, lineOffset.offset - 1);
|
||||
private lineOffsetToPosition(fileName: string, lineOffset: protocol.Location, lineMap?: number[]): number {
|
||||
lineMap = lineMap || this.getLineMap(fileName);
|
||||
return ts.computePositionOfLineAndCharacter(lineMap, lineOffset.line - 1, lineOffset.offset - 1);
|
||||
}
|
||||
|
||||
private positionToOneBasedLineOffset(fileName: string, position: number): protocol.Location {
|
||||
var lineOffset = ts.computeLineAndCharacterOfPosition(this.getLineMap(fileName), position);
|
||||
const lineOffset = ts.computeLineAndCharacterOfPosition(this.getLineMap(fileName), position);
|
||||
return {
|
||||
line: lineOffset.line + 1,
|
||||
offset: lineOffset.character + 1
|
||||
@@ -59,8 +59,8 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
private convertCodeEditsToTextChange(fileName: string, codeEdit: protocol.CodeEdit): ts.TextChange {
|
||||
var start = this.lineOffsetToPosition(fileName, codeEdit.start);
|
||||
var end = this.lineOffsetToPosition(fileName, codeEdit.end);
|
||||
const start = this.lineOffsetToPosition(fileName, codeEdit.start);
|
||||
const end = this.lineOffsetToPosition(fileName, codeEdit.end);
|
||||
|
||||
return {
|
||||
span: ts.createTextSpanFromBounds(start, end),
|
||||
@@ -69,12 +69,13 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
private processRequest<T extends protocol.Request>(command: string, args?: any): T {
|
||||
var request: protocol.Request = {
|
||||
seq: this.sequence++,
|
||||
const request: protocol.Request = {
|
||||
seq: this.sequence,
|
||||
type: "request",
|
||||
arguments: args,
|
||||
command
|
||||
};
|
||||
this.sequence++;
|
||||
|
||||
this.writeMessage(JSON.stringify(request));
|
||||
|
||||
@@ -82,34 +83,29 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
private processResponse<T extends protocol.Response>(request: protocol.Request): T {
|
||||
var lastMessage = this.messages.shift();
|
||||
Debug.assert(!!lastMessage, "Did not receive any responses.");
|
||||
|
||||
// Read the content length
|
||||
var contentLengthPrefix = "Content-Length: ";
|
||||
var lines = lastMessage.split("\r\n");
|
||||
Debug.assert(lines.length >= 2, "Malformed response: Expected 3 lines in the response.");
|
||||
|
||||
var contentLengthText = lines[0];
|
||||
Debug.assert(contentLengthText.indexOf(contentLengthPrefix) === 0, "Malformed response: Response text did not contain content-length header.");
|
||||
var contentLength = parseInt(contentLengthText.substring(contentLengthPrefix.length));
|
||||
|
||||
// Read the body
|
||||
var responseBody = lines[2];
|
||||
|
||||
// Verify content length
|
||||
Debug.assert(responseBody.length + 1 === contentLength, "Malformed response: Content length did not match the response's body length.");
|
||||
|
||||
try {
|
||||
var response: T = JSON.parse(responseBody);
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error("Malformed response: Failed to parse server response: " + lastMessage + ". \r\n Error details: " + e.message);
|
||||
let foundResponseMessage = false;
|
||||
let lastMessage: string;
|
||||
let response: T;
|
||||
while (!foundResponseMessage) {
|
||||
lastMessage = this.messages.shift();
|
||||
Debug.assert(!!lastMessage, "Did not receive any responses.");
|
||||
const responseBody = processMessage(lastMessage);
|
||||
try {
|
||||
response = JSON.parse(responseBody);
|
||||
// the server may emit events before emitting the response. We
|
||||
// want to ignore these events for testing purpose.
|
||||
if (response.type === "response") {
|
||||
foundResponseMessage = true;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error("Malformed response: Failed to parse server response: " + lastMessage + ". \r\n Error details: " + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
// verify the sequence numbers
|
||||
Debug.assert(response.request_seq === request.seq, "Malformed response: response sequence number did not match request sequence number.");
|
||||
|
||||
|
||||
// unmarshal errors
|
||||
if (!response.success) {
|
||||
throw new Error("Error " + response.message);
|
||||
@@ -118,15 +114,33 @@ namespace ts.server {
|
||||
Debug.assert(!!response.body, "Malformed response: Unexpected empty response body.");
|
||||
|
||||
return response;
|
||||
|
||||
function processMessage(message: string) {
|
||||
// Read the content length
|
||||
const contentLengthPrefix = "Content-Length: ";
|
||||
const lines = message.split("\r\n");
|
||||
Debug.assert(lines.length >= 2, "Malformed response: Expected 3 lines in the response.");
|
||||
|
||||
const contentLengthText = lines[0];
|
||||
Debug.assert(contentLengthText.indexOf(contentLengthPrefix) === 0, "Malformed response: Response text did not contain content-length header.");
|
||||
const contentLength = parseInt(contentLengthText.substring(contentLengthPrefix.length));
|
||||
|
||||
// Read the body
|
||||
const responseBody = lines[2];
|
||||
|
||||
// Verify content length
|
||||
Debug.assert(responseBody.length + 1 === contentLength, "Malformed response: Content length did not match the response's body length.");
|
||||
return responseBody;
|
||||
}
|
||||
}
|
||||
|
||||
openFile(fileName: string, content?: string): void {
|
||||
var args: protocol.OpenRequestArgs = { file: fileName, fileContent: content };
|
||||
openFile(fileName: string, content?: string, scriptKindName?: "TS" | "JS" | "TSX" | "JSX"): void {
|
||||
const args: protocol.OpenRequestArgs = { file: fileName, fileContent: content, scriptKindName };
|
||||
this.processRequest(CommandNames.Open, args);
|
||||
}
|
||||
|
||||
closeFile(fileName: string): void {
|
||||
var args: protocol.FileRequestArgs = { file: fileName };
|
||||
const args: protocol.FileRequestArgs = { file: fileName };
|
||||
this.processRequest(CommandNames.Close, args);
|
||||
}
|
||||
|
||||
@@ -134,10 +148,10 @@ namespace ts.server {
|
||||
// clear the line map after an edit
|
||||
this.lineMaps[fileName] = undefined;
|
||||
|
||||
var lineOffset = this.positionToOneBasedLineOffset(fileName, start);
|
||||
var endLineOffset = this.positionToOneBasedLineOffset(fileName, end);
|
||||
const lineOffset = this.positionToOneBasedLineOffset(fileName, start);
|
||||
const endLineOffset = this.positionToOneBasedLineOffset(fileName, end);
|
||||
|
||||
var args: protocol.ChangeRequestArgs = {
|
||||
const args: protocol.ChangeRequestArgs = {
|
||||
file: fileName,
|
||||
line: lineOffset.line,
|
||||
offset: lineOffset.offset,
|
||||
@@ -150,18 +164,18 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
getQuickInfoAtPosition(fileName: string, position: number): QuickInfo {
|
||||
var lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
var args: protocol.FileLocationRequestArgs = {
|
||||
const lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
const args: protocol.FileLocationRequestArgs = {
|
||||
file: fileName,
|
||||
line: lineOffset.line,
|
||||
offset: lineOffset.offset
|
||||
};
|
||||
|
||||
var request = this.processRequest<protocol.QuickInfoRequest>(CommandNames.Quickinfo, args);
|
||||
var response = this.processResponse<protocol.QuickInfoResponse>(request);
|
||||
const request = this.processRequest<protocol.QuickInfoRequest>(CommandNames.Quickinfo, args);
|
||||
const response = this.processResponse<protocol.QuickInfoResponse>(request);
|
||||
|
||||
var start = this.lineOffsetToPosition(fileName, response.body.start);
|
||||
var end = this.lineOffsetToPosition(fileName, response.body.end);
|
||||
const start = this.lineOffsetToPosition(fileName, response.body.start);
|
||||
const end = this.lineOffsetToPosition(fileName, response.body.end);
|
||||
|
||||
return {
|
||||
kind: response.body.kind,
|
||||
@@ -173,68 +187,68 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
getProjectInfo(fileName: string, needFileNameList: boolean): protocol.ProjectInfo {
|
||||
var args: protocol.ProjectInfoRequestArgs = {
|
||||
const args: protocol.ProjectInfoRequestArgs = {
|
||||
file: fileName,
|
||||
needFileNameList: needFileNameList
|
||||
};
|
||||
|
||||
var request = this.processRequest<protocol.ProjectInfoRequest>(CommandNames.ProjectInfo, args);
|
||||
var response = this.processResponse<protocol.ProjectInfoResponse>(request);
|
||||
const request = this.processRequest<protocol.ProjectInfoRequest>(CommandNames.ProjectInfo, args);
|
||||
const response = this.processResponse<protocol.ProjectInfoResponse>(request);
|
||||
|
||||
return {
|
||||
configFileName: response.body.configFileName,
|
||||
fileNames: response.body.fileNames
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
getCompletionsAtPosition(fileName: string, position: number): CompletionInfo {
|
||||
var lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
var args: protocol.CompletionsRequestArgs = {
|
||||
const lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
const args: protocol.CompletionsRequestArgs = {
|
||||
file: fileName,
|
||||
line: lineOffset.line,
|
||||
offset: lineOffset.offset,
|
||||
prefix: undefined
|
||||
};
|
||||
|
||||
var request = this.processRequest<protocol.CompletionsRequest>(CommandNames.Completions, args);
|
||||
var response = this.processResponse<protocol.CompletionsResponse>(request);
|
||||
const request = this.processRequest<protocol.CompletionsRequest>(CommandNames.Completions, args);
|
||||
const response = this.processResponse<protocol.CompletionsResponse>(request);
|
||||
|
||||
return {
|
||||
return {
|
||||
isMemberCompletion: false,
|
||||
isNewIdentifierLocation: false,
|
||||
entries: response.body
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails {
|
||||
var lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
var args: protocol.CompletionDetailsRequestArgs = {
|
||||
const lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
const args: protocol.CompletionDetailsRequestArgs = {
|
||||
file: fileName,
|
||||
line: lineOffset.line,
|
||||
offset: lineOffset.offset,
|
||||
entryNames: [entryName]
|
||||
};
|
||||
|
||||
var request = this.processRequest<protocol.CompletionDetailsRequest>(CommandNames.CompletionDetails, args);
|
||||
var response = this.processResponse<protocol.CompletionDetailsResponse>(request);
|
||||
const request = this.processRequest<protocol.CompletionDetailsRequest>(CommandNames.CompletionDetails, args);
|
||||
const response = this.processResponse<protocol.CompletionDetailsResponse>(request);
|
||||
Debug.assert(response.body.length === 1, "Unexpected length of completion details response body.");
|
||||
return response.body[0];
|
||||
}
|
||||
|
||||
getNavigateToItems(searchValue: string): NavigateToItem[] {
|
||||
var args: protocol.NavtoRequestArgs = {
|
||||
const args: protocol.NavtoRequestArgs = {
|
||||
searchValue,
|
||||
file: this.host.getScriptFileNames()[0]
|
||||
};
|
||||
|
||||
var request = this.processRequest<protocol.NavtoRequest>(CommandNames.Navto, args);
|
||||
var response = this.processResponse<protocol.NavtoResponse>(request);
|
||||
const request = this.processRequest<protocol.NavtoRequest>(CommandNames.Navto, args);
|
||||
const response = this.processResponse<protocol.NavtoResponse>(request);
|
||||
|
||||
return response.body.map(entry => {
|
||||
var fileName = entry.file;
|
||||
var start = this.lineOffsetToPosition(fileName, entry.start);
|
||||
var end = this.lineOffsetToPosition(fileName, entry.end);
|
||||
|
||||
const fileName = entry.file;
|
||||
const start = this.lineOffsetToPosition(fileName, entry.start);
|
||||
const end = this.lineOffsetToPosition(fileName, entry.end);
|
||||
|
||||
return {
|
||||
name: entry.name,
|
||||
containerName: entry.containerName || "",
|
||||
@@ -250,9 +264,9 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
getFormattingEditsForRange(fileName: string, start: number, end: number, options: ts.FormatCodeOptions): ts.TextChange[] {
|
||||
var startLineOffset = this.positionToOneBasedLineOffset(fileName, start);
|
||||
var endLineOffset = this.positionToOneBasedLineOffset(fileName, end);
|
||||
var args: protocol.FormatRequestArgs = {
|
||||
const startLineOffset = this.positionToOneBasedLineOffset(fileName, start);
|
||||
const endLineOffset = this.positionToOneBasedLineOffset(fileName, end);
|
||||
const args: protocol.FormatRequestArgs = {
|
||||
file: fileName,
|
||||
line: startLineOffset.line,
|
||||
offset: startLineOffset.offset,
|
||||
@@ -261,10 +275,10 @@ namespace ts.server {
|
||||
};
|
||||
|
||||
// TODO: handle FormatCodeOptions
|
||||
var request = this.processRequest<protocol.FormatRequest>(CommandNames.Format, args);
|
||||
var response = this.processResponse<protocol.FormatResponse>(request);
|
||||
const request = this.processRequest<protocol.FormatRequest>(CommandNames.Format, args);
|
||||
const response = this.processResponse<protocol.FormatResponse>(request);
|
||||
|
||||
return response.body.map(entry=> this.convertCodeEditsToTextChange(fileName, entry));
|
||||
return response.body.map(entry => this.convertCodeEditsToTextChange(fileName, entry));
|
||||
}
|
||||
|
||||
getFormattingEditsForDocument(fileName: string, options: ts.FormatCodeOptions): ts.TextChange[] {
|
||||
@@ -272,8 +286,8 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions): ts.TextChange[] {
|
||||
var lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
var args: protocol.FormatOnKeyRequestArgs = {
|
||||
const lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
const args: protocol.FormatOnKeyRequestArgs = {
|
||||
file: fileName,
|
||||
line: lineOffset.line,
|
||||
offset: lineOffset.offset,
|
||||
@@ -281,27 +295,27 @@ namespace ts.server {
|
||||
};
|
||||
|
||||
// TODO: handle FormatCodeOptions
|
||||
var request = this.processRequest<protocol.FormatOnKeyRequest>(CommandNames.Formatonkey, args);
|
||||
var response = this.processResponse<protocol.FormatResponse>(request);
|
||||
const request = this.processRequest<protocol.FormatOnKeyRequest>(CommandNames.Formatonkey, args);
|
||||
const response = this.processResponse<protocol.FormatResponse>(request);
|
||||
|
||||
return response.body.map(entry=> this.convertCodeEditsToTextChange(fileName, entry));
|
||||
return response.body.map(entry => this.convertCodeEditsToTextChange(fileName, entry));
|
||||
}
|
||||
|
||||
getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] {
|
||||
var lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
var args: protocol.FileLocationRequestArgs = {
|
||||
const lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
const args: protocol.FileLocationRequestArgs = {
|
||||
file: fileName,
|
||||
line: lineOffset.line,
|
||||
offset: lineOffset.offset,
|
||||
};
|
||||
|
||||
var request = this.processRequest<protocol.DefinitionRequest>(CommandNames.Definition, args);
|
||||
var response = this.processResponse<protocol.DefinitionResponse>(request);
|
||||
const request = this.processRequest<protocol.DefinitionRequest>(CommandNames.Definition, args);
|
||||
const response = this.processResponse<protocol.DefinitionResponse>(request);
|
||||
|
||||
return response.body.map(entry => {
|
||||
var fileName = entry.file;
|
||||
var start = this.lineOffsetToPosition(fileName, entry.start);
|
||||
var end = this.lineOffsetToPosition(fileName, entry.end);
|
||||
const fileName = entry.file;
|
||||
const start = this.lineOffsetToPosition(fileName, entry.start);
|
||||
const end = this.lineOffsetToPosition(fileName, entry.end);
|
||||
return {
|
||||
containerKind: "",
|
||||
containerName: "",
|
||||
@@ -314,20 +328,20 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] {
|
||||
var lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
var args: protocol.FileLocationRequestArgs = {
|
||||
const lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
const args: protocol.FileLocationRequestArgs = {
|
||||
file: fileName,
|
||||
line: lineOffset.line,
|
||||
offset: lineOffset.offset,
|
||||
};
|
||||
|
||||
var request = this.processRequest<protocol.TypeDefinitionRequest>(CommandNames.TypeDefinition, args);
|
||||
var response = this.processResponse<protocol.TypeDefinitionResponse>(request);
|
||||
const request = this.processRequest<protocol.TypeDefinitionRequest>(CommandNames.TypeDefinition, args);
|
||||
const response = this.processResponse<protocol.TypeDefinitionResponse>(request);
|
||||
|
||||
return response.body.map(entry => {
|
||||
var fileName = entry.file;
|
||||
var start = this.lineOffsetToPosition(fileName, entry.start);
|
||||
var end = this.lineOffsetToPosition(fileName, entry.end);
|
||||
const fileName = entry.file;
|
||||
const start = this.lineOffsetToPosition(fileName, entry.start);
|
||||
const end = this.lineOffsetToPosition(fileName, entry.end);
|
||||
return {
|
||||
containerKind: "",
|
||||
containerName: "",
|
||||
@@ -339,30 +353,31 @@ namespace ts.server {
|
||||
});
|
||||
}
|
||||
|
||||
findReferences(fileName: string, position: number): ReferencedSymbol[]{
|
||||
findReferences(fileName: string, position: number): ReferencedSymbol[] {
|
||||
// Not yet implemented.
|
||||
return [];
|
||||
}
|
||||
|
||||
getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] {
|
||||
var lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
var args: protocol.FileLocationRequestArgs = {
|
||||
const lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
const args: protocol.FileLocationRequestArgs = {
|
||||
file: fileName,
|
||||
line: lineOffset.line,
|
||||
offset: lineOffset.offset,
|
||||
};
|
||||
|
||||
var request = this.processRequest<protocol.ReferencesRequest>(CommandNames.References, args);
|
||||
var response = this.processResponse<protocol.ReferencesResponse>(request);
|
||||
const request = this.processRequest<protocol.ReferencesRequest>(CommandNames.References, args);
|
||||
const response = this.processResponse<protocol.ReferencesResponse>(request);
|
||||
|
||||
return response.body.refs.map(entry => {
|
||||
var fileName = entry.file;
|
||||
var start = this.lineOffsetToPosition(fileName, entry.start);
|
||||
var end = this.lineOffsetToPosition(fileName, entry.end);
|
||||
const fileName = entry.file;
|
||||
const start = this.lineOffsetToPosition(fileName, entry.start);
|
||||
const end = this.lineOffsetToPosition(fileName, entry.end);
|
||||
return {
|
||||
fileName: fileName,
|
||||
textSpan: ts.createTextSpanFromBounds(start, end),
|
||||
isWriteAccess: entry.isWriteAccess,
|
||||
isDefinition: entry.isDefinition,
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -384,8 +399,8 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
getRenameInfo(fileName: string, position: number, findInStrings?: boolean, findInComments?: boolean): RenameInfo {
|
||||
var lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
var args: protocol.RenameRequestArgs = {
|
||||
const lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
const args: protocol.RenameRequestArgs = {
|
||||
file: fileName,
|
||||
line: lineOffset.line,
|
||||
offset: lineOffset.offset,
|
||||
@@ -393,14 +408,14 @@ namespace ts.server {
|
||||
findInComments
|
||||
};
|
||||
|
||||
var request = this.processRequest<protocol.RenameRequest>(CommandNames.Rename, args);
|
||||
var response = this.processResponse<protocol.RenameResponse>(request);
|
||||
var locations: RenameLocation[] = [];
|
||||
const request = this.processRequest<protocol.RenameRequest>(CommandNames.Rename, args);
|
||||
const response = this.processResponse<protocol.RenameResponse>(request);
|
||||
const locations: RenameLocation[] = [];
|
||||
response.body.locs.map((entry: protocol.SpanGroup) => {
|
||||
var fileName = entry.file;
|
||||
const fileName = entry.file;
|
||||
entry.locs.map((loc: protocol.TextSpan) => {
|
||||
var start = this.lineOffsetToPosition(fileName, loc.start);
|
||||
var end = this.lineOffsetToPosition(fileName, loc.end);
|
||||
const start = this.lineOffsetToPosition(fileName, loc.start);
|
||||
const end = this.lineOffsetToPosition(fileName, loc.end);
|
||||
locations.push({
|
||||
textSpan: ts.createTextSpanFromBounds(start, end),
|
||||
fileName: fileName
|
||||
@@ -435,7 +450,7 @@ namespace ts.server {
|
||||
return this.lastRenameEntry.locations;
|
||||
}
|
||||
|
||||
decodeNavigationBarItems(items: protocol.NavigationBarItem[], fileName: string): NavigationBarItem[] {
|
||||
decodeNavigationBarItems(items: protocol.NavigationBarItem[], fileName: string, lineMap: number[]): NavigationBarItem[] {
|
||||
if (!items) {
|
||||
return [];
|
||||
}
|
||||
@@ -444,23 +459,27 @@ namespace ts.server {
|
||||
text: item.text,
|
||||
kind: item.kind,
|
||||
kindModifiers: item.kindModifiers || "",
|
||||
spans: item.spans.map(span=> createTextSpanFromBounds(this.lineOffsetToPosition(fileName, span.start), this.lineOffsetToPosition(fileName, span.end))),
|
||||
childItems: this.decodeNavigationBarItems(item.childItems, fileName),
|
||||
indent: 0,
|
||||
spans: item.spans.map(span =>
|
||||
createTextSpanFromBounds(
|
||||
this.lineOffsetToPosition(fileName, span.start, lineMap),
|
||||
this.lineOffsetToPosition(fileName, span.end, lineMap))),
|
||||
childItems: this.decodeNavigationBarItems(item.childItems, fileName, lineMap),
|
||||
indent: item.indent,
|
||||
bolded: false,
|
||||
grayed: false
|
||||
}));
|
||||
}
|
||||
|
||||
getNavigationBarItems(fileName: string): NavigationBarItem[] {
|
||||
var args: protocol.FileRequestArgs = {
|
||||
const args: protocol.FileRequestArgs = {
|
||||
file: fileName
|
||||
};
|
||||
|
||||
var request = this.processRequest<protocol.NavBarRequest>(CommandNames.NavBar, args);
|
||||
var response = this.processResponse<protocol.NavBarResponse>(request);
|
||||
const request = this.processRequest<protocol.NavBarRequest>(CommandNames.NavBar, args);
|
||||
const response = this.processResponse<protocol.NavBarResponse>(request);
|
||||
|
||||
return this.decodeNavigationBarItems(response.body, fileName);
|
||||
const lineMap = this.getLineMap(fileName);
|
||||
return this.decodeNavigationBarItems(response.body, fileName, lineMap);
|
||||
}
|
||||
|
||||
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TextSpan {
|
||||
@@ -472,26 +491,26 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
getSignatureHelpItems(fileName: string, position: number): SignatureHelpItems {
|
||||
var lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
var args: protocol.SignatureHelpRequestArgs = {
|
||||
const lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
const args: protocol.SignatureHelpRequestArgs = {
|
||||
file: fileName,
|
||||
line: lineOffset.line,
|
||||
offset: lineOffset.offset
|
||||
};
|
||||
|
||||
var request = this.processRequest<protocol.SignatureHelpRequest>(CommandNames.SignatureHelp, args);
|
||||
var response = this.processResponse<protocol.SignatureHelpResponse>(request);
|
||||
|
||||
|
||||
const request = this.processRequest<protocol.SignatureHelpRequest>(CommandNames.SignatureHelp, args);
|
||||
const response = this.processResponse<protocol.SignatureHelpResponse>(request);
|
||||
|
||||
if (!response.body) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var helpItems: protocol.SignatureHelpItems = response.body;
|
||||
var span = helpItems.applicableSpan;
|
||||
var start = this.lineOffsetToPosition(fileName, span.start);
|
||||
var end = this.lineOffsetToPosition(fileName, span.end);
|
||||
|
||||
var result: SignatureHelpItems = {
|
||||
const helpItems: protocol.SignatureHelpItems = response.body;
|
||||
const span = helpItems.applicableSpan;
|
||||
const start = this.lineOffsetToPosition(fileName, span.start);
|
||||
const end = this.lineOffsetToPosition(fileName, span.end);
|
||||
|
||||
const result: SignatureHelpItems = {
|
||||
items: helpItems.items,
|
||||
applicableSpan: {
|
||||
start: start,
|
||||
@@ -499,46 +518,47 @@ namespace ts.server {
|
||||
},
|
||||
selectedItemIndex: helpItems.selectedItemIndex,
|
||||
argumentIndex: helpItems.argumentIndex,
|
||||
argumentCount: helpItems.argumentCount,
|
||||
}
|
||||
argumentCount: helpItems.argumentCount,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[] {
|
||||
var lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
var args: protocol.FileLocationRequestArgs = {
|
||||
const lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
const args: protocol.FileLocationRequestArgs = {
|
||||
file: fileName,
|
||||
line: lineOffset.line,
|
||||
offset: lineOffset.offset,
|
||||
};
|
||||
|
||||
var request = this.processRequest<protocol.OccurrencesRequest>(CommandNames.Occurrences, args);
|
||||
var response = this.processResponse<protocol.OccurrencesResponse>(request);
|
||||
const request = this.processRequest<protocol.OccurrencesRequest>(CommandNames.Occurrences, args);
|
||||
const response = this.processResponse<protocol.OccurrencesResponse>(request);
|
||||
|
||||
return response.body.map(entry => {
|
||||
var fileName = entry.file;
|
||||
var start = this.lineOffsetToPosition(fileName, entry.start);
|
||||
var end = this.lineOffsetToPosition(fileName, entry.end);
|
||||
const fileName = entry.file;
|
||||
const start = this.lineOffsetToPosition(fileName, entry.start);
|
||||
const end = this.lineOffsetToPosition(fileName, entry.end);
|
||||
return {
|
||||
fileName,
|
||||
textSpan: ts.createTextSpanFromBounds(start, end),
|
||||
isWriteAccess: entry.isWriteAccess,
|
||||
isDefinition: false
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[] {
|
||||
let { line, offset } = this.positionToOneBasedLineOffset(fileName, position);
|
||||
let args: protocol.DocumentHighlightsRequestArgs = { file: fileName, line, offset, filesToSearch };
|
||||
const { line, offset } = this.positionToOneBasedLineOffset(fileName, position);
|
||||
const args: protocol.DocumentHighlightsRequestArgs = { file: fileName, line, offset, filesToSearch };
|
||||
|
||||
let request = this.processRequest<protocol.DocumentHighlightsRequest>(CommandNames.DocumentHighlights, args);
|
||||
let response = this.processResponse<protocol.DocumentHighlightsResponse>(request);
|
||||
const request = this.processRequest<protocol.DocumentHighlightsRequest>(CommandNames.DocumentHighlights, args);
|
||||
const response = this.processResponse<protocol.DocumentHighlightsResponse>(request);
|
||||
|
||||
let self = this;
|
||||
const self = this;
|
||||
return response.body.map(convertToDocumentHighlights);
|
||||
|
||||
function convertToDocumentHighlights(item: ts.server.protocol.DocumentHighlightsItem): ts.DocumentHighlights {
|
||||
let { file, highlightSpans } = item;
|
||||
const { file, highlightSpans } = item;
|
||||
|
||||
return {
|
||||
fileName: file,
|
||||
@@ -546,8 +566,8 @@ namespace ts.server {
|
||||
};
|
||||
|
||||
function convertHighlightSpan(span: ts.server.protocol.HighlightSpan): ts.HighlightSpan {
|
||||
let start = self.lineOffsetToPosition(file, span.start);
|
||||
let end = self.lineOffsetToPosition(file, span.end);
|
||||
const start = self.lineOffsetToPosition(file, span.start);
|
||||
const end = self.lineOffsetToPosition(file, span.end);
|
||||
return {
|
||||
textSpan: ts.createTextSpanFromBounds(start, end),
|
||||
kind: span.kind
|
||||
@@ -561,27 +581,31 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[] {
|
||||
throw new Error("Not Implemented Yet.");
|
||||
throw new Error("Not Implemented Yet.");
|
||||
}
|
||||
|
||||
|
||||
getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion {
|
||||
throw new Error("Not Implemented Yet.");
|
||||
throw new Error("Not Implemented Yet.");
|
||||
}
|
||||
|
||||
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean {
|
||||
throw new Error("Not Implemented Yet.");
|
||||
}
|
||||
|
||||
getBraceMatchingAtPosition(fileName: string, position: number): TextSpan[] {
|
||||
var lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
var args: protocol.FileLocationRequestArgs = {
|
||||
const lineOffset = this.positionToOneBasedLineOffset(fileName, position);
|
||||
const args: protocol.FileLocationRequestArgs = {
|
||||
file: fileName,
|
||||
line: lineOffset.line,
|
||||
offset: lineOffset.offset,
|
||||
};
|
||||
|
||||
var request = this.processRequest<protocol.BraceRequest>(CommandNames.Brace, args);
|
||||
var response = this.processResponse<protocol.BraceResponse>(request);
|
||||
const request = this.processRequest<protocol.BraceRequest>(CommandNames.Brace, args);
|
||||
const response = this.processResponse<protocol.BraceResponse>(request);
|
||||
|
||||
return response.body.map(entry => {
|
||||
var start = this.lineOffsetToPosition(fileName, entry.start);
|
||||
var end = this.lineOffsetToPosition(fileName, entry.end);
|
||||
const start = this.lineOffsetToPosition(fileName, entry.start);
|
||||
const end = this.lineOffsetToPosition(fileName, entry.end);
|
||||
return {
|
||||
start: start,
|
||||
length: end - start,
|
||||
|
||||
+277
-60
@@ -27,13 +27,16 @@ namespace ts.server {
|
||||
});
|
||||
}
|
||||
|
||||
export const maxProgramSizeForNonTsFiles = 20 * 1024 * 1024;
|
||||
|
||||
export class ScriptInfo {
|
||||
svc: ScriptVersionCache;
|
||||
children: ScriptInfo[] = []; // files referenced by this file
|
||||
defaultProject: Project; // project to use by default for file
|
||||
fileWatcher: FileWatcher;
|
||||
formatCodeOptions = ts.clone(CompilerService.defaultFormatCodeOptions);
|
||||
formatCodeOptions = ts.clone(CompilerService.getDefaultFormatCodeOptions(this.host));
|
||||
path: Path;
|
||||
scriptKind: ScriptKind;
|
||||
|
||||
constructor(private host: ServerHost, public fileName: string, public content: string, public isOpen = false) {
|
||||
this.path = toPath(fileName, host.getCurrentDirectory(), createGetCanonicalFileName(host.useCaseSensitiveFileNames));
|
||||
@@ -215,8 +218,16 @@ namespace ts.server {
|
||||
return this.roots.map(root => root.fileName);
|
||||
}
|
||||
|
||||
getScriptKind() {
|
||||
return ScriptKind.Unknown;
|
||||
getScriptKind(fileName: string) {
|
||||
const info = this.getScriptInfo(fileName);
|
||||
if (!info) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!info.scriptKind) {
|
||||
info.scriptKind = getScriptKindFromFileName(fileName);
|
||||
}
|
||||
return info.scriptKind;
|
||||
}
|
||||
|
||||
getScriptVersion(filename: string) {
|
||||
@@ -259,7 +270,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
removeRoot(info: ScriptInfo) {
|
||||
if (!this.filenameToScript.contains(info.path)) {
|
||||
if (this.filenameToScript.contains(info.path)) {
|
||||
this.filenameToScript.remove(info.path);
|
||||
this.roots = copyListRemovingItem(info, this.roots);
|
||||
this.resolvedModuleNames.remove(info.path);
|
||||
@@ -306,6 +317,10 @@ namespace ts.server {
|
||||
return this.host.directoryExists(path);
|
||||
}
|
||||
|
||||
getDirectories(path: string): string[] {
|
||||
return this.host.getDirectories(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param line 1 based index
|
||||
*/
|
||||
@@ -344,18 +359,23 @@ namespace ts.server {
|
||||
* @param line 1-based index
|
||||
* @param offset 1-based index
|
||||
*/
|
||||
positionToLineOffset(filename: string, position: number): ILineInfo {
|
||||
positionToLineOffset(filename: string, position: number, lineIndex?: LineIndex): ILineInfo {
|
||||
lineIndex = lineIndex || this.getLineIndex(filename);
|
||||
const lineOffset = lineIndex.charOffsetToLineNumberAndPos(position);
|
||||
return { line: lineOffset.line, offset: lineOffset.offset + 1 };
|
||||
}
|
||||
|
||||
getLineIndex(filename: string): LineIndex {
|
||||
const path = toPath(filename, this.host.getCurrentDirectory(), this.getCanonicalFileName);
|
||||
const script: ScriptInfo = this.filenameToScript.get(path);
|
||||
const index = script.snap().index;
|
||||
const lineOffset = index.charOffsetToLineNumberAndPos(position);
|
||||
return { line: lineOffset.line, offset: lineOffset.offset + 1 };
|
||||
return script.snap().index;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProjectOptions {
|
||||
// these fields can be present in the project file
|
||||
files?: string[];
|
||||
wildcardDirectories?: ts.Map<ts.WatchDirectoryFlags>;
|
||||
compilerOptions?: ts.CompilerOptions;
|
||||
}
|
||||
|
||||
@@ -364,6 +384,7 @@ namespace ts.server {
|
||||
projectFilename: string;
|
||||
projectFileWatcher: FileWatcher;
|
||||
directoryWatcher: FileWatcher;
|
||||
directoriesWatchedForWildcards: Map<FileWatcher>;
|
||||
// Used to keep track of what directories are watched for this project
|
||||
directoriesWatchedForTsconfig: string[] = [];
|
||||
program: ts.Program;
|
||||
@@ -372,12 +393,29 @@ namespace ts.server {
|
||||
/** Used for configured projects which may have multiple open roots */
|
||||
openRefCount = 0;
|
||||
|
||||
constructor(public projectService: ProjectService, public projectOptions?: ProjectOptions) {
|
||||
constructor(
|
||||
public projectService: ProjectService,
|
||||
public projectOptions?: ProjectOptions,
|
||||
public languageServiceDiabled = false) {
|
||||
if (projectOptions && projectOptions.files) {
|
||||
// If files are listed explicitly, allow all extensions
|
||||
projectOptions.compilerOptions.allowNonTsExtensions = true;
|
||||
}
|
||||
this.compilerService = new CompilerService(this, projectOptions && projectOptions.compilerOptions);
|
||||
if (!languageServiceDiabled) {
|
||||
this.compilerService = new CompilerService(this, projectOptions && projectOptions.compilerOptions);
|
||||
}
|
||||
}
|
||||
|
||||
enableLanguageService() {
|
||||
// if the language service was disabled, we should re-initiate the compiler service
|
||||
if (this.languageServiceDiabled) {
|
||||
this.compilerService = new CompilerService(this, this.projectOptions && this.projectOptions.compilerOptions);
|
||||
}
|
||||
this.languageServiceDiabled = false;
|
||||
}
|
||||
|
||||
disableLanguageService() {
|
||||
this.languageServiceDiabled = true;
|
||||
}
|
||||
|
||||
addOpenRef() {
|
||||
@@ -394,19 +432,45 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
getRootFiles() {
|
||||
if (this.languageServiceDiabled) {
|
||||
// When the languageService was disabled, only return file list if it is a configured project
|
||||
return this.projectOptions ? this.projectOptions.files : undefined;
|
||||
}
|
||||
|
||||
return this.compilerService.host.roots.map(info => info.fileName);
|
||||
}
|
||||
|
||||
getFileNames() {
|
||||
if (this.languageServiceDiabled) {
|
||||
if (!this.projectOptions) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const fileNames: string[] = [];
|
||||
if (this.projectOptions && this.projectOptions.compilerOptions) {
|
||||
fileNames.push(getDefaultLibFilePath(this.projectOptions.compilerOptions));
|
||||
}
|
||||
ts.addRange(fileNames, this.projectOptions.files);
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
const sourceFiles = this.program.getSourceFiles();
|
||||
return sourceFiles.map(sourceFile => sourceFile.fileName);
|
||||
}
|
||||
|
||||
getSourceFile(info: ScriptInfo) {
|
||||
if (this.languageServiceDiabled) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.filenameToSourceFile[info.fileName];
|
||||
}
|
||||
|
||||
getSourceFileFromName(filename: string, requireOpen?: boolean) {
|
||||
if (this.languageServiceDiabled) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const info = this.projectService.getScriptInfo(filename);
|
||||
if (info) {
|
||||
if ((!requireOpen) || info.isOpen) {
|
||||
@@ -416,15 +480,27 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
isRoot(info: ScriptInfo) {
|
||||
if (this.languageServiceDiabled) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.compilerService.host.roots.some(root => root === info);
|
||||
}
|
||||
|
||||
removeReferencedFile(info: ScriptInfo) {
|
||||
if (this.languageServiceDiabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.compilerService.host.removeReferencedFile(info);
|
||||
this.updateGraph();
|
||||
}
|
||||
|
||||
updateFileMap() {
|
||||
if (this.languageServiceDiabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.filenameToSourceFile = {};
|
||||
const sourceFiles = this.program.getSourceFiles();
|
||||
for (let i = 0, len = sourceFiles.length; i < len; i++) {
|
||||
@@ -434,11 +510,19 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
finishGraph() {
|
||||
if (this.languageServiceDiabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateGraph();
|
||||
this.compilerService.languageService.getNavigateToItems(".*");
|
||||
}
|
||||
|
||||
updateGraph() {
|
||||
if (this.languageServiceDiabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.program = this.compilerService.languageService.getProgram();
|
||||
this.updateFileMap();
|
||||
}
|
||||
@@ -449,15 +533,32 @@ namespace ts.server {
|
||||
|
||||
// add a root file to project
|
||||
addRoot(info: ScriptInfo) {
|
||||
if (this.languageServiceDiabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.compilerService.host.addRoot(info);
|
||||
}
|
||||
|
||||
// remove a root file from project
|
||||
removeRoot(info: ScriptInfo) {
|
||||
if (this.languageServiceDiabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.compilerService.host.removeRoot(info);
|
||||
}
|
||||
|
||||
filesToString() {
|
||||
if (this.languageServiceDiabled) {
|
||||
if (this.projectOptions) {
|
||||
let strBuilder = "";
|
||||
ts.forEach(this.projectOptions.files,
|
||||
file => { strBuilder += file + "\n"; });
|
||||
return strBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
let strBuilder = "";
|
||||
ts.forEachValue(this.filenameToSourceFile,
|
||||
sourceFile => { strBuilder += sourceFile.fileName + "\n"; });
|
||||
@@ -468,7 +569,9 @@ namespace ts.server {
|
||||
this.projectOptions = projectOptions;
|
||||
if (projectOptions.compilerOptions) {
|
||||
projectOptions.compilerOptions.allowNonTsExtensions = true;
|
||||
this.compilerService.setCompilerOptions(projectOptions.compilerOptions);
|
||||
if (!this.languageServiceDiabled) {
|
||||
this.compilerService.setCompilerOptions(projectOptions.compilerOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -489,6 +592,14 @@ namespace ts.server {
|
||||
return copiedList;
|
||||
}
|
||||
|
||||
/**
|
||||
* This helper funciton processes a list of projects and return the concatenated, sortd and deduplicated output of processing each project.
|
||||
*/
|
||||
export function combineProjectOutput<T>(projects: Project[], action: (project: Project) => T[], comparer?: (a: T, b: T) => number, areEqual?: (a: T, b: T) => boolean) {
|
||||
const result = projects.reduce<T[]>((previous, current) => concatenate(previous, action(current)), []).sort(comparer);
|
||||
return projects.length > 1 ? deduplicate(result, areEqual) : result;
|
||||
}
|
||||
|
||||
export interface ProjectServiceEventHandler {
|
||||
(eventName: string, project: Project, fileName: string): void;
|
||||
}
|
||||
@@ -516,7 +627,7 @@ namespace ts.server {
|
||||
// number becomes 0 for a watcher, then we should close it.
|
||||
directoryWatchersRefCount: ts.Map<number> = {};
|
||||
hostConfiguration: HostConfiguration;
|
||||
timerForDetectingProjectFileListChanges: Map<NodeJS.Timer> = {};
|
||||
timerForDetectingProjectFileListChanges: Map<any> = {};
|
||||
|
||||
constructor(public host: ServerHost, public psLogger: Logger, public eventHandler?: ProjectServiceEventHandler) {
|
||||
// ts.disableIncrementalParsing = true;
|
||||
@@ -525,7 +636,7 @@ namespace ts.server {
|
||||
|
||||
addDefaultHostConfiguration() {
|
||||
this.hostConfiguration = {
|
||||
formatCodeOptions: ts.clone(CompilerService.defaultFormatCodeOptions),
|
||||
formatCodeOptions: ts.clone(CompilerService.getDefaultFormatCodeOptions(this.host)),
|
||||
hostInfo: "Unknown host"
|
||||
};
|
||||
}
|
||||
@@ -576,9 +687,9 @@ namespace ts.server {
|
||||
|
||||
startTimerForDetectingProjectFileListChanges(project: Project) {
|
||||
if (this.timerForDetectingProjectFileListChanges[project.projectFilename]) {
|
||||
clearTimeout(this.timerForDetectingProjectFileListChanges[project.projectFilename]);
|
||||
this.host.clearTimeout(this.timerForDetectingProjectFileListChanges[project.projectFilename]);
|
||||
}
|
||||
this.timerForDetectingProjectFileListChanges[project.projectFilename] = setTimeout(
|
||||
this.timerForDetectingProjectFileListChanges[project.projectFilename] = this.host.setTimeout(
|
||||
() => this.handleProjectFileListChanges(project),
|
||||
250
|
||||
);
|
||||
@@ -743,6 +854,8 @@ namespace ts.server {
|
||||
if (project.isConfiguredProject()) {
|
||||
project.projectFileWatcher.close();
|
||||
project.directoryWatcher.close();
|
||||
forEachValue(project.directoriesWatchedForWildcards, watcher => { watcher.close(); });
|
||||
delete project.directoriesWatchedForWildcards;
|
||||
this.configuredProjects = copyListRemovingItem(project, this.configuredProjects);
|
||||
}
|
||||
else {
|
||||
@@ -786,6 +899,7 @@ namespace ts.server {
|
||||
else {
|
||||
this.findReferencingProjects(info);
|
||||
if (info.defaultProject) {
|
||||
info.defaultProject.addOpenRef();
|
||||
this.openFilesReferenced.push(info);
|
||||
}
|
||||
else {
|
||||
@@ -902,6 +1016,7 @@ namespace ts.server {
|
||||
configuredProject.updateGraph();
|
||||
if (configuredProject.getSourceFile(info)) {
|
||||
info.defaultProject = configuredProject;
|
||||
referencingProjects.push(configuredProject);
|
||||
}
|
||||
}
|
||||
return referencingProjects;
|
||||
@@ -1013,7 +1128,7 @@ namespace ts.server {
|
||||
* @param filename is absolute pathname
|
||||
* @param fileContent is a known version of the file content that is more up to date than the one on disk
|
||||
*/
|
||||
openFile(fileName: string, openedByClient: boolean, fileContent?: string) {
|
||||
openFile(fileName: string, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind) {
|
||||
fileName = ts.normalizePath(fileName);
|
||||
let info = ts.lookUp(this.filenameToScriptInfo, fileName);
|
||||
if (!info) {
|
||||
@@ -1028,6 +1143,7 @@ namespace ts.server {
|
||||
}
|
||||
if (content !== undefined) {
|
||||
info = new ScriptInfo(this.host, fileName, content, openedByClient);
|
||||
info.scriptKind = scriptKind;
|
||||
info.setFormatOptions(this.getFormatCodeOptions());
|
||||
this.filenameToScriptInfo[fileName] = info;
|
||||
if (!info.isOpen) {
|
||||
@@ -1077,12 +1193,12 @@ namespace ts.server {
|
||||
* @param filename is absolute pathname
|
||||
* @param fileContent is a known version of the file content that is more up to date than the one on disk
|
||||
*/
|
||||
openClientFile(fileName: string, fileContent?: string) {
|
||||
this.openOrUpdateConfiguredProjectForFile(fileName);
|
||||
const info = this.openFile(fileName, /*openedByClient*/ true, fileContent);
|
||||
openClientFile(fileName: string, fileContent?: string, scriptKind?: ScriptKind): { configFileName?: string, configFileErrors?: Diagnostic[] } {
|
||||
const { configFileName, configFileErrors } = this.openOrUpdateConfiguredProjectForFile(fileName);
|
||||
const info = this.openFile(fileName, /*openedByClient*/ true, fileContent, scriptKind);
|
||||
this.addOpenFile(info);
|
||||
this.printProjects();
|
||||
return info;
|
||||
return { configFileName, configFileErrors };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1090,7 +1206,7 @@ namespace ts.server {
|
||||
* we first detect if there is already a configured project created for it: if so, we re-read
|
||||
* the tsconfig file content and update the project; otherwise we create a new one.
|
||||
*/
|
||||
openOrUpdateConfiguredProjectForFile(fileName: string) {
|
||||
openOrUpdateConfiguredProjectForFile(fileName: string): { configFileName?: string, configFileErrors?: Diagnostic[] } {
|
||||
const searchPath = ts.normalizePath(getDirectoryPath(fileName));
|
||||
this.log("Search path: " + searchPath, "Info");
|
||||
const configFileName = this.findConfigFile(searchPath);
|
||||
@@ -1100,11 +1216,16 @@ namespace ts.server {
|
||||
if (!project) {
|
||||
const configResult = this.openConfigFile(configFileName, fileName);
|
||||
if (!configResult.success) {
|
||||
this.log("Error opening config file " + configFileName + " " + configResult.errorMsg);
|
||||
return { configFileName, configFileErrors: configResult.errors };
|
||||
}
|
||||
else {
|
||||
// even if opening config file was successful, it could still
|
||||
// contain errors that were tolerated.
|
||||
this.log("Opened configuration file " + configFileName, "Info");
|
||||
this.configuredProjects.push(configResult.project);
|
||||
if (configResult.errors && configResult.errors.length > 0) {
|
||||
return { configFileName, configFileErrors: configResult.errors };
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1114,6 +1235,7 @@ namespace ts.server {
|
||||
else {
|
||||
this.log("No config files found.");
|
||||
}
|
||||
return configFileName ? { configFileName } : {};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1203,77 +1325,164 @@ namespace ts.server {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
configFileToProjectOptions(configFilename: string): { succeeded: boolean, projectOptions?: ProjectOptions, error?: ProjectOpenResult } {
|
||||
configFileToProjectOptions(configFilename: string): { succeeded: boolean, projectOptions?: ProjectOptions, errors?: Diagnostic[] } {
|
||||
configFilename = ts.normalizePath(configFilename);
|
||||
// file references will be relative to dirPath (or absolute)
|
||||
const dirPath = ts.getDirectoryPath(configFilename);
|
||||
const contents = this.host.readFile(configFilename);
|
||||
const rawConfig: { config?: ProjectOptions; error?: Diagnostic; } = ts.parseConfigFileTextToJson(configFilename, contents);
|
||||
if (rawConfig.error) {
|
||||
return { succeeded: false, error: rawConfig.error };
|
||||
return { succeeded: false, errors: [rawConfig.error] };
|
||||
}
|
||||
else {
|
||||
const parsedCommandLine = ts.parseJsonConfigFileContent(rawConfig.config, this.host, dirPath, /*existingOptions*/ {}, configFilename);
|
||||
Debug.assert(!!parsedCommandLine.fileNames);
|
||||
|
||||
if (parsedCommandLine.errors && (parsedCommandLine.errors.length > 0)) {
|
||||
return { succeeded: false, error: { errorMsg: "tsconfig option errors" } };
|
||||
return { succeeded: false, errors: parsedCommandLine.errors };
|
||||
}
|
||||
else if (parsedCommandLine.fileNames.length === 0) {
|
||||
return { succeeded: false, error: { errorMsg: "no files found" } };
|
||||
const error = createCompilerDiagnostic(Diagnostics.The_config_file_0_found_doesn_t_contain_any_source_files, configFilename);
|
||||
return { succeeded: false, errors: [error] };
|
||||
}
|
||||
else {
|
||||
const projectOptions: ProjectOptions = {
|
||||
files: parsedCommandLine.fileNames,
|
||||
compilerOptions: parsedCommandLine.options
|
||||
wildcardDirectories: parsedCommandLine.wildcardDirectories,
|
||||
compilerOptions: parsedCommandLine.options,
|
||||
};
|
||||
return { succeeded: true, projectOptions };
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
openConfigFile(configFilename: string, clientFileName?: string): ProjectOpenResult {
|
||||
const { succeeded, projectOptions, error } = this.configFileToProjectOptions(configFilename);
|
||||
private exceedTotalNonTsFileSizeLimit(fileNames: string[]) {
|
||||
let totalNonTsFileSize = 0;
|
||||
if (!this.host.getFileSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const fileName of fileNames) {
|
||||
if (hasTypeScriptFileExtension(fileName)) {
|
||||
continue;
|
||||
}
|
||||
totalNonTsFileSize += this.host.getFileSize(fileName);
|
||||
if (totalNonTsFileSize > maxProgramSizeForNonTsFiles) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
openConfigFile(configFilename: string, clientFileName?: string): { success: boolean, project?: Project, errors?: Diagnostic[] } {
|
||||
const { succeeded, projectOptions, errors } = this.configFileToProjectOptions(configFilename);
|
||||
if (!succeeded) {
|
||||
return error;
|
||||
return { success: false, errors };
|
||||
}
|
||||
else {
|
||||
if (!projectOptions.compilerOptions.disableSizeLimit && projectOptions.compilerOptions.allowJs) {
|
||||
if (this.exceedTotalNonTsFileSizeLimit(projectOptions.files)) {
|
||||
const project = this.createProject(configFilename, projectOptions, /*languageServiceDisabled*/ true);
|
||||
|
||||
// for configured projects with languageService disabled, we only watch its config file,
|
||||
// do not care about the directory changes in the folder.
|
||||
project.projectFileWatcher = this.host.watchFile(
|
||||
toPath(configFilename, configFilename, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)),
|
||||
_ => this.watchedProjectConfigFileChanged(project));
|
||||
return { success: true, project };
|
||||
}
|
||||
}
|
||||
|
||||
const project = this.createProject(configFilename, projectOptions);
|
||||
let errors: Diagnostic[];
|
||||
for (const rootFilename of projectOptions.files) {
|
||||
if (this.host.fileExists(rootFilename)) {
|
||||
const info = this.openFile(rootFilename, /*openedByClient*/ clientFileName == rootFilename);
|
||||
project.addRoot(info);
|
||||
}
|
||||
else {
|
||||
return { errorMsg: "specified file " + rootFilename + " not found" };
|
||||
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.File_0_not_found, rootFilename));
|
||||
}
|
||||
}
|
||||
project.finishGraph();
|
||||
project.projectFileWatcher = this.host.watchFile(configFilename, _ => this.watchedProjectConfigFileChanged(project));
|
||||
this.log("Add recursive watcher for: " + ts.getDirectoryPath(configFilename));
|
||||
|
||||
const configDirectoryPath = ts.getDirectoryPath(configFilename);
|
||||
|
||||
this.log("Add recursive watcher for: " + configDirectoryPath);
|
||||
project.directoryWatcher = this.host.watchDirectory(
|
||||
ts.getDirectoryPath(configFilename),
|
||||
configDirectoryPath,
|
||||
path => this.directoryWatchedForSourceFilesChanged(project, path),
|
||||
/*recursive*/ true
|
||||
);
|
||||
return { success: true, project: project };
|
||||
|
||||
project.directoriesWatchedForWildcards = reduceProperties(projectOptions.wildcardDirectories, (watchers, flag, directory) => {
|
||||
if (comparePaths(configDirectoryPath, directory, ".", !this.host.useCaseSensitiveFileNames) !== Comparison.EqualTo) {
|
||||
const recursive = (flag & WatchDirectoryFlags.Recursive) !== 0;
|
||||
this.log(`Add ${ recursive ? "recursive " : ""}watcher for: ${directory}`);
|
||||
watchers[directory] = this.host.watchDirectory(
|
||||
directory,
|
||||
path => this.directoryWatchedForSourceFilesChanged(project, path),
|
||||
recursive
|
||||
);
|
||||
}
|
||||
|
||||
return watchers;
|
||||
}, <Map<FileWatcher>>{});
|
||||
|
||||
return { success: true, project: project, errors };
|
||||
}
|
||||
}
|
||||
|
||||
updateConfiguredProject(project: Project) {
|
||||
updateConfiguredProject(project: Project): Diagnostic[] {
|
||||
if (!this.host.fileExists(project.projectFilename)) {
|
||||
this.log("Config file deleted");
|
||||
this.removeProject(project);
|
||||
}
|
||||
else {
|
||||
const { succeeded, projectOptions, error } = this.configFileToProjectOptions(project.projectFilename);
|
||||
const { succeeded, projectOptions, errors } = this.configFileToProjectOptions(project.projectFilename);
|
||||
if (!succeeded) {
|
||||
return error;
|
||||
return errors;
|
||||
}
|
||||
else {
|
||||
const oldFileNames = project.compilerService.host.roots.map(info => info.fileName);
|
||||
const newFileNames = projectOptions.files;
|
||||
if (projectOptions.compilerOptions && !projectOptions.compilerOptions.disableSizeLimit && this.exceedTotalNonTsFileSizeLimit(projectOptions.files)) {
|
||||
project.setProjectOptions(projectOptions);
|
||||
if (project.languageServiceDiabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
project.disableLanguageService();
|
||||
if (project.directoryWatcher) {
|
||||
project.directoryWatcher.close();
|
||||
project.directoryWatcher = undefined;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (project.languageServiceDiabled) {
|
||||
project.setProjectOptions(projectOptions);
|
||||
project.enableLanguageService();
|
||||
project.directoryWatcher = this.host.watchDirectory(
|
||||
ts.getDirectoryPath(project.projectFilename),
|
||||
path => this.directoryWatchedForSourceFilesChanged(project, path),
|
||||
/*recursive*/ true
|
||||
);
|
||||
|
||||
for (const rootFilename of projectOptions.files) {
|
||||
if (this.host.fileExists(rootFilename)) {
|
||||
const info = this.openFile(rootFilename, /*openedByClient*/ false);
|
||||
project.addRoot(info);
|
||||
}
|
||||
}
|
||||
project.finishGraph();
|
||||
return;
|
||||
}
|
||||
|
||||
// if the project is too large, the root files might not have been all loaded if the total
|
||||
// program size reached the upper limit. In that case project.projectOptions.files should
|
||||
// be more precise. However this would only happen for configured project.
|
||||
const oldFileNames = project.projectOptions ? project.projectOptions.files : project.compilerService.host.roots.map(info => info.fileName);
|
||||
const newFileNames = ts.filter(projectOptions.files, f => this.host.fileExists(f));
|
||||
const fileNamesToRemove = oldFileNames.filter(f => newFileNames.indexOf(f) < 0);
|
||||
const fileNamesToAdd = newFileNames.filter(f => oldFileNames.indexOf(f) < 0);
|
||||
|
||||
@@ -1315,8 +1524,8 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
createProject(projectFilename: string, projectOptions?: ProjectOptions) {
|
||||
const project = new Project(this, projectOptions);
|
||||
createProject(projectFilename: string, projectOptions?: ProjectOptions, languageServiceDisabled?: boolean) {
|
||||
const project = new Project(this, projectOptions, languageServiceDisabled);
|
||||
project.projectFilename = projectFilename;
|
||||
return project;
|
||||
}
|
||||
@@ -1355,23 +1564,26 @@ namespace ts.server {
|
||||
return ts.isExternalModule(sourceFile);
|
||||
}
|
||||
|
||||
static defaultFormatCodeOptions: ts.FormatCodeOptions = {
|
||||
IndentSize: 4,
|
||||
TabSize: 4,
|
||||
NewLineCharacter: ts.sys ? ts.sys.newLine : "\n",
|
||||
ConvertTabsToSpaces: true,
|
||||
IndentStyle: ts.IndentStyle.Smart,
|
||||
InsertSpaceAfterCommaDelimiter: true,
|
||||
InsertSpaceAfterSemicolonInForStatements: true,
|
||||
InsertSpaceBeforeAndAfterBinaryOperators: true,
|
||||
InsertSpaceAfterKeywordsInControlFlowStatements: true,
|
||||
InsertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
PlaceOpenBraceOnNewLineForFunctions: false,
|
||||
PlaceOpenBraceOnNewLineForControlBlocks: false,
|
||||
};
|
||||
static getDefaultFormatCodeOptions(host: ServerHost): ts.FormatCodeOptions {
|
||||
return ts.clone({
|
||||
BaseIndentSize: 0,
|
||||
IndentSize: 4,
|
||||
TabSize: 4,
|
||||
NewLineCharacter: host.newLine || "\n",
|
||||
ConvertTabsToSpaces: true,
|
||||
IndentStyle: ts.IndentStyle.Smart,
|
||||
InsertSpaceAfterCommaDelimiter: true,
|
||||
InsertSpaceAfterSemicolonInForStatements: true,
|
||||
InsertSpaceBeforeAndAfterBinaryOperators: true,
|
||||
InsertSpaceAfterKeywordsInControlFlowStatements: true,
|
||||
InsertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
PlaceOpenBraceOnNewLineForFunctions: false,
|
||||
PlaceOpenBraceOnNewLineForControlBlocks: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface LineCollection {
|
||||
@@ -1666,7 +1878,12 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
reloadFromFile(filename: string, cb?: () => any) {
|
||||
const content = this.host.readFile(filename);
|
||||
let content = this.host.readFile(filename);
|
||||
// If the file doesn't exist or cannot be read, we should
|
||||
// wipe out its cached content on the server to avoid side effects.
|
||||
if (!content) {
|
||||
content = "";
|
||||
}
|
||||
this.reload(content);
|
||||
if (cb)
|
||||
cb();
|
||||
|
||||
Vendored
+132
-59
@@ -1,54 +1,54 @@
|
||||
/**
|
||||
* Declaration module describing the TypeScript Server protocol
|
||||
/**
|
||||
* Declaration module describing the TypeScript Server protocol
|
||||
*/
|
||||
declare namespace ts.server.protocol {
|
||||
/**
|
||||
* A TypeScript Server message
|
||||
/**
|
||||
* A TypeScript Server message
|
||||
*/
|
||||
export interface Message {
|
||||
/**
|
||||
* Sequence number of the message
|
||||
/**
|
||||
* Sequence number of the message
|
||||
*/
|
||||
seq: number;
|
||||
|
||||
/**
|
||||
* One of "request", "response", or "event"
|
||||
* One of "request", "response", or "event"
|
||||
*/
|
||||
type: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Client-initiated request message
|
||||
/**
|
||||
* Client-initiated request message
|
||||
*/
|
||||
export interface Request extends Message {
|
||||
/**
|
||||
* The command to execute
|
||||
* The command to execute
|
||||
*/
|
||||
command: string;
|
||||
|
||||
/**
|
||||
* Object containing arguments for the command
|
||||
/**
|
||||
* Object containing arguments for the command
|
||||
*/
|
||||
arguments?: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request to reload the project structure for all the opened files
|
||||
* Request to reload the project structure for all the opened files
|
||||
*/
|
||||
export interface ReloadProjectsRequest extends Message {
|
||||
}
|
||||
|
||||
/**
|
||||
* Server-initiated event message
|
||||
/**
|
||||
* Server-initiated event message
|
||||
*/
|
||||
export interface Event extends Message {
|
||||
/**
|
||||
* Name of event
|
||||
/**
|
||||
* Name of event
|
||||
*/
|
||||
event: string;
|
||||
|
||||
/**
|
||||
* Event-specific information
|
||||
/**
|
||||
* Event-specific information
|
||||
*/
|
||||
body?: any;
|
||||
}
|
||||
@@ -62,18 +62,18 @@ declare namespace ts.server.protocol {
|
||||
*/
|
||||
request_seq: number;
|
||||
|
||||
/**
|
||||
* Outcome of the request.
|
||||
/**
|
||||
* Outcome of the request.
|
||||
*/
|
||||
success: boolean;
|
||||
|
||||
/**
|
||||
/**
|
||||
* The command requested.
|
||||
*/
|
||||
command: string;
|
||||
|
||||
/**
|
||||
* Contains error message if success === false.
|
||||
/**
|
||||
* Contains error message if success === false.
|
||||
*/
|
||||
message?: string;
|
||||
|
||||
@@ -83,7 +83,7 @@ declare namespace ts.server.protocol {
|
||||
body?: any;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Arguments for FileRequest messages.
|
||||
*/
|
||||
export interface FileRequestArgs {
|
||||
@@ -93,7 +93,7 @@ declare namespace ts.server.protocol {
|
||||
file: string;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Arguments for ProjectInfoRequest request.
|
||||
*/
|
||||
export interface ProjectInfoRequestArgs extends FileRequestArgs {
|
||||
@@ -110,7 +110,7 @@ declare namespace ts.server.protocol {
|
||||
arguments: ProjectInfoRequestArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Response message body for "projectInfo" request
|
||||
*/
|
||||
export interface ProjectInfo {
|
||||
@@ -123,9 +123,13 @@ declare namespace ts.server.protocol {
|
||||
* The list of normalized file name in the project, including 'lib.d.ts'
|
||||
*/
|
||||
fileNames?: string[];
|
||||
/**
|
||||
* Indicates if the project has a active language service instance
|
||||
*/
|
||||
languageServiceDisabled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Response message for "projectInfo" request
|
||||
*/
|
||||
export interface ProjectInfoResponse extends Response {
|
||||
@@ -144,12 +148,12 @@ declare namespace ts.server.protocol {
|
||||
* (file, line, character offset), where line and character offset are 1-based.
|
||||
*/
|
||||
export interface FileLocationRequestArgs extends FileRequestArgs {
|
||||
/**
|
||||
/**
|
||||
* The line number for the request (1-based).
|
||||
*/
|
||||
line: number;
|
||||
|
||||
/**
|
||||
/**
|
||||
* The character offset (on the line) for the request (1-based).
|
||||
*/
|
||||
offset: number;
|
||||
@@ -216,7 +220,7 @@ declare namespace ts.server.protocol {
|
||||
* Object found in response messages defining a span of text in a specific source file.
|
||||
*/
|
||||
export interface FileSpan extends TextSpan {
|
||||
/**
|
||||
/**
|
||||
* File containing text span.
|
||||
*/
|
||||
file: string;
|
||||
@@ -300,14 +304,19 @@ declare namespace ts.server.protocol {
|
||||
*/
|
||||
lineText: string;
|
||||
|
||||
/**
|
||||
/**
|
||||
* True if reference is a write location, false otherwise.
|
||||
*/
|
||||
isWriteAccess: boolean;
|
||||
|
||||
/**
|
||||
* True if reference is a definition, false otherwise.
|
||||
*/
|
||||
isDefinition: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* The body of a "references" response message.
|
||||
* The body of a "references" response message.
|
||||
*/
|
||||
export interface ReferencesResponseBody {
|
||||
/**
|
||||
@@ -325,7 +334,7 @@ declare namespace ts.server.protocol {
|
||||
*/
|
||||
symbolStartOffset: number;
|
||||
|
||||
/**
|
||||
/**
|
||||
* The full display name of the symbol.
|
||||
*/
|
||||
symbolDisplayString: string;
|
||||
@@ -355,7 +364,7 @@ declare namespace ts.server.protocol {
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about the item to be renamed.
|
||||
* Information about the item to be renamed.
|
||||
*/
|
||||
export interface RenameInfo {
|
||||
/**
|
||||
@@ -373,7 +382,7 @@ declare namespace ts.server.protocol {
|
||||
*/
|
||||
displayName: string;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Full display name of item to be renamed.
|
||||
*/
|
||||
fullDisplayName: string;
|
||||
@@ -383,7 +392,7 @@ declare namespace ts.server.protocol {
|
||||
*/
|
||||
kind: string;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Optional modifiers for the kind (such as 'public').
|
||||
*/
|
||||
kindModifiers: string;
|
||||
@@ -429,6 +438,9 @@ declare namespace ts.server.protocol {
|
||||
/** Number of spaces to indent during formatting. Default value is 4. */
|
||||
indentSize?: number;
|
||||
|
||||
/** Number of additional spaces to indent during formatting to preserve base indentation (ex. script block indentation). Default value is 0. */
|
||||
baseIndentSize?: number;
|
||||
|
||||
/** The new line character to be used. Default value is the OS line delimiter. */
|
||||
newLineCharacter?: string;
|
||||
|
||||
@@ -469,7 +481,7 @@ declare namespace ts.server.protocol {
|
||||
placeOpenBraceOnNewLineForControlBlocks?: boolean;
|
||||
|
||||
/** Index operator */
|
||||
[key: string]: string | number | boolean;
|
||||
[key: string]: string | number | boolean | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -477,7 +489,7 @@ declare namespace ts.server.protocol {
|
||||
*/
|
||||
export interface ConfigureRequestArguments {
|
||||
|
||||
/**
|
||||
/**
|
||||
* Information about the host, for example 'Emacs 24.4' or
|
||||
* 'Sublime Text version 3075'
|
||||
*/
|
||||
@@ -495,7 +507,7 @@ declare namespace ts.server.protocol {
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure request; value of command field is "configure". Specifies
|
||||
* Configure request; value of command field is "configure". Specifies
|
||||
* host information, such as host type, tab size, and indent size.
|
||||
*/
|
||||
export interface ConfigureRequest extends Request {
|
||||
@@ -514,10 +526,15 @@ declare namespace ts.server.protocol {
|
||||
*/
|
||||
export interface OpenRequestArgs extends FileRequestArgs {
|
||||
/**
|
||||
* Used when a version of the file content is known to be more up to date than the one on disk.
|
||||
* Then the known content will be used upon opening instead of the disk copy
|
||||
* Used when a version of the file content is known to be more up to date than the one on disk.
|
||||
* Then the known content will be used upon opening instead of the disk copy
|
||||
*/
|
||||
fileContent?: string;
|
||||
/**
|
||||
* Used to specify the script kind of the file explicitly. It could be one of the following:
|
||||
* "TS", "JS", "TSX", "JSX"
|
||||
*/
|
||||
scriptKindName?: "TS" | "JS" | "TSX" | "JSX";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -751,7 +768,7 @@ declare namespace ts.server.protocol {
|
||||
* Optional modifiers for the kind (such as 'public').
|
||||
*/
|
||||
kindModifiers: string;
|
||||
/**
|
||||
/**
|
||||
* A string that is used for comparing completion items so that they can be ordered. This
|
||||
* is often the same as the name but may be different in certain circumstances.
|
||||
*/
|
||||
@@ -794,7 +811,7 @@ declare namespace ts.server.protocol {
|
||||
}
|
||||
|
||||
/**
|
||||
* Signature help information for a single parameter
|
||||
* Signature help information for a single parameter
|
||||
*/
|
||||
export interface SignatureHelpParameter {
|
||||
|
||||
@@ -814,18 +831,18 @@ declare namespace ts.server.protocol {
|
||||
displayParts: SymbolDisplayPart[];
|
||||
|
||||
/**
|
||||
* Whether the parameter is optional or not.
|
||||
* Whether the parameter is optional or not.
|
||||
*/
|
||||
isOptional: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a single signature to show in signature help.
|
||||
* Represents a single signature to show in signature help.
|
||||
*/
|
||||
export interface SignatureHelpItem {
|
||||
|
||||
/**
|
||||
* Whether the signature accepts a variable number of arguments.
|
||||
* Whether the signature accepts a variable number of arguments.
|
||||
*/
|
||||
isVariadic: boolean;
|
||||
|
||||
@@ -845,7 +862,7 @@ declare namespace ts.server.protocol {
|
||||
separatorDisplayParts: SymbolDisplayPart[];
|
||||
|
||||
/**
|
||||
* The signature helps items for the parameters.
|
||||
* The signature helps items for the parameters.
|
||||
*/
|
||||
parameters: SignatureHelpParameter[];
|
||||
|
||||
@@ -861,17 +878,17 @@ declare namespace ts.server.protocol {
|
||||
export interface SignatureHelpItems {
|
||||
|
||||
/**
|
||||
* The signature help items.
|
||||
* The signature help items.
|
||||
*/
|
||||
items: SignatureHelpItem[];
|
||||
|
||||
/**
|
||||
* The span for which signature help should appear on a signature
|
||||
* The span for which signature help should appear on a signature
|
||||
*/
|
||||
applicableSpan: TextSpan;
|
||||
|
||||
/**
|
||||
* The item selected in the set of available help items.
|
||||
* The item selected in the set of available help items.
|
||||
*/
|
||||
selectedItemIndex: number;
|
||||
|
||||
@@ -890,12 +907,11 @@ declare namespace ts.server.protocol {
|
||||
* Arguments of a signature help request.
|
||||
*/
|
||||
export interface SignatureHelpRequestArgs extends FileLocationRequestArgs {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Signature help request; value of command field is "signatureHelp".
|
||||
* Given a file location (file, line, col), return the signature
|
||||
* Given a file location (file, line, col), return the signature
|
||||
* help.
|
||||
*/
|
||||
export interface SignatureHelpRequest extends FileLocationRequest {
|
||||
@@ -909,6 +925,32 @@ declare namespace ts.server.protocol {
|
||||
body?: SignatureHelpItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronous request for semantic diagnostics of one file.
|
||||
*/
|
||||
export interface SemanticDiagnosticsSyncRequest extends FileRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Response object for synchronous sematic diagnostics request.
|
||||
*/
|
||||
export interface SemanticDiagnosticsSyncResponse extends Response {
|
||||
body?: Diagnostic[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronous request for syntactic diagnostics of one file.
|
||||
*/
|
||||
export interface SyntacticDiagnosticsSyncRequest extends FileRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Response object for synchronous syntactic diagnostics request.
|
||||
*/
|
||||
export interface SyntacticDiagnosticsSyncResponse extends Response {
|
||||
body?: Diagnostic[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Arguments for GeterrForProject request.
|
||||
*/
|
||||
@@ -926,8 +968,8 @@ declare namespace ts.server.protocol {
|
||||
}
|
||||
|
||||
/**
|
||||
* GeterrForProjectRequest request; value of command field is
|
||||
* "geterrForProject". It works similarly with 'Geterr', only
|
||||
* GeterrForProjectRequest request; value of command field is
|
||||
* "geterrForProject". It works similarly with 'Geterr', only
|
||||
* it request for every file in this project.
|
||||
*/
|
||||
export interface GeterrForProjectRequest extends Request {
|
||||
@@ -997,7 +1039,7 @@ declare namespace ts.server.protocol {
|
||||
diagnostics: Diagnostic[];
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Event message for "syntaxDiag" and "semanticDiag" event types.
|
||||
* These events provide syntactic and semantic errors for a file.
|
||||
*/
|
||||
@@ -1005,6 +1047,32 @@ declare namespace ts.server.protocol {
|
||||
body?: DiagnosticEventBody;
|
||||
}
|
||||
|
||||
export interface ConfigFileDiagnosticEventBody {
|
||||
/**
|
||||
* The file which trigged the searching and error-checking of the config file
|
||||
*/
|
||||
triggerFile: string;
|
||||
|
||||
/**
|
||||
* The name of the found config file.
|
||||
*/
|
||||
configFile: string;
|
||||
|
||||
/**
|
||||
* An arry of diagnostic information items for the found config file.
|
||||
*/
|
||||
diagnostics: Diagnostic[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Event message for "configFileDiag" event type.
|
||||
* This event provides errors for a found config file.
|
||||
*/
|
||||
export interface ConfigFileDiagnosticEvent extends Event {
|
||||
body?: ConfigFileDiagnosticEventBody;
|
||||
event: "configFileDiag";
|
||||
}
|
||||
|
||||
/**
|
||||
* Arguments for reload request.
|
||||
*/
|
||||
@@ -1033,7 +1101,7 @@ declare namespace ts.server.protocol {
|
||||
export interface ReloadResponse extends Response {
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Arguments for saveto request.
|
||||
*/
|
||||
export interface SavetoRequestArgs extends FileRequestArgs {
|
||||
@@ -1109,7 +1177,7 @@ declare namespace ts.server.protocol {
|
||||
*/
|
||||
kindModifiers?: string;
|
||||
|
||||
/**
|
||||
/**
|
||||
* The file in which the symbol is found.
|
||||
*/
|
||||
file: string;
|
||||
@@ -1156,7 +1224,7 @@ declare namespace ts.server.protocol {
|
||||
|
||||
/**
|
||||
* Change request message; value of command field is "change".
|
||||
* Update the server's view of the file named by argument 'file'.
|
||||
* Update the server's view of the file named by argument 'file'.
|
||||
* Server does not currently send a response to a change request.
|
||||
*/
|
||||
export interface ChangeRequest extends FileLocationRequest {
|
||||
@@ -1211,6 +1279,11 @@ declare namespace ts.server.protocol {
|
||||
* Optional children.
|
||||
*/
|
||||
childItems?: NavigationBarItem[];
|
||||
|
||||
/**
|
||||
* Number of levels deep this item should appear.
|
||||
*/
|
||||
indent: number;
|
||||
}
|
||||
|
||||
export interface NavBarResponse extends Response {
|
||||
|
||||
+107
-4
@@ -1,7 +1,7 @@
|
||||
/// <reference path="node.d.ts" />
|
||||
/// <reference path="session.ts" />
|
||||
// used in fs.writeSync
|
||||
/* tslint:disable:no-null */
|
||||
/* tslint:disable:no-null-keyword */
|
||||
|
||||
namespace ts.server {
|
||||
const readline: NodeJS.ReadLine = require("readline");
|
||||
@@ -153,6 +153,98 @@ namespace ts.server {
|
||||
// This places log file in the directory containing editorServices.js
|
||||
// TODO: check that this location is writable
|
||||
|
||||
// average async stat takes about 30 microseconds
|
||||
// set chunk size to do 30 files in < 1 millisecond
|
||||
function createPollingWatchedFileSet(interval = 2500, chunkSize = 30) {
|
||||
let watchedFiles: WatchedFile[] = [];
|
||||
let nextFileToCheck = 0;
|
||||
let watchTimer: any;
|
||||
|
||||
function getModifiedTime(fileName: string): Date {
|
||||
return fs.statSync(fileName).mtime;
|
||||
}
|
||||
|
||||
function poll(checkedIndex: number) {
|
||||
const watchedFile = watchedFiles[checkedIndex];
|
||||
if (!watchedFile) {
|
||||
return;
|
||||
}
|
||||
|
||||
fs.stat(watchedFile.fileName, (err: any, stats: any) => {
|
||||
if (err) {
|
||||
watchedFile.callback(watchedFile.fileName);
|
||||
}
|
||||
else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) {
|
||||
watchedFile.mtime = getModifiedTime(watchedFile.fileName);
|
||||
watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// this implementation uses polling and
|
||||
// stat due to inconsistencies of fs.watch
|
||||
// and efficiency of stat on modern filesystems
|
||||
function startWatchTimer() {
|
||||
watchTimer = setInterval(() => {
|
||||
let count = 0;
|
||||
let nextToCheck = nextFileToCheck;
|
||||
let firstCheck = -1;
|
||||
while ((count < chunkSize) && (nextToCheck !== firstCheck)) {
|
||||
poll(nextToCheck);
|
||||
if (firstCheck < 0) {
|
||||
firstCheck = nextToCheck;
|
||||
}
|
||||
nextToCheck++;
|
||||
if (nextToCheck === watchedFiles.length) {
|
||||
nextToCheck = 0;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
nextFileToCheck = nextToCheck;
|
||||
}, interval);
|
||||
}
|
||||
|
||||
function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile {
|
||||
const file: WatchedFile = {
|
||||
fileName,
|
||||
callback,
|
||||
mtime: getModifiedTime(fileName)
|
||||
};
|
||||
|
||||
watchedFiles.push(file);
|
||||
if (watchedFiles.length === 1) {
|
||||
startWatchTimer();
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
function removeFile(file: WatchedFile) {
|
||||
watchedFiles = copyListRemovingItem(file, watchedFiles);
|
||||
}
|
||||
|
||||
return {
|
||||
getModifiedTime: getModifiedTime,
|
||||
poll: poll,
|
||||
startWatchTimer: startWatchTimer,
|
||||
addFile: addFile,
|
||||
removeFile: removeFile
|
||||
};
|
||||
}
|
||||
|
||||
// REVIEW: for now this implementation uses polling.
|
||||
// The advantage of polling is that it works reliably
|
||||
// on all os and with network mounted files.
|
||||
// For 90 referenced files, the average time to detect
|
||||
// changes is 2*msInterval (by default 5 seconds).
|
||||
// The overhead of this is .04 percent (1/2500) with
|
||||
// average pause of < 1 millisecond (and max
|
||||
// pause less than 1.5 milliseconds); question is
|
||||
// do we anticipate reference sets in the 100s and
|
||||
// do we care about waiting 10-20 seconds to detect
|
||||
// changes for large reference sets? If so, do we want
|
||||
// to increase the chunk size or decrease the interval
|
||||
// time dynamically to match the large reference set?
|
||||
const pollingWatchedFileSet = createPollingWatchedFileSet();
|
||||
const logger = createLoggerFromEnv();
|
||||
|
||||
const pending: string[] = [];
|
||||
@@ -174,10 +266,21 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
// Override sys.write because fs.writeSync is not reliable on Node 4
|
||||
ts.sys.write = (s: string) => writeMessage(s);
|
||||
const sys = <ServerHost>ts.sys;
|
||||
|
||||
const ioSession = new IOSession(ts.sys, logger);
|
||||
// Override sys.write because fs.writeSync is not reliable on Node 4
|
||||
sys.write = (s: string) => writeMessage(s);
|
||||
sys.watchFile = (fileName, callback) => {
|
||||
const watchedFile = pollingWatchedFileSet.addFile(fileName, callback);
|
||||
return {
|
||||
close: () => pollingWatchedFileSet.removeFile(watchedFile)
|
||||
};
|
||||
};
|
||||
|
||||
sys.setTimeout = setTimeout;
|
||||
sys.clearTimeout = clearTimeout;
|
||||
|
||||
const ioSession = new IOSession(sys, logger);
|
||||
process.on("uncaughtException", function(err: Error) {
|
||||
ioSession.logError(err, "unknown");
|
||||
});
|
||||
|
||||
+299
-155
@@ -68,7 +68,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
function formatDiag(fileName: string, project: Project, diag: ts.Diagnostic) {
|
||||
function formatDiag(fileName: string, project: Project, diag: ts.Diagnostic): protocol.Diagnostic {
|
||||
return {
|
||||
start: project.compilerService.host.positionToLineOffset(fileName, diag.start),
|
||||
end: project.compilerService.host.positionToLineOffset(fileName, diag.start + diag.length),
|
||||
@@ -76,6 +76,14 @@ namespace ts.server {
|
||||
};
|
||||
}
|
||||
|
||||
function formatConfigFileDiag(diag: ts.Diagnostic): protocol.Diagnostic {
|
||||
return {
|
||||
start: undefined,
|
||||
end: undefined,
|
||||
text: ts.flattenDiagnosticMessageText(diag.messageText, "\n")
|
||||
};
|
||||
}
|
||||
|
||||
export interface PendingErrorCheck {
|
||||
fileName: string;
|
||||
project: Project;
|
||||
@@ -103,6 +111,8 @@ namespace ts.server {
|
||||
export const Formatonkey = "formatonkey";
|
||||
export const Geterr = "geterr";
|
||||
export const GeterrForProject = "geterrForProject";
|
||||
export const SemanticDiagnosticsSync = "semanticDiagnosticsSync";
|
||||
export const SyntacticDiagnosticsSync = "syntacticDiagnosticsSync";
|
||||
export const NavBar = "navbar";
|
||||
export const Navto = "navto";
|
||||
export const Occurrences = "occurrences";
|
||||
@@ -122,9 +132,12 @@ namespace ts.server {
|
||||
|
||||
namespace Errors {
|
||||
export const NoProject = new Error("No Project.");
|
||||
export const ProjectLanguageServiceDisabled = new Error("The project's language service is disabled.");
|
||||
}
|
||||
|
||||
export interface ServerHost extends ts.System {
|
||||
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
clearTimeout(timeoutId: any): void;
|
||||
}
|
||||
|
||||
export class Session {
|
||||
@@ -141,8 +154,8 @@ namespace ts.server {
|
||||
) {
|
||||
this.projectService =
|
||||
new ProjectService(host, logger, (eventName, project, fileName) => {
|
||||
this.handleEvent(eventName, project, fileName);
|
||||
});
|
||||
this.handleEvent(eventName, project, fileName);
|
||||
});
|
||||
}
|
||||
|
||||
private handleEvent(eventName: string, project: Project, fileName: string) {
|
||||
@@ -178,6 +191,21 @@ namespace ts.server {
|
||||
"\r\n\r\n" + json);
|
||||
}
|
||||
|
||||
public configFileDiagnosticEvent(triggerFile: string, configFile: string, diagnostics: ts.Diagnostic[]) {
|
||||
const bakedDiags = ts.map(diagnostics, formatConfigFileDiag);
|
||||
const ev: protocol.ConfigFileDiagnosticEvent = {
|
||||
seq: 0,
|
||||
type: "event",
|
||||
event: "configFileDiag",
|
||||
body: {
|
||||
triggerFile,
|
||||
configFile,
|
||||
diagnostics: bakedDiags
|
||||
}
|
||||
};
|
||||
this.send(ev);
|
||||
}
|
||||
|
||||
public event(info: any, eventName: string) {
|
||||
const ev: protocol.Event = {
|
||||
seq: 0,
|
||||
@@ -288,7 +316,7 @@ namespace ts.server {
|
||||
private getDefinition(line: number, offset: number, fileName: string): protocol.FileSpan[] {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
@@ -310,7 +338,7 @@ namespace ts.server {
|
||||
private getTypeDefinition(line: number, offset: number, fileName: string): protocol.FileSpan[] {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
@@ -333,7 +361,7 @@ namespace ts.server {
|
||||
fileName = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(fileName);
|
||||
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
@@ -354,16 +382,37 @@ namespace ts.server {
|
||||
start,
|
||||
end,
|
||||
file: fileName,
|
||||
isWriteAccess
|
||||
isWriteAccess,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private getDiagnosticsWorker(args: protocol.FileRequestArgs, selector: (project: Project, file: string) => Diagnostic[]) {
|
||||
const file = normalizePath(args.file);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
if (project.languageServiceDiabled) {
|
||||
throw Errors.ProjectLanguageServiceDisabled;
|
||||
}
|
||||
const diagnostics = selector(project, file);
|
||||
return ts.map(diagnostics, originalDiagnostic => formatDiag(file, project, originalDiagnostic));
|
||||
}
|
||||
|
||||
private getSyntacticDiagnosticsSync(args: protocol.FileRequestArgs): protocol.Diagnostic[] {
|
||||
return this.getDiagnosticsWorker(args, (project, file) => project.compilerService.languageService.getSyntacticDiagnostics(file));
|
||||
}
|
||||
|
||||
private getSemanticDiagnosticsSync(args: protocol.FileRequestArgs): protocol.Diagnostic[] {
|
||||
return this.getDiagnosticsWorker(args, (project, file) => project.compilerService.languageService.getSemanticDiagnostics(file));
|
||||
}
|
||||
|
||||
private getDocumentHighlights(line: number, offset: number, fileName: string, filesToSearch: string[]): protocol.DocumentHighlightsItem[] {
|
||||
fileName = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(fileName);
|
||||
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
@@ -398,28 +447,35 @@ namespace ts.server {
|
||||
private getProjectInfo(fileName: string, needFileNameList: boolean): protocol.ProjectInfo {
|
||||
fileName = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(fileName);
|
||||
if (!project) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
const projectInfo: protocol.ProjectInfo = {
|
||||
configFileName: project.projectFilename
|
||||
configFileName: project.projectFilename,
|
||||
languageServiceDisabled: project.languageServiceDiabled
|
||||
};
|
||||
|
||||
if (needFileNameList) {
|
||||
projectInfo.fileNames = project.getFileNames();
|
||||
}
|
||||
|
||||
return projectInfo;
|
||||
}
|
||||
|
||||
private getRenameLocations(line: number, offset: number, fileName: string, findInComments: boolean, findInStrings: boolean): protocol.RenameResponseBody {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
const info = this.projectService.getScriptInfo(file);
|
||||
const projects = this.projectService.findReferencingProjects(info);
|
||||
const projectsWithLanguageServiceEnabeld = ts.filter(projects, p => !p.languageServiceDiabled);
|
||||
if (projectsWithLanguageServiceEnabeld.length === 0) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
const compilerService = project.compilerService;
|
||||
const position = compilerService.host.lineOffsetToPosition(file, line, offset);
|
||||
const renameInfo = compilerService.languageService.getRenameInfo(file, position);
|
||||
const defaultProject = projectsWithLanguageServiceEnabeld[0];
|
||||
// The rename info should be the same for every project
|
||||
const defaultProjectCompilerService = defaultProject.compilerService;
|
||||
const position = defaultProjectCompilerService.host.lineOffsetToPosition(file, line, offset);
|
||||
const renameInfo = defaultProjectCompilerService.languageService.getRenameInfo(file, position);
|
||||
if (!renameInfo) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -431,16 +487,43 @@ namespace ts.server {
|
||||
};
|
||||
}
|
||||
|
||||
const renameLocations = compilerService.languageService.findRenameLocations(file, position, findInStrings, findInComments);
|
||||
if (!renameLocations) {
|
||||
return undefined;
|
||||
}
|
||||
const fileSpans = combineProjectOutput(
|
||||
projectsWithLanguageServiceEnabeld,
|
||||
(project: Project) => {
|
||||
const compilerService = project.compilerService;
|
||||
const renameLocations = compilerService.languageService.findRenameLocations(file, position, findInStrings, findInComments);
|
||||
if (!renameLocations) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const bakedRenameLocs = renameLocations.map(location => (<protocol.FileSpan>{
|
||||
file: location.fileName,
|
||||
start: compilerService.host.positionToLineOffset(location.fileName, location.textSpan.start),
|
||||
end: compilerService.host.positionToLineOffset(location.fileName, ts.textSpanEnd(location.textSpan)),
|
||||
})).sort((a, b) => {
|
||||
return renameLocations.map(location => (<protocol.FileSpan>{
|
||||
file: location.fileName,
|
||||
start: compilerService.host.positionToLineOffset(location.fileName, location.textSpan.start),
|
||||
end: compilerService.host.positionToLineOffset(location.fileName, ts.textSpanEnd(location.textSpan)),
|
||||
}));
|
||||
},
|
||||
compareRenameLocation,
|
||||
(a, b) => a.file === b.file && a.start.line === b.start.line && a.start.offset === b.start.offset
|
||||
);
|
||||
const locs = fileSpans.reduce<protocol.SpanGroup[]>((accum, cur) => {
|
||||
let curFileAccum: protocol.SpanGroup;
|
||||
if (accum.length > 0) {
|
||||
curFileAccum = accum[accum.length - 1];
|
||||
if (curFileAccum.file !== cur.file) {
|
||||
curFileAccum = undefined;
|
||||
}
|
||||
}
|
||||
if (!curFileAccum) {
|
||||
curFileAccum = { file: cur.file, locs: [] };
|
||||
accum.push(curFileAccum);
|
||||
}
|
||||
curFileAccum.locs.push({ start: cur.start, end: cur.end });
|
||||
return accum;
|
||||
}, []);
|
||||
|
||||
return { info: renameInfo, locs };
|
||||
|
||||
function compareRenameLocation(a: protocol.FileSpan, b: protocol.FileSpan) {
|
||||
if (a.file < b.file) {
|
||||
return -1;
|
||||
}
|
||||
@@ -459,85 +542,90 @@ namespace ts.server {
|
||||
return b.start.offset - a.start.offset;
|
||||
}
|
||||
}
|
||||
}).reduce<protocol.SpanGroup[]>((accum: protocol.SpanGroup[], cur: protocol.FileSpan) => {
|
||||
let curFileAccum: protocol.SpanGroup;
|
||||
if (accum.length > 0) {
|
||||
curFileAccum = accum[accum.length - 1];
|
||||
if (curFileAccum.file != cur.file) {
|
||||
curFileAccum = undefined;
|
||||
}
|
||||
}
|
||||
if (!curFileAccum) {
|
||||
curFileAccum = { file: cur.file, locs: [] };
|
||||
accum.push(curFileAccum);
|
||||
}
|
||||
curFileAccum.locs.push({ start: cur.start, end: cur.end });
|
||||
return accum;
|
||||
}, []);
|
||||
|
||||
return { info: renameInfo, locs: bakedRenameLocs };
|
||||
}
|
||||
}
|
||||
|
||||
private getReferences(line: number, offset: number, fileName: string): protocol.ReferencesResponseBody {
|
||||
// TODO: get all projects for this file; report refs for all projects deleting duplicates
|
||||
// can avoid duplicates by eliminating same ref file from subsequent projects
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
const info = this.projectService.getScriptInfo(file);
|
||||
const projects = this.projectService.findReferencingProjects(info);
|
||||
const projectsWithLanguageServiceEnabeld = ts.filter(projects, p => !p.languageServiceDiabled);
|
||||
if (projectsWithLanguageServiceEnabeld.length === 0) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
const compilerService = project.compilerService;
|
||||
const position = compilerService.host.lineOffsetToPosition(file, line, offset);
|
||||
|
||||
const references = compilerService.languageService.getReferencesAtPosition(file, position);
|
||||
if (!references) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const nameInfo = compilerService.languageService.getQuickInfoAtPosition(file, position);
|
||||
const defaultProject = projectsWithLanguageServiceEnabeld[0];
|
||||
const position = defaultProject.compilerService.host.lineOffsetToPosition(file, line, offset);
|
||||
const nameInfo = defaultProject.compilerService.languageService.getQuickInfoAtPosition(file, position);
|
||||
if (!nameInfo) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const displayString = ts.displayPartsToString(nameInfo.displayParts);
|
||||
const nameSpan = nameInfo.textSpan;
|
||||
const nameColStart = compilerService.host.positionToLineOffset(file, nameSpan.start).offset;
|
||||
const nameText = compilerService.host.getScriptSnapshot(file).getText(nameSpan.start, ts.textSpanEnd(nameSpan));
|
||||
const bakedRefs: protocol.ReferencesResponseItem[] = references.map(ref => {
|
||||
const start = compilerService.host.positionToLineOffset(ref.fileName, ref.textSpan.start);
|
||||
const refLineSpan = compilerService.host.lineToTextSpan(ref.fileName, start.line - 1);
|
||||
const snap = compilerService.host.getScriptSnapshot(ref.fileName);
|
||||
const lineText = snap.getText(refLineSpan.start, ts.textSpanEnd(refLineSpan)).replace(/\r|\n/g, "");
|
||||
return {
|
||||
file: ref.fileName,
|
||||
start: start,
|
||||
lineText: lineText,
|
||||
end: compilerService.host.positionToLineOffset(ref.fileName, ts.textSpanEnd(ref.textSpan)),
|
||||
isWriteAccess: ref.isWriteAccess
|
||||
};
|
||||
}).sort(compareFileStart);
|
||||
const nameColStart = defaultProject.compilerService.host.positionToLineOffset(file, nameSpan.start).offset;
|
||||
const nameText = defaultProject.compilerService.host.getScriptSnapshot(file).getText(nameSpan.start, ts.textSpanEnd(nameSpan));
|
||||
const refs = combineProjectOutput<protocol.ReferencesResponseItem>(
|
||||
projectsWithLanguageServiceEnabeld,
|
||||
(project: Project) => {
|
||||
const compilerService = project.compilerService;
|
||||
const references = compilerService.languageService.getReferencesAtPosition(file, position);
|
||||
if (!references) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return references.map(ref => {
|
||||
const start = compilerService.host.positionToLineOffset(ref.fileName, ref.textSpan.start);
|
||||
const refLineSpan = compilerService.host.lineToTextSpan(ref.fileName, start.line - 1);
|
||||
const snap = compilerService.host.getScriptSnapshot(ref.fileName);
|
||||
const lineText = snap.getText(refLineSpan.start, ts.textSpanEnd(refLineSpan)).replace(/\r|\n/g, "");
|
||||
return {
|
||||
file: ref.fileName,
|
||||
start: start,
|
||||
lineText: lineText,
|
||||
end: compilerService.host.positionToLineOffset(ref.fileName, ts.textSpanEnd(ref.textSpan)),
|
||||
isWriteAccess: ref.isWriteAccess,
|
||||
isDefinition: ref.isDefinition
|
||||
};
|
||||
});
|
||||
},
|
||||
compareFileStart,
|
||||
areReferencesResponseItemsForTheSameLocation
|
||||
);
|
||||
|
||||
return {
|
||||
refs: bakedRefs,
|
||||
refs,
|
||||
symbolName: nameText,
|
||||
symbolStartOffset: nameColStart,
|
||||
symbolDisplayString: displayString
|
||||
};
|
||||
|
||||
function areReferencesResponseItemsForTheSameLocation(a: protocol.ReferencesResponseItem, b: protocol.ReferencesResponseItem) {
|
||||
if (a && b) {
|
||||
return a.file === b.file &&
|
||||
a.start === b.start &&
|
||||
a.end === b.end;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fileName is the name of the file to be opened
|
||||
* @param fileContent is a version of the file content that is known to be more up to date than the one on disk
|
||||
*/
|
||||
private openClientFile(fileName: string, fileContent?: string) {
|
||||
private openClientFile(fileName: string, fileContent?: string, scriptKind?: ScriptKind) {
|
||||
const file = ts.normalizePath(fileName);
|
||||
this.projectService.openClientFile(file, fileContent);
|
||||
const { configFileName, configFileErrors } = this.projectService.openClientFile(file, fileContent, scriptKind);
|
||||
if (configFileErrors) {
|
||||
this.configFileDiagnosticEvent(fileName, configFileName, configFileErrors);
|
||||
}
|
||||
}
|
||||
|
||||
private getQuickInfo(line: number, offset: number, fileName: string): protocol.QuickInfoResponseBody {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
@@ -563,7 +651,7 @@ namespace ts.server {
|
||||
private getFormattingEditsForRange(line: number, offset: number, endLine: number, endOffset: number, fileName: string): protocol.CodeEdit[] {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
@@ -591,7 +679,7 @@ namespace ts.server {
|
||||
const file = ts.normalizePath(fileName);
|
||||
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
@@ -615,9 +703,10 @@ namespace ts.server {
|
||||
if (lineText.search("\\S") < 0) {
|
||||
// TODO: get these options from host
|
||||
const editorOptions: ts.EditorOptions = {
|
||||
BaseIndentSize: formatOptions.BaseIndentSize,
|
||||
IndentSize: formatOptions.IndentSize,
|
||||
TabSize: formatOptions.TabSize,
|
||||
NewLineCharacter: "\n",
|
||||
NewLineCharacter: formatOptions.NewLineCharacter,
|
||||
ConvertTabsToSpaces: formatOptions.ConvertTabsToSpaces,
|
||||
IndentStyle: ts.IndentStyle.Smart,
|
||||
};
|
||||
@@ -669,7 +758,7 @@ namespace ts.server {
|
||||
}
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
@@ -693,7 +782,7 @@ namespace ts.server {
|
||||
entryNames: string[], fileName: string): protocol.CompletionEntryDetails[] {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
@@ -712,7 +801,7 @@ namespace ts.server {
|
||||
private getSignatureHelpItems(line: number, offset: number, fileName: string): protocol.SignatureHelpItems {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
@@ -742,7 +831,7 @@ namespace ts.server {
|
||||
const checkList = fileNames.reduce((accum: PendingErrorCheck[], fileName: string) => {
|
||||
fileName = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(fileName);
|
||||
if (project) {
|
||||
if (project && !project.languageServiceDiabled) {
|
||||
accum.push({ fileName, project });
|
||||
}
|
||||
return accum;
|
||||
@@ -756,7 +845,7 @@ namespace ts.server {
|
||||
private change(line: number, offset: number, endLine: number, endOffset: number, insertString: string, fileName: string) {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (project) {
|
||||
if (project && !project.languageServiceDiabled) {
|
||||
const compilerService = project.compilerService;
|
||||
const start = compilerService.host.lineOffsetToPosition(file, line, offset);
|
||||
const end = compilerService.host.lineOffsetToPosition(file, endLine, endOffset);
|
||||
@@ -772,7 +861,7 @@ namespace ts.server {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const tmpfile = ts.normalizePath(tempFileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (project) {
|
||||
if (project && !project.languageServiceDiabled) {
|
||||
this.changeSeq++;
|
||||
// make sure no changes happen before this one is finished
|
||||
project.compilerService.host.reloadScript(file, tmpfile, () => {
|
||||
@@ -786,7 +875,7 @@ namespace ts.server {
|
||||
const tmpfile = ts.normalizePath(tempFileName);
|
||||
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (project) {
|
||||
if (project && !project.languageServiceDiabled) {
|
||||
project.compilerService.host.saveTo(file, tmpfile);
|
||||
}
|
||||
}
|
||||
@@ -799,7 +888,7 @@ namespace ts.server {
|
||||
this.projectService.closeClientFile(file);
|
||||
}
|
||||
|
||||
private decorateNavigationBarItem(project: Project, fileName: string, items: ts.NavigationBarItem[]): protocol.NavigationBarItem[] {
|
||||
private decorateNavigationBarItem(project: Project, fileName: string, items: ts.NavigationBarItem[], lineIndex: LineIndex): protocol.NavigationBarItem[] {
|
||||
if (!items) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -811,17 +900,18 @@ namespace ts.server {
|
||||
kind: item.kind,
|
||||
kindModifiers: item.kindModifiers,
|
||||
spans: item.spans.map(span => ({
|
||||
start: compilerService.host.positionToLineOffset(fileName, span.start),
|
||||
end: compilerService.host.positionToLineOffset(fileName, ts.textSpanEnd(span))
|
||||
start: compilerService.host.positionToLineOffset(fileName, span.start, lineIndex),
|
||||
end: compilerService.host.positionToLineOffset(fileName, ts.textSpanEnd(span), lineIndex)
|
||||
})),
|
||||
childItems: this.decorateNavigationBarItem(project, fileName, item.childItems)
|
||||
childItems: this.decorateNavigationBarItem(project, fileName, item.childItems, lineIndex),
|
||||
indent: item.indent
|
||||
}));
|
||||
}
|
||||
|
||||
private getNavigationBarItems(fileName: string): protocol.NavigationBarItem[] {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
@@ -831,53 +921,72 @@ namespace ts.server {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.decorateNavigationBarItem(project, fileName, items);
|
||||
return this.decorateNavigationBarItem(project, fileName, items, compilerService.host.getLineIndex(fileName));
|
||||
}
|
||||
|
||||
private getNavigateToItems(searchValue: string, fileName: string, maxResultCount?: number): protocol.NavtoItem[] {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
const info = this.projectService.getScriptInfo(file);
|
||||
const projects = this.projectService.findReferencingProjects(info);
|
||||
const projectsWithLanguageServiceEnabeld = ts.filter(projects, p => !p.languageServiceDiabled);
|
||||
if (projectsWithLanguageServiceEnabeld.length === 0) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
const compilerService = project.compilerService;
|
||||
const navItems = compilerService.languageService.getNavigateToItems(searchValue, maxResultCount);
|
||||
if (!navItems) {
|
||||
return undefined;
|
||||
}
|
||||
const allNavToItems = combineProjectOutput(
|
||||
projectsWithLanguageServiceEnabeld,
|
||||
(project: Project) => {
|
||||
const compilerService = project.compilerService;
|
||||
const navItems = compilerService.languageService.getNavigateToItems(searchValue, maxResultCount);
|
||||
if (!navItems) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return navItems.map((navItem) => {
|
||||
const start = compilerService.host.positionToLineOffset(navItem.fileName, navItem.textSpan.start);
|
||||
const end = compilerService.host.positionToLineOffset(navItem.fileName, ts.textSpanEnd(navItem.textSpan));
|
||||
const bakedItem: protocol.NavtoItem = {
|
||||
name: navItem.name,
|
||||
kind: navItem.kind,
|
||||
file: navItem.fileName,
|
||||
start: start,
|
||||
end: end,
|
||||
};
|
||||
if (navItem.kindModifiers && (navItem.kindModifiers != "")) {
|
||||
bakedItem.kindModifiers = navItem.kindModifiers;
|
||||
return navItems.map((navItem) => {
|
||||
const start = compilerService.host.positionToLineOffset(navItem.fileName, navItem.textSpan.start);
|
||||
const end = compilerService.host.positionToLineOffset(navItem.fileName, ts.textSpanEnd(navItem.textSpan));
|
||||
const bakedItem: protocol.NavtoItem = {
|
||||
name: navItem.name,
|
||||
kind: navItem.kind,
|
||||
file: navItem.fileName,
|
||||
start: start,
|
||||
end: end,
|
||||
};
|
||||
if (navItem.kindModifiers && (navItem.kindModifiers !== "")) {
|
||||
bakedItem.kindModifiers = navItem.kindModifiers;
|
||||
}
|
||||
if (navItem.matchKind !== "none") {
|
||||
bakedItem.matchKind = navItem.matchKind;
|
||||
}
|
||||
if (navItem.containerName && (navItem.containerName.length > 0)) {
|
||||
bakedItem.containerName = navItem.containerName;
|
||||
}
|
||||
if (navItem.containerKind && (navItem.containerKind.length > 0)) {
|
||||
bakedItem.containerKind = navItem.containerKind;
|
||||
}
|
||||
return bakedItem;
|
||||
});
|
||||
},
|
||||
/*comparer*/ undefined,
|
||||
areNavToItemsForTheSameLocation
|
||||
);
|
||||
return allNavToItems;
|
||||
|
||||
function areNavToItemsForTheSameLocation(a: protocol.NavtoItem, b: protocol.NavtoItem) {
|
||||
if (a && b) {
|
||||
return a.file === b.file &&
|
||||
a.start === b.start &&
|
||||
a.end === b.end;
|
||||
}
|
||||
if (navItem.matchKind !== "none") {
|
||||
bakedItem.matchKind = navItem.matchKind;
|
||||
}
|
||||
if (navItem.containerName && (navItem.containerName.length > 0)) {
|
||||
bakedItem.containerName = navItem.containerName;
|
||||
}
|
||||
if (navItem.containerKind && (navItem.containerKind.length > 0)) {
|
||||
bakedItem.containerKind = navItem.containerKind;
|
||||
}
|
||||
return bakedItem;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private getBraceMatching(line: number, offset: number, fileName: string): protocol.TextSpan[] {
|
||||
const file = ts.normalizePath(fileName);
|
||||
|
||||
const project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
if (!project || project.languageServiceDiabled) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
@@ -896,7 +1005,11 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
getDiagnosticsForProject(delay: number, fileName: string) {
|
||||
const { fileNames } = this.getProjectInfo(fileName, /*needFileNameList*/ true);
|
||||
const { fileNames, languageServiceDisabled } = this.getProjectInfo(fileName, /*needFileNameList*/ true);
|
||||
if (languageServiceDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No need to analyze lib.d.ts
|
||||
let fileNamesInProject = fileNames.filter((value, index, array) => value.indexOf("lib.d.ts") < 0);
|
||||
|
||||
@@ -944,129 +1057,156 @@ namespace ts.server {
|
||||
exit() {
|
||||
}
|
||||
|
||||
private handlers: Map<(request: protocol.Request) => {response?: any, responseRequired?: boolean}> = {
|
||||
private requiredResponse(response: any) {
|
||||
return { response, responseRequired: true };
|
||||
}
|
||||
|
||||
private handlers: Map<(request: protocol.Request) => { response?: any, responseRequired?: boolean }> = {
|
||||
[CommandNames.Exit]: () => {
|
||||
this.exit();
|
||||
return { responseRequired: false};
|
||||
return { responseRequired: false };
|
||||
},
|
||||
[CommandNames.Definition]: (request: protocol.Request) => {
|
||||
const defArgs = <protocol.FileLocationRequestArgs>request.arguments;
|
||||
return {response: this.getDefinition(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true};
|
||||
return { response: this.getDefinition(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true };
|
||||
},
|
||||
[CommandNames.TypeDefinition]: (request: protocol.Request) => {
|
||||
const defArgs = <protocol.FileLocationRequestArgs>request.arguments;
|
||||
return {response: this.getTypeDefinition(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true};
|
||||
return { response: this.getTypeDefinition(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true };
|
||||
},
|
||||
[CommandNames.References]: (request: protocol.Request) => {
|
||||
const defArgs = <protocol.FileLocationRequestArgs>request.arguments;
|
||||
return {response: this.getReferences(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true};
|
||||
return { response: this.getReferences(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true };
|
||||
},
|
||||
[CommandNames.Rename]: (request: protocol.Request) => {
|
||||
const renameArgs = <protocol.RenameRequestArgs>request.arguments;
|
||||
return {response: this.getRenameLocations(renameArgs.line, renameArgs.offset, renameArgs.file, renameArgs.findInComments, renameArgs.findInStrings), responseRequired: true};
|
||||
return { response: this.getRenameLocations(renameArgs.line, renameArgs.offset, renameArgs.file, renameArgs.findInComments, renameArgs.findInStrings), responseRequired: true };
|
||||
},
|
||||
[CommandNames.Open]: (request: protocol.Request) => {
|
||||
const openArgs = <protocol.OpenRequestArgs>request.arguments;
|
||||
this.openClientFile(openArgs.file, openArgs.fileContent);
|
||||
return {responseRequired: false};
|
||||
let scriptKind: ScriptKind;
|
||||
switch (openArgs.scriptKindName) {
|
||||
case "TS":
|
||||
scriptKind = ScriptKind.TS;
|
||||
break;
|
||||
case "JS":
|
||||
scriptKind = ScriptKind.JS;
|
||||
break;
|
||||
case "TSX":
|
||||
scriptKind = ScriptKind.TSX;
|
||||
break;
|
||||
case "JSX":
|
||||
scriptKind = ScriptKind.JSX;
|
||||
break;
|
||||
}
|
||||
this.openClientFile(openArgs.file, openArgs.fileContent, scriptKind);
|
||||
return { responseRequired: false };
|
||||
},
|
||||
[CommandNames.Quickinfo]: (request: protocol.Request) => {
|
||||
const quickinfoArgs = <protocol.FileLocationRequestArgs>request.arguments;
|
||||
return {response: this.getQuickInfo(quickinfoArgs.line, quickinfoArgs.offset, quickinfoArgs.file), responseRequired: true};
|
||||
return { response: this.getQuickInfo(quickinfoArgs.line, quickinfoArgs.offset, quickinfoArgs.file), responseRequired: true };
|
||||
},
|
||||
[CommandNames.Format]: (request: protocol.Request) => {
|
||||
const formatArgs = <protocol.FormatRequestArgs>request.arguments;
|
||||
return {response: this.getFormattingEditsForRange(formatArgs.line, formatArgs.offset, formatArgs.endLine, formatArgs.endOffset, formatArgs.file), responseRequired: true};
|
||||
return { response: this.getFormattingEditsForRange(formatArgs.line, formatArgs.offset, formatArgs.endLine, formatArgs.endOffset, formatArgs.file), responseRequired: true };
|
||||
},
|
||||
[CommandNames.Formatonkey]: (request: protocol.Request) => {
|
||||
const formatOnKeyArgs = <protocol.FormatOnKeyRequestArgs>request.arguments;
|
||||
return {response: this.getFormattingEditsAfterKeystroke(formatOnKeyArgs.line, formatOnKeyArgs.offset, formatOnKeyArgs.key, formatOnKeyArgs.file), responseRequired: true};
|
||||
return { response: this.getFormattingEditsAfterKeystroke(formatOnKeyArgs.line, formatOnKeyArgs.offset, formatOnKeyArgs.key, formatOnKeyArgs.file), responseRequired: true };
|
||||
},
|
||||
[CommandNames.Completions]: (request: protocol.Request) => {
|
||||
const completionsArgs = <protocol.CompletionsRequestArgs>request.arguments;
|
||||
return {response: this.getCompletions(completionsArgs.line, completionsArgs.offset, completionsArgs.prefix, completionsArgs.file), responseRequired: true};
|
||||
return { response: this.getCompletions(completionsArgs.line, completionsArgs.offset, completionsArgs.prefix, completionsArgs.file), responseRequired: true };
|
||||
},
|
||||
[CommandNames.CompletionDetails]: (request: protocol.Request) => {
|
||||
const completionDetailsArgs = <protocol.CompletionDetailsRequestArgs>request.arguments;
|
||||
return {response: this.getCompletionEntryDetails(completionDetailsArgs.line, completionDetailsArgs.offset,
|
||||
completionDetailsArgs.entryNames, completionDetailsArgs.file), responseRequired: true};
|
||||
return {
|
||||
response: this.getCompletionEntryDetails(completionDetailsArgs.line, completionDetailsArgs.offset,
|
||||
completionDetailsArgs.entryNames, completionDetailsArgs.file), responseRequired: true
|
||||
};
|
||||
},
|
||||
[CommandNames.SignatureHelp]: (request: protocol.Request) => {
|
||||
const signatureHelpArgs = <protocol.SignatureHelpRequestArgs>request.arguments;
|
||||
return {response: this.getSignatureHelpItems(signatureHelpArgs.line, signatureHelpArgs.offset, signatureHelpArgs.file), responseRequired: true};
|
||||
return { response: this.getSignatureHelpItems(signatureHelpArgs.line, signatureHelpArgs.offset, signatureHelpArgs.file), responseRequired: true };
|
||||
},
|
||||
[CommandNames.SemanticDiagnosticsSync]: (request: protocol.FileRequest) => {
|
||||
return this.requiredResponse(this.getSemanticDiagnosticsSync(request.arguments));
|
||||
},
|
||||
[CommandNames.SyntacticDiagnosticsSync]: (request: protocol.FileRequest) => {
|
||||
return this.requiredResponse(this.getSyntacticDiagnosticsSync(request.arguments));
|
||||
},
|
||||
[CommandNames.Geterr]: (request: protocol.Request) => {
|
||||
const geterrArgs = <protocol.GeterrRequestArgs>request.arguments;
|
||||
return {response: this.getDiagnostics(geterrArgs.delay, geterrArgs.files), responseRequired: false};
|
||||
return { response: this.getDiagnostics(geterrArgs.delay, geterrArgs.files), responseRequired: false };
|
||||
},
|
||||
[CommandNames.GeterrForProject]: (request: protocol.Request) => {
|
||||
const { file, delay } = <protocol.GeterrForProjectRequestArgs>request.arguments;
|
||||
return {response: this.getDiagnosticsForProject(delay, file), responseRequired: false};
|
||||
return { response: this.getDiagnosticsForProject(delay, file), responseRequired: false };
|
||||
},
|
||||
[CommandNames.Change]: (request: protocol.Request) => {
|
||||
const changeArgs = <protocol.ChangeRequestArgs>request.arguments;
|
||||
this.change(changeArgs.line, changeArgs.offset, changeArgs.endLine, changeArgs.endOffset,
|
||||
changeArgs.insertString, changeArgs.file);
|
||||
return {responseRequired: false};
|
||||
changeArgs.insertString, changeArgs.file);
|
||||
return { responseRequired: false };
|
||||
},
|
||||
[CommandNames.Configure]: (request: protocol.Request) => {
|
||||
const configureArgs = <protocol.ConfigureRequestArguments>request.arguments;
|
||||
this.projectService.setHostConfiguration(configureArgs);
|
||||
this.output(undefined, CommandNames.Configure, request.seq);
|
||||
return {responseRequired: false};
|
||||
return { responseRequired: false };
|
||||
},
|
||||
[CommandNames.Reload]: (request: protocol.Request) => {
|
||||
const reloadArgs = <protocol.ReloadRequestArgs>request.arguments;
|
||||
this.reload(reloadArgs.file, reloadArgs.tmpfile, request.seq);
|
||||
return {responseRequired: false};
|
||||
return { response: { reloadFinished: true }, responseRequired: true };
|
||||
},
|
||||
[CommandNames.Saveto]: (request: protocol.Request) => {
|
||||
const savetoArgs = <protocol.SavetoRequestArgs>request.arguments;
|
||||
this.saveToTmp(savetoArgs.file, savetoArgs.tmpfile);
|
||||
return {responseRequired: false};
|
||||
return { responseRequired: false };
|
||||
},
|
||||
[CommandNames.Close]: (request: protocol.Request) => {
|
||||
const closeArgs = <protocol.FileRequestArgs>request.arguments;
|
||||
this.closeClientFile(closeArgs.file);
|
||||
return {responseRequired: false};
|
||||
return { responseRequired: false };
|
||||
},
|
||||
[CommandNames.Navto]: (request: protocol.Request) => {
|
||||
const navtoArgs = <protocol.NavtoRequestArgs>request.arguments;
|
||||
return {response: this.getNavigateToItems(navtoArgs.searchValue, navtoArgs.file, navtoArgs.maxResultCount), responseRequired: true};
|
||||
return { response: this.getNavigateToItems(navtoArgs.searchValue, navtoArgs.file, navtoArgs.maxResultCount), responseRequired: true };
|
||||
},
|
||||
[CommandNames.Brace]: (request: protocol.Request) => {
|
||||
const braceArguments = <protocol.FileLocationRequestArgs>request.arguments;
|
||||
return {response: this.getBraceMatching(braceArguments.line, braceArguments.offset, braceArguments.file), responseRequired: true};
|
||||
return { response: this.getBraceMatching(braceArguments.line, braceArguments.offset, braceArguments.file), responseRequired: true };
|
||||
},
|
||||
[CommandNames.NavBar]: (request: protocol.Request) => {
|
||||
const navBarArgs = <protocol.FileRequestArgs>request.arguments;
|
||||
return {response: this.getNavigationBarItems(navBarArgs.file), responseRequired: true};
|
||||
return { response: this.getNavigationBarItems(navBarArgs.file), responseRequired: true };
|
||||
},
|
||||
[CommandNames.Occurrences]: (request: protocol.Request) => {
|
||||
const { line, offset, file: fileName } = <protocol.FileLocationRequestArgs>request.arguments;
|
||||
return {response: this.getOccurrences(line, offset, fileName), responseRequired: true};
|
||||
return { response: this.getOccurrences(line, offset, fileName), responseRequired: true };
|
||||
},
|
||||
[CommandNames.DocumentHighlights]: (request: protocol.Request) => {
|
||||
const { line, offset, file: fileName, filesToSearch } = <protocol.DocumentHighlightsRequestArgs>request.arguments;
|
||||
return {response: this.getDocumentHighlights(line, offset, fileName, filesToSearch), responseRequired: true};
|
||||
return { response: this.getDocumentHighlights(line, offset, fileName, filesToSearch), responseRequired: true };
|
||||
},
|
||||
[CommandNames.ProjectInfo]: (request: protocol.Request) => {
|
||||
const { file, needFileNameList } = <protocol.ProjectInfoRequestArgs>request.arguments;
|
||||
return {response: this.getProjectInfo(file, needFileNameList), responseRequired: true};
|
||||
return { response: this.getProjectInfo(file, needFileNameList), responseRequired: true };
|
||||
},
|
||||
[CommandNames.ReloadProjects]: (request: protocol.ReloadProjectsRequest) => {
|
||||
this.reloadProjects();
|
||||
return {responseRequired: false};
|
||||
return { responseRequired: false };
|
||||
}
|
||||
};
|
||||
public addProtocolHandler(command: string, handler: (request: protocol.Request) => {response?: any, responseRequired: boolean}) {
|
||||
public addProtocolHandler(command: string, handler: (request: protocol.Request) => { response?: any, responseRequired: boolean }) {
|
||||
if (this.handlers[command]) {
|
||||
throw new Error(`Protocol handler already exists for command "${command}"`);
|
||||
}
|
||||
this.handlers[command] = handler;
|
||||
}
|
||||
|
||||
public executeCommand(request: protocol.Request): {response?: any, responseRequired?: boolean} {
|
||||
public executeCommand(request: protocol.Request): { response?: any, responseRequired?: boolean } {
|
||||
const handler = this.handlers[request.command];
|
||||
if (handler) {
|
||||
return handler(request);
|
||||
@@ -1074,7 +1214,7 @@ namespace ts.server {
|
||||
else {
|
||||
this.projectService.log("Unrecognized JSON command: " + JSON.stringify(request));
|
||||
this.output(undefined, CommandNames.Unknown, request.seq, "Unrecognized JSON command: " + request.command);
|
||||
return {responseRequired: false};
|
||||
return { responseRequired: false };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1112,7 +1252,11 @@ namespace ts.server {
|
||||
// Handle cancellation exceptions
|
||||
}
|
||||
this.logError(err, message);
|
||||
this.output(undefined, request ? request.command : CommandNames.Unknown, request ? request.seq : 0, "Error processing request. " + err.message);
|
||||
this.output(
|
||||
undefined,
|
||||
request ? request.command : CommandNames.Unknown,
|
||||
request ? request.seq : 0,
|
||||
"Error processing request. " + (<StackTraceError>err).message + "\n" + (<StackTraceError>err).stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,16 @@
|
||||
"removeComments": true,
|
||||
"preserveConstEnums": true,
|
||||
"out": "../../built/local/tsserver.js",
|
||||
"sourceMap": true
|
||||
"sourceMap": true,
|
||||
"stripInternal": true
|
||||
},
|
||||
"files": [
|
||||
"../services/shims.ts",
|
||||
"../services/utilities.ts",
|
||||
"node.d.ts",
|
||||
"editorServices.ts",
|
||||
"protocol.d.ts",
|
||||
"server.ts",
|
||||
"session.ts"
|
||||
"session.ts",
|
||||
"server.ts"
|
||||
]
|
||||
}
|
||||
|
||||
+40
-40
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0.
|
||||
// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0.
|
||||
// See LICENSE.txt in the project root for complete license information.
|
||||
|
||||
/// <reference path='services.ts' />
|
||||
@@ -15,16 +15,16 @@ namespace ts.BreakpointResolver {
|
||||
}
|
||||
|
||||
let tokenAtLocation = getTokenAtPosition(sourceFile, position);
|
||||
let lineOfPosition = sourceFile.getLineAndCharacterOfPosition(position).line;
|
||||
const lineOfPosition = sourceFile.getLineAndCharacterOfPosition(position).line;
|
||||
if (sourceFile.getLineAndCharacterOfPosition(tokenAtLocation.getStart(sourceFile)).line > lineOfPosition) {
|
||||
// Get previous token if the token is returned starts on new line
|
||||
// eg: let x =10; |--- cursor is here
|
||||
// let y = 10;
|
||||
// token at position will return let keyword on second line as the token but we would like to use
|
||||
// let y = 10;
|
||||
// token at position will return let keyword on second line as the token but we would like to use
|
||||
// token on same line if trailing trivia (comments or white spaces on same line) part of the last token on that line
|
||||
tokenAtLocation = findPrecedingToken(tokenAtLocation.pos, sourceFile);
|
||||
|
||||
// Its a blank line
|
||||
// It's a blank line
|
||||
if (!tokenAtLocation || sourceFile.getLineAndCharacterOfPosition(tokenAtLocation.getEnd()).line !== lineOfPosition) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -216,7 +216,7 @@ namespace ts.BreakpointResolver {
|
||||
return spanInNodeIfStartsOnSameLine(findPrecedingToken(node.pos, sourceFile));
|
||||
|
||||
case SyntaxKind.CommaToken:
|
||||
return spanInPreviousNode(node)
|
||||
return spanInPreviousNode(node);
|
||||
|
||||
case SyntaxKind.OpenBraceToken:
|
||||
return spanInOpenBraceToken(node);
|
||||
@@ -259,13 +259,13 @@ namespace ts.BreakpointResolver {
|
||||
if (isArrayLiteralOrObjectLiteralDestructuringPattern(node)) {
|
||||
return spanInArrayLiteralOrObjectLiteralDestructuringPattern(<DestructuringPattern>node);
|
||||
}
|
||||
|
||||
|
||||
// Set breakpoint on identifier element of destructuring pattern
|
||||
// a or ...c or d: x from
|
||||
// a or ...c or d: x from
|
||||
// [a, b, ...c] or { a, b } or { d: x } from destructuring pattern
|
||||
if ((node.kind === SyntaxKind.Identifier ||
|
||||
node.kind == SyntaxKind.SpreadElementExpression ||
|
||||
node.kind === SyntaxKind.PropertyAssignment ||
|
||||
node.kind == SyntaxKind.SpreadElementExpression ||
|
||||
node.kind === SyntaxKind.PropertyAssignment ||
|
||||
node.kind === SyntaxKind.ShorthandPropertyAssignment) &&
|
||||
isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent)) {
|
||||
return textSpan(node);
|
||||
@@ -275,7 +275,7 @@ namespace ts.BreakpointResolver {
|
||||
const binaryExpression = <BinaryExpression>node;
|
||||
// Set breakpoint in destructuring pattern if its destructuring assignment
|
||||
// [a, b, c] or {a, b, c} of
|
||||
// [a, b, c] = expression or
|
||||
// [a, b, c] = expression or
|
||||
// {a, b, c} = expression
|
||||
if (isArrayLiteralOrObjectLiteralDestructuringPattern(binaryExpression.left)) {
|
||||
return spanInArrayLiteralOrObjectLiteralDestructuringPattern(
|
||||
@@ -285,8 +285,8 @@ namespace ts.BreakpointResolver {
|
||||
if (binaryExpression.operatorToken.kind === SyntaxKind.EqualsToken &&
|
||||
isArrayLiteralOrObjectLiteralDestructuringPattern(binaryExpression.parent)) {
|
||||
// Set breakpoint on assignment expression element of destructuring pattern
|
||||
// a = expression of
|
||||
// [a = expression, b, c] = someExpression or
|
||||
// a = expression of
|
||||
// [a = expression, b, c] = someExpression or
|
||||
// { a = expression, b, c } = someExpression
|
||||
return textSpan(node);
|
||||
}
|
||||
@@ -312,7 +312,7 @@ namespace ts.BreakpointResolver {
|
||||
|
||||
case SyntaxKind.BinaryExpression:
|
||||
if ((<BinaryExpression>node.parent).operatorToken.kind === SyntaxKind.CommaToken) {
|
||||
// if this is comma expression, the breakpoint is possible in this expression
|
||||
// If this is a comma expression, the breakpoint is possible in this expression
|
||||
return textSpan(node);
|
||||
}
|
||||
break;
|
||||
@@ -325,14 +325,14 @@ namespace ts.BreakpointResolver {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If this is name of property assignment, set breakpoint in the initializer
|
||||
if (node.parent.kind === SyntaxKind.PropertyAssignment &&
|
||||
(<PropertyDeclaration>node.parent).name === node &&
|
||||
(<PropertyDeclaration>node.parent).name === node &&
|
||||
!isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent.parent)) {
|
||||
return spanInNode((<PropertyDeclaration>node.parent).initializer);
|
||||
}
|
||||
|
||||
|
||||
// Breakpoint in type assertion goes to its operand
|
||||
if (node.parent.kind === SyntaxKind.TypeAssertionExpression && (<TypeAssertion>node.parent).type === node) {
|
||||
return spanInNextNode((<TypeAssertion>node.parent).type);
|
||||
@@ -370,7 +370,7 @@ namespace ts.BreakpointResolver {
|
||||
}
|
||||
|
||||
function textSpanFromVariableDeclaration(variableDeclaration: VariableDeclaration): TextSpan {
|
||||
let declarations = variableDeclaration.parent.declarations;
|
||||
const declarations = variableDeclaration.parent.declarations;
|
||||
if (declarations && declarations[0] === variableDeclaration) {
|
||||
// First declaration - include let keyword
|
||||
return textSpan(findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent), variableDeclaration);
|
||||
@@ -386,8 +386,8 @@ namespace ts.BreakpointResolver {
|
||||
if (variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement) {
|
||||
return spanInNode(variableDeclaration.parent.parent);
|
||||
}
|
||||
|
||||
// If this is a destructuring pattern set breakpoint in binding pattern
|
||||
|
||||
// If this is a destructuring pattern, set breakpoint in binding pattern
|
||||
if (isBindingPattern(variableDeclaration.name)) {
|
||||
return spanInBindingPattern(<BindingPattern>variableDeclaration.name);
|
||||
}
|
||||
@@ -400,11 +400,11 @@ namespace ts.BreakpointResolver {
|
||||
return textSpanFromVariableDeclaration(variableDeclaration);
|
||||
}
|
||||
|
||||
let declarations = variableDeclaration.parent.declarations;
|
||||
const declarations = variableDeclaration.parent.declarations;
|
||||
if (declarations && declarations[0] !== variableDeclaration) {
|
||||
// If we cant set breakpoint on this declaration, set it on previous one
|
||||
// Because the variable declaration may be binding pattern and
|
||||
// we would like to set breakpoint in last binding element if thats the case,
|
||||
// If we cannot set breakpoint on this declaration, set it on previous one
|
||||
// Because the variable declaration may be binding pattern and
|
||||
// we would like to set breakpoint in last binding element if that's the case,
|
||||
// use preceding token instead
|
||||
return spanInNode(findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent));
|
||||
}
|
||||
@@ -418,15 +418,15 @@ namespace ts.BreakpointResolver {
|
||||
|
||||
function spanInParameterDeclaration(parameter: ParameterDeclaration): TextSpan {
|
||||
if (isBindingPattern(parameter.name)) {
|
||||
// set breakpoint in binding pattern
|
||||
// Set breakpoint in binding pattern
|
||||
return spanInBindingPattern(<BindingPattern>parameter.name);
|
||||
}
|
||||
else if (canHaveSpanInParameterDeclaration(parameter)) {
|
||||
return textSpan(parameter);
|
||||
}
|
||||
else {
|
||||
let functionDeclaration = <FunctionLikeDeclaration>parameter.parent;
|
||||
let indexOfParameter = indexOf(functionDeclaration.parameters, parameter);
|
||||
const functionDeclaration = <FunctionLikeDeclaration>parameter.parent;
|
||||
const indexOfParameter = indexOf(functionDeclaration.parameters, parameter);
|
||||
if (indexOfParameter) {
|
||||
// Not a first parameter, go to previous parameter
|
||||
return spanInParameterDeclaration(functionDeclaration.parameters[indexOfParameter - 1]);
|
||||
@@ -459,7 +459,7 @@ namespace ts.BreakpointResolver {
|
||||
}
|
||||
|
||||
function spanInFunctionBlock(block: Block): TextSpan {
|
||||
let nodeForSpanInBlock = block.statements.length ? block.statements[0] : block.getLastToken();
|
||||
const nodeForSpanInBlock = block.statements.length ? block.statements[0] : block.getLastToken();
|
||||
if (canFunctionHaveSpanInWholeDeclaration(<FunctionLikeDeclaration>block.parent)) {
|
||||
return spanInNodeIfStartsOnSameLine(block.parent, nodeForSpanInBlock);
|
||||
}
|
||||
@@ -492,8 +492,8 @@ namespace ts.BreakpointResolver {
|
||||
|
||||
function spanInInitializerOfForLike(forLikeStatement: ForStatement | ForOfStatement | ForInStatement): TextSpan {
|
||||
if (forLikeStatement.initializer.kind === SyntaxKind.VariableDeclarationList) {
|
||||
// declaration list, set breakpoint in first declaration
|
||||
let variableDeclarationList = <VariableDeclarationList>forLikeStatement.initializer;
|
||||
// Declaration list - set breakpoint in first declaration
|
||||
const variableDeclarationList = <VariableDeclarationList>forLikeStatement.initializer;
|
||||
if (variableDeclarationList.declarations.length > 0) {
|
||||
return spanInNode(variableDeclarationList.declarations[0]);
|
||||
}
|
||||
@@ -519,7 +519,7 @@ namespace ts.BreakpointResolver {
|
||||
|
||||
function spanInBindingPattern(bindingPattern: BindingPattern): TextSpan {
|
||||
// Set breakpoint in first binding element
|
||||
let firstBindingElement = forEach(bindingPattern.elements,
|
||||
const firstBindingElement = forEach(bindingPattern.elements,
|
||||
element => element.kind !== SyntaxKind.OmittedExpression ? element : undefined);
|
||||
|
||||
if (firstBindingElement) {
|
||||
@@ -549,7 +549,7 @@ namespace ts.BreakpointResolver {
|
||||
return spanInNode(firstBindingElement);
|
||||
}
|
||||
|
||||
// Could be ArrayLiteral from destructuring assignment or
|
||||
// Could be ArrayLiteral from destructuring assignment or
|
||||
// just nested element in another destructuring assignment
|
||||
// set breakpoint on assignment when parent is destructuring assignment
|
||||
// Otherwise set breakpoint for this element
|
||||
@@ -578,7 +578,7 @@ namespace ts.BreakpointResolver {
|
||||
function spanInCloseBraceToken(node: Node): TextSpan {
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.ModuleBlock:
|
||||
// If this is not instantiated module block no bp span
|
||||
// If this is not an instantiated module block, no bp span
|
||||
if (getModuleInstanceState(node.parent.parent) !== ModuleInstanceState.Instantiated) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -593,7 +593,7 @@ namespace ts.BreakpointResolver {
|
||||
// Span on close brace token
|
||||
return textSpan(node);
|
||||
}
|
||||
// fall through.
|
||||
// fall through
|
||||
|
||||
case SyntaxKind.CatchClause:
|
||||
return spanInNode(lastOrUndefined((<Block>node.parent).statements));
|
||||
@@ -616,7 +616,7 @@ namespace ts.BreakpointResolver {
|
||||
default:
|
||||
if (isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent)) {
|
||||
// Breakpoint in last binding element or binding pattern if it contains no elements
|
||||
let objectLiteral = <ObjectLiteralExpression>node.parent;
|
||||
const objectLiteral = <ObjectLiteralExpression>node.parent;
|
||||
return textSpan(lastOrUndefined(objectLiteral.properties) || objectLiteral);
|
||||
}
|
||||
return spanInNode(node.parent);
|
||||
@@ -633,7 +633,7 @@ namespace ts.BreakpointResolver {
|
||||
default:
|
||||
if (isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent)) {
|
||||
// Breakpoint in last binding element or binding pattern if it contains no elements
|
||||
let arrayLiteral = <ArrayLiteralExpression>node.parent;
|
||||
const arrayLiteral = <ArrayLiteralExpression>node.parent;
|
||||
return textSpan(lastOrUndefined(arrayLiteral.elements) || arrayLiteral);
|
||||
}
|
||||
|
||||
@@ -686,7 +686,7 @@ namespace ts.BreakpointResolver {
|
||||
function spanInColonToken(node: Node): TextSpan {
|
||||
// Is this : specifying return annotation of the function declaration
|
||||
if (isFunctionLike(node.parent) ||
|
||||
node.parent.kind === SyntaxKind.PropertyAssignment ||
|
||||
node.parent.kind === SyntaxKind.PropertyAssignment ||
|
||||
node.parent.kind === SyntaxKind.Parameter) {
|
||||
return spanInPreviousNode(node);
|
||||
}
|
||||
@@ -714,7 +714,7 @@ namespace ts.BreakpointResolver {
|
||||
|
||||
function spanInOfKeyword(node: Node): TextSpan {
|
||||
if (node.parent.kind === SyntaxKind.ForOfStatement) {
|
||||
// set using next token
|
||||
// Set using next token
|
||||
return spanInNextNode(node);
|
||||
}
|
||||
|
||||
@@ -722,5 +722,5 @@ namespace ts.BreakpointResolver {
|
||||
return spanInNode(node.parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,14 +20,14 @@ namespace ts.formatting {
|
||||
Unknown = -1
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Indentation for the scope that can be dynamically recomputed.
|
||||
* i.e
|
||||
* i.e
|
||||
* while(true)
|
||||
* { let 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
|
||||
* Normally indentation is applied only to the first token in line so at glance 'let' should not be touched.
|
||||
* However if some format rule adds new line between '}' and 'let' 'let' will become
|
||||
* the first token in line so it should be indented
|
||||
*/
|
||||
interface DynamicIndentation {
|
||||
@@ -48,15 +48,15 @@ namespace ts.formatting {
|
||||
* foo(bar({
|
||||
* $
|
||||
* }))
|
||||
* Both 'foo', 'bar' introduce new indentation with delta = 4, but total indentation in $ is not 8.
|
||||
* 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(child: TextRangeWithKind): number;
|
||||
/**
|
||||
* Formatter calls this function when rule adds or deletes new lines from the text
|
||||
* 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;
|
||||
@@ -64,11 +64,11 @@ namespace ts.formatting {
|
||||
|
||||
interface Indentation {
|
||||
indentation: number;
|
||||
delta: number
|
||||
delta: number;
|
||||
}
|
||||
|
||||
export function formatOnEnter(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||
let line = sourceFile.getLineAndCharacterOfPosition(position).line;
|
||||
const line = sourceFile.getLineAndCharacterOfPosition(position).line;
|
||||
if (line === 0) {
|
||||
return [];
|
||||
}
|
||||
@@ -81,12 +81,18 @@ namespace ts.formatting {
|
||||
while (isWhiteSpace(sourceFile.text.charCodeAt(endOfFormatSpan)) && !isLineBreak(sourceFile.text.charCodeAt(endOfFormatSpan))) {
|
||||
endOfFormatSpan--;
|
||||
}
|
||||
let span = {
|
||||
// if the character at the end of the span is a line break, we shouldn't include it, because it indicates we don't want to
|
||||
// touch the current line at all. Also, on some OSes the line break consists of two characters (\r\n), we should test if the
|
||||
// previous character before the end of format span is line break character as well.
|
||||
if (isLineBreak(sourceFile.text.charCodeAt(endOfFormatSpan))) {
|
||||
endOfFormatSpan--;
|
||||
}
|
||||
const span = {
|
||||
// get start position for the previous line
|
||||
pos: getStartPositionOfLine(line - 1, sourceFile),
|
||||
// end value is exclusive so add 1 to the result
|
||||
end: endOfFormatSpan + 1
|
||||
}
|
||||
};
|
||||
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnEnter);
|
||||
}
|
||||
|
||||
@@ -99,7 +105,7 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
export function formatDocument(sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||
let span = {
|
||||
const span = {
|
||||
pos: 0,
|
||||
end: sourceFile.text.length
|
||||
};
|
||||
@@ -108,7 +114,7 @@ namespace ts.formatting {
|
||||
|
||||
export function formatSelection(start: number, end: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||
// format from the beginning of the line
|
||||
let span = {
|
||||
const span = {
|
||||
pos: getLineStartPositionForPosition(start, sourceFile),
|
||||
end: end
|
||||
};
|
||||
@@ -116,11 +122,11 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
function formatOutermostParent(position: number, expectedLastToken: SyntaxKind, sourceFile: SourceFile, options: FormatCodeOptions, rulesProvider: RulesProvider, requestKind: FormattingRequestKind): TextChange[] {
|
||||
let parent = findOutermostParent(position, expectedLastToken, sourceFile);
|
||||
const parent = findOutermostParent(position, expectedLastToken, sourceFile);
|
||||
if (!parent) {
|
||||
return [];
|
||||
}
|
||||
let span = {
|
||||
const span = {
|
||||
pos: getLineStartPositionForPosition(parent.getStart(sourceFile), sourceFile),
|
||||
end: parent.end
|
||||
};
|
||||
@@ -128,11 +134,11 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
function findOutermostParent(position: number, expectedTokenKind: SyntaxKind, sourceFile: SourceFile): Node {
|
||||
let precedingToken = findPrecedingToken(position, sourceFile);
|
||||
const precedingToken = findPrecedingToken(position, sourceFile);
|
||||
|
||||
// when it is claimed that trigger character was typed at given position
|
||||
// when it is claimed that trigger character was typed at given position
|
||||
// we verify that there is a token with a matching kind whose end is equal to position (because the character was just typed).
|
||||
// If this condition is not hold - then trigger character was typed in some other context,
|
||||
// If this condition is not hold - then trigger character was typed in some other context,
|
||||
// i.e.in comment and thus should not trigger autoformatting
|
||||
if (!precedingToken ||
|
||||
precedingToken.kind !== expectedTokenKind ||
|
||||
@@ -142,12 +148,12 @@ namespace ts.formatting {
|
||||
|
||||
// walk up and search for the parent node that ends at the same position with precedingToken.
|
||||
// for cases like this
|
||||
//
|
||||
//
|
||||
// let 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 -
|
||||
// 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
|
||||
let current = precedingToken;
|
||||
while (current &&
|
||||
@@ -168,7 +174,7 @@ namespace ts.formatting {
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
return rangeContainsRange((<InterfaceDeclaration>parent).members, node);
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
let body = (<ModuleDeclaration>parent).body;
|
||||
const body = (<ModuleDeclaration>parent).body;
|
||||
return body && body.kind === SyntaxKind.Block && rangeContainsRange((<Block>body).statements, node);
|
||||
case SyntaxKind.SourceFile:
|
||||
case SyntaxKind.Block:
|
||||
@@ -186,9 +192,9 @@ namespace ts.formatting {
|
||||
return find(sourceFile);
|
||||
|
||||
function find(n: Node): Node {
|
||||
let candidate = forEachChild(n, c => startEndContainsRange(c.getStart(sourceFile), c.end, range) && c);
|
||||
const candidate = forEachChild(n, c => startEndContainsRange(c.getStart(sourceFile), c.end, range) && c);
|
||||
if (candidate) {
|
||||
let result = find(candidate);
|
||||
const result = find(candidate);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
@@ -208,7 +214,7 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
// pick only errors that fall in range
|
||||
let sorted = errors
|
||||
const sorted = errors
|
||||
.filter(d => rangeOverlapsWithStartEnd(originalRange, d.start, d.start + d.length))
|
||||
.sort((e1, e2) => e1.start - e2.start);
|
||||
|
||||
@@ -223,11 +229,11 @@ namespace ts.formatting {
|
||||
// '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
|
||||
// all errors in the range were already checked -> no error in specified range
|
||||
return false;
|
||||
}
|
||||
|
||||
let error = sorted[index];
|
||||
const error = sorted[index];
|
||||
if (r.end <= error.start) {
|
||||
// specified range ends before the error refered by 'index' - no error in range
|
||||
return false;
|
||||
@@ -249,16 +255,16 @@ namespace ts.formatting {
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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 {
|
||||
let start = enclosingNode.getStart(sourceFile);
|
||||
const start = enclosingNode.getStart(sourceFile);
|
||||
if (start === originalRange.pos && enclosingNode.end === originalRange.end) {
|
||||
return start;
|
||||
}
|
||||
|
||||
let precedingToken = findPrecedingToken(originalRange.pos, sourceFile);
|
||||
const precedingToken = findPrecedingToken(originalRange.pos, sourceFile);
|
||||
if (!precedingToken) {
|
||||
// no preceding token found - start from the beginning of enclosing node
|
||||
return enclosingNode.pos;
|
||||
@@ -274,7 +280,7 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
/*
|
||||
* For cases like
|
||||
* For cases like
|
||||
* if (a ||
|
||||
* b ||$
|
||||
* c) {...}
|
||||
@@ -284,15 +290,15 @@ namespace ts.formatting {
|
||||
* Initial indentation for this node will be 0.
|
||||
* Binary expressions don't introduce new indentation scopes, however it is possible
|
||||
* that some parent node on the same line does - like if statement in this case.
|
||||
* Note that we are considering parents only from the same line with initial node -
|
||||
* if parent is on the different line - its delta was already contributed
|
||||
* Note that we are considering parents only from the same line with initial node -
|
||||
* if parent is on the different line - its delta was already contributed
|
||||
* to the initial indentation.
|
||||
*/
|
||||
function getOwnOrInheritedDelta(n: Node, options: FormatCodeOptions, sourceFile: SourceFile): number {
|
||||
let previousLine = Constants.Unknown;
|
||||
let child: Node;
|
||||
while (n) {
|
||||
let line = sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile)).line;
|
||||
const line = sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile)).line;
|
||||
if (previousLine !== Constants.Unknown && line !== previousLine) {
|
||||
break;
|
||||
}
|
||||
@@ -314,17 +320,17 @@ namespace ts.formatting {
|
||||
rulesProvider: RulesProvider,
|
||||
requestKind: FormattingRequestKind): TextChange[] {
|
||||
|
||||
let rangeContainsError = prepareRangeContainsErrorFunction(sourceFile.parseDiagnostics, originalRange);
|
||||
const rangeContainsError = prepareRangeContainsErrorFunction(sourceFile.parseDiagnostics, originalRange);
|
||||
|
||||
// formatting context is used by rules provider
|
||||
let formattingContext = new FormattingContext(sourceFile, requestKind);
|
||||
const formattingContext = new FormattingContext(sourceFile, requestKind);
|
||||
|
||||
// find the smallest node that fully wraps the range and compute the initial indentation for the node
|
||||
let enclosingNode = findEnclosingNode(originalRange, sourceFile);
|
||||
const enclosingNode = findEnclosingNode(originalRange, sourceFile);
|
||||
|
||||
let formattingScanner = getFormattingScanner(sourceFile, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end);
|
||||
const formattingScanner = getFormattingScanner(sourceFile, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end);
|
||||
|
||||
let initialIndentation = SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, options);
|
||||
const initialIndentation = SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, options);
|
||||
|
||||
let previousRangeHasError: boolean;
|
||||
let previousRange: TextRangeWithKind;
|
||||
@@ -334,23 +340,23 @@ namespace ts.formatting {
|
||||
let lastIndentedLine: number;
|
||||
let indentationOnLastIndentedLine: number;
|
||||
|
||||
let edits: TextChange[] = [];
|
||||
const edits: TextChange[] = [];
|
||||
|
||||
formattingScanner.advance();
|
||||
|
||||
if (formattingScanner.isOnToken()) {
|
||||
let startLine = sourceFile.getLineAndCharacterOfPosition(enclosingNode.getStart(sourceFile)).line;
|
||||
const startLine = sourceFile.getLineAndCharacterOfPosition(enclosingNode.getStart(sourceFile)).line;
|
||||
let undecoratedStartLine = startLine;
|
||||
if (enclosingNode.decorators) {
|
||||
undecoratedStartLine = sourceFile.getLineAndCharacterOfPosition(getNonDecoratorTokenPosOfNode(enclosingNode, sourceFile)).line;
|
||||
}
|
||||
|
||||
let delta = getOwnOrInheritedDelta(enclosingNode, options, sourceFile);
|
||||
const delta = getOwnOrInheritedDelta(enclosingNode, options, sourceFile);
|
||||
processNode(enclosingNode, enclosingNode, startLine, undecoratedStartLine, initialIndentation, delta);
|
||||
}
|
||||
|
||||
if (!formattingScanner.isOnToken()) {
|
||||
let leadingTrivia = formattingScanner.getCurrentLeadingTrivia();
|
||||
const leadingTrivia = formattingScanner.getCurrentLeadingTrivia();
|
||||
if (leadingTrivia) {
|
||||
processTrivia(leadingTrivia, enclosingNode, enclosingNode, undefined);
|
||||
trimTrailingWhitespacesForRemainingRange();
|
||||
@@ -364,10 +370,10 @@ namespace ts.formatting {
|
||||
// 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
|
||||
* 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
|
||||
* If list element is in the range - its indentation will be equal
|
||||
* to inherited indentation from its predecessors.
|
||||
*/
|
||||
function tryComputeIndentationForListItem(startPos: number,
|
||||
@@ -378,17 +384,20 @@ namespace ts.formatting {
|
||||
|
||||
if (rangeOverlapsWithStartEnd(range, startPos, endPos) ||
|
||||
rangeContainsStartEnd(range, startPos, endPos) /* Not to miss zero-range nodes e.g. JsxText */) {
|
||||
|
||||
|
||||
if (inheritedIndentation !== Constants.Unknown) {
|
||||
return inheritedIndentation;
|
||||
}
|
||||
}
|
||||
else {
|
||||
let startLine = sourceFile.getLineAndCharacterOfPosition(startPos).line;
|
||||
let startLinePosition = getLineStartPositionForPosition(startPos, sourceFile);
|
||||
let column = SmartIndenter.findFirstNonWhitespaceColumn(startLinePosition, startPos, sourceFile, options);
|
||||
const startLine = sourceFile.getLineAndCharacterOfPosition(startPos).line;
|
||||
const startLinePosition = getLineStartPositionForPosition(startPos, sourceFile);
|
||||
const column = SmartIndenter.findFirstNonWhitespaceColumn(startLinePosition, startPos, sourceFile, options);
|
||||
if (startLine !== parentStartLine || startPos === column) {
|
||||
return column
|
||||
// Use the base indent size if it is greater than
|
||||
// the indentation of the inherited predecessor.
|
||||
const baseIndentSize = SmartIndenter.getBaseIndentation(options);
|
||||
return baseIndentSize > column ? baseIndentSize : column;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,7 +413,7 @@ namespace ts.formatting {
|
||||
effectiveParentStartLine: number): Indentation {
|
||||
|
||||
let indentation = inheritedIndentation;
|
||||
var delta = SmartIndenter.shouldIndentChildNode(node) ? options.IndentSize : 0;
|
||||
let delta = SmartIndenter.shouldIndentChildNode(node) ? options.IndentSize : 0;
|
||||
|
||||
if (effectiveParentStartLine === startLine) {
|
||||
// if node is located on the same line with the parent
|
||||
@@ -427,7 +436,7 @@ namespace ts.formatting {
|
||||
return {
|
||||
indentation,
|
||||
delta
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getFirstNonDecoratorTokenOfNode(node: Node) {
|
||||
@@ -511,7 +520,7 @@ namespace ts.formatting {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function getEffectiveDelta(delta: number, child: TextRangeWithKind) {
|
||||
// Delta value should be zero when the node explicitly prevents indentation of the child node
|
||||
@@ -524,17 +533,17 @@ namespace ts.formatting {
|
||||
return;
|
||||
}
|
||||
|
||||
let nodeDynamicIndentation = getDynamicIndentation(node, nodeStartLine, indentation, delta);
|
||||
const 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'
|
||||
// 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
|
||||
|
||||
@@ -545,7 +554,7 @@ namespace ts.formatting {
|
||||
forEachChild(
|
||||
node,
|
||||
child => {
|
||||
processChildNode(child, /*inheritedIndentation*/ Constants.Unknown, node, nodeDynamicIndentation, nodeStartLine, undecoratedNodeStartLine, /*isListElement*/ false)
|
||||
processChildNode(child, /*inheritedIndentation*/ Constants.Unknown, node, nodeDynamicIndentation, nodeStartLine, undecoratedNodeStartLine, /*isListItem*/ false);
|
||||
},
|
||||
(nodes: NodeArray<Node>) => {
|
||||
processChildNodes(nodes, node, nodeStartLine, nodeDynamicIndentation);
|
||||
@@ -553,7 +562,7 @@ namespace ts.formatting {
|
||||
|
||||
// proceed any tokens in the node that are located after child nodes
|
||||
while (formattingScanner.isOnToken()) {
|
||||
let tokenInfo = formattingScanner.readTokenInfo(node);
|
||||
const tokenInfo = formattingScanner.readTokenInfo(node);
|
||||
if (tokenInfo.token.end > node.end) {
|
||||
break;
|
||||
}
|
||||
@@ -567,11 +576,12 @@ namespace ts.formatting {
|
||||
parentDynamicIndentation: DynamicIndentation,
|
||||
parentStartLine: number,
|
||||
undecoratedParentStartLine: number,
|
||||
isListItem: boolean): number {
|
||||
isListItem: boolean,
|
||||
isFirstListItem?: boolean): number {
|
||||
|
||||
let childStartPos = child.getStart(sourceFile);
|
||||
const childStartPos = child.getStart(sourceFile);
|
||||
|
||||
let childStartLine = sourceFile.getLineAndCharacterOfPosition(childStartPos).line;
|
||||
const childStartLine = sourceFile.getLineAndCharacterOfPosition(childStartPos).line;
|
||||
|
||||
let undecoratedChildStartLine = childStartLine;
|
||||
if (child.decorators) {
|
||||
@@ -598,7 +608,7 @@ namespace ts.formatting {
|
||||
|
||||
while (formattingScanner.isOnToken()) {
|
||||
// proceed any parent tokens that are located prior to child.getStart()
|
||||
let tokenInfo = formattingScanner.readTokenInfo(node);
|
||||
const tokenInfo = formattingScanner.readTokenInfo(node);
|
||||
if (tokenInfo.token.end > childStartPos) {
|
||||
// stop when formatting scanner advances past the beginning of the child
|
||||
break;
|
||||
@@ -613,19 +623,23 @@ namespace ts.formatting {
|
||||
|
||||
if (isToken(child)) {
|
||||
// if child node is a token, it does not impact indentation, proceed it using parent indentation scope rules
|
||||
let tokenInfo = formattingScanner.readTokenInfo(child);
|
||||
const tokenInfo = formattingScanner.readTokenInfo(child);
|
||||
Debug.assert(tokenInfo.token.end === child.end);
|
||||
consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation, child);
|
||||
return inheritedIndentation;
|
||||
}
|
||||
|
||||
let effectiveParentStartLine = child.kind === SyntaxKind.Decorator ? childStartLine : undecoratedParentStartLine;
|
||||
let childIndentation = computeIndentation(child, childStartLine, childIndentationAmount, node, parentDynamicIndentation, effectiveParentStartLine);
|
||||
const effectiveParentStartLine = child.kind === SyntaxKind.Decorator ? childStartLine : undecoratedParentStartLine;
|
||||
const childIndentation = computeIndentation(child, childStartLine, childIndentationAmount, node, parentDynamicIndentation, effectiveParentStartLine);
|
||||
|
||||
processNode(child, childContextNode, childStartLine, undecoratedChildStartLine, childIndentation.indentation, childIndentation.delta);
|
||||
|
||||
childContextNode = node;
|
||||
|
||||
if (isFirstListItem && parent.kind === SyntaxKind.ArrayLiteralExpression && inheritedIndentation === Constants.Unknown) {
|
||||
inheritedIndentation = childIndentation.indentation;
|
||||
}
|
||||
|
||||
return inheritedIndentation;
|
||||
}
|
||||
|
||||
@@ -634,8 +648,8 @@ namespace ts.formatting {
|
||||
parentStartLine: number,
|
||||
parentDynamicIndentation: DynamicIndentation): void {
|
||||
|
||||
let listStartToken = getOpenTokenForList(parent, nodes);
|
||||
let listEndToken = getCloseTokenForOpenToken(listStartToken);
|
||||
const listStartToken = getOpenTokenForList(parent, nodes);
|
||||
const listEndToken = getCloseTokenForOpenToken(listStartToken);
|
||||
|
||||
let listDynamicIndentation = parentDynamicIndentation;
|
||||
let startLine = parentStartLine;
|
||||
@@ -643,7 +657,7 @@ namespace ts.formatting {
|
||||
if (listStartToken !== SyntaxKind.Unknown) {
|
||||
// introduce a new indentation scope for lists (including list start and end tokens)
|
||||
while (formattingScanner.isOnToken()) {
|
||||
let tokenInfo = formattingScanner.readTokenInfo(parent);
|
||||
const tokenInfo = formattingScanner.readTokenInfo(parent);
|
||||
if (tokenInfo.token.end > nodes.pos) {
|
||||
// stop when formatting scanner moves past the beginning of node list
|
||||
break;
|
||||
@@ -651,7 +665,7 @@ namespace ts.formatting {
|
||||
else if (tokenInfo.token.kind === listStartToken) {
|
||||
// consume list start token
|
||||
startLine = sourceFile.getLineAndCharacterOfPosition(tokenInfo.token.pos).line;
|
||||
let indentation =
|
||||
const indentation =
|
||||
computeIndentation(tokenInfo.token, startLine, Constants.Unknown, parent, parentDynamicIndentation, parentStartLine);
|
||||
|
||||
listDynamicIndentation = getDynamicIndentation(parent, parentStartLine, indentation.indentation, indentation.delta);
|
||||
@@ -665,16 +679,17 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
let inheritedIndentation = Constants.Unknown;
|
||||
for (let child of nodes) {
|
||||
inheritedIndentation = processChildNode(child, inheritedIndentation, node, listDynamicIndentation, startLine, startLine, /*isListElement*/ true)
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const child = nodes[i];
|
||||
inheritedIndentation = processChildNode(child, inheritedIndentation, node, listDynamicIndentation, startLine, startLine, /*isListItem*/ true, /*isFirstListItem*/ i === 0);
|
||||
}
|
||||
|
||||
if (listEndToken !== SyntaxKind.Unknown) {
|
||||
if (formattingScanner.isOnToken()) {
|
||||
let tokenInfo = formattingScanner.readTokenInfo(parent);
|
||||
const tokenInfo = formattingScanner.readTokenInfo(parent);
|
||||
// consume the list end token only if it is still belong to the parent
|
||||
// there might be the case when current token matches end token but does not considered as one
|
||||
// function (x: function) <--
|
||||
// function (x: function) <--
|
||||
// without this check close paren will be interpreted as list end token for function expression which is wrong
|
||||
if (tokenInfo.token.kind === listEndToken && rangeContainsRange(parent, tokenInfo.token)) {
|
||||
// consume list end token
|
||||
@@ -687,7 +702,7 @@ namespace ts.formatting {
|
||||
function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation, container?: Node): void {
|
||||
Debug.assert(rangeContainsRange(parent, currentTokenInfo.token));
|
||||
|
||||
let lastTriviaWasNewLine = formattingScanner.lastTrailingTriviaWasNewLine();
|
||||
const lastTriviaWasNewLine = formattingScanner.lastTrailingTriviaWasNewLine();
|
||||
let indentToken = false;
|
||||
|
||||
if (currentTokenInfo.leadingTrivia) {
|
||||
@@ -695,13 +710,13 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
let lineAdded: boolean;
|
||||
let isTokenInRange = rangeContainsRange(originalRange, currentTokenInfo.token);
|
||||
const isTokenInRange = rangeContainsRange(originalRange, currentTokenInfo.token);
|
||||
|
||||
let tokenStart = sourceFile.getLineAndCharacterOfPosition(currentTokenInfo.token.pos);
|
||||
const tokenStart = sourceFile.getLineAndCharacterOfPosition(currentTokenInfo.token.pos);
|
||||
if (isTokenInRange) {
|
||||
let rangeHasError = rangeContainsError(currentTokenInfo.token);
|
||||
const rangeHasError = rangeContainsError(currentTokenInfo.token);
|
||||
// save previousRange since processRange will overwrite this value with current one
|
||||
let savePreviousRange = previousRange;
|
||||
const savePreviousRange = previousRange;
|
||||
lineAdded = processRange(currentTokenInfo.token, tokenStart, parent, childContextNode, dynamicIndentation);
|
||||
if (rangeHasError) {
|
||||
// do not indent comments\token if token range overlaps with some error
|
||||
@@ -724,29 +739,28 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
if (indentToken) {
|
||||
let tokenIndentation = (isTokenInRange && !rangeContainsError(currentTokenInfo.token)) ?
|
||||
const tokenIndentation = (isTokenInRange && !rangeContainsError(currentTokenInfo.token)) ?
|
||||
dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind, container) :
|
||||
Constants.Unknown;
|
||||
|
||||
let indentNextTokenOrTrivia = true;
|
||||
if (currentTokenInfo.leadingTrivia) {
|
||||
let commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind, tokenIndentation, container);
|
||||
let indentNextTokenOrTrivia = true;
|
||||
|
||||
for (let triviaItem of currentTokenInfo.leadingTrivia) {
|
||||
if (!rangeContainsRange(originalRange, triviaItem)) {
|
||||
continue;
|
||||
}
|
||||
const commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind, tokenIndentation, container);
|
||||
|
||||
for (const triviaItem of currentTokenInfo.leadingTrivia) {
|
||||
const triviaInRange = rangeContainsRange(originalRange, triviaItem);
|
||||
switch (triviaItem.kind) {
|
||||
case SyntaxKind.MultiLineCommentTrivia:
|
||||
indentMultilineComment(triviaItem, commentIndentation, /*firstLineIsIndented*/ !indentNextTokenOrTrivia);
|
||||
if (triviaInRange) {
|
||||
indentMultilineComment(triviaItem, commentIndentation, /*firstLineIsIndented*/ !indentNextTokenOrTrivia);
|
||||
}
|
||||
indentNextTokenOrTrivia = false;
|
||||
break;
|
||||
case SyntaxKind.SingleLineCommentTrivia:
|
||||
if (indentNextTokenOrTrivia) {
|
||||
if (indentNextTokenOrTrivia && triviaInRange) {
|
||||
insertIndentation(triviaItem.pos, commentIndentation, /*lineAdded*/ false);
|
||||
indentNextTokenOrTrivia = false;
|
||||
}
|
||||
indentNextTokenOrTrivia = false;
|
||||
break;
|
||||
case SyntaxKind.NewLineTrivia:
|
||||
indentNextTokenOrTrivia = true;
|
||||
@@ -756,7 +770,7 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
// indent token only if is it is in target range and does not overlap with any error ranges
|
||||
if (tokenIndentation !== Constants.Unknown) {
|
||||
if (tokenIndentation !== Constants.Unknown && indentNextTokenOrTrivia) {
|
||||
insertIndentation(currentTokenInfo.token.pos, tokenIndentation, lineAdded);
|
||||
|
||||
lastIndentedLine = tokenStart.line;
|
||||
@@ -771,9 +785,9 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
function processTrivia(trivia: TextRangeWithKind[], parent: Node, contextNode: Node, dynamicIndentation: DynamicIndentation): void {
|
||||
for (let triviaItem of trivia) {
|
||||
for (const triviaItem of trivia) {
|
||||
if (isComment(triviaItem.kind) && rangeContainsRange(originalRange, triviaItem)) {
|
||||
let triviaItemStart = sourceFile.getLineAndCharacterOfPosition(triviaItem.pos);
|
||||
const triviaItemStart = sourceFile.getLineAndCharacterOfPosition(triviaItem.pos);
|
||||
processRange(triviaItem, triviaItemStart, parent, contextNode, dynamicIndentation);
|
||||
}
|
||||
}
|
||||
@@ -785,17 +799,17 @@ namespace ts.formatting {
|
||||
contextNode: Node,
|
||||
dynamicIndentation: DynamicIndentation): boolean {
|
||||
|
||||
let rangeHasError = rangeContainsError(range);
|
||||
const rangeHasError = rangeContainsError(range);
|
||||
let lineAdded: boolean;
|
||||
if (!rangeHasError && !previousRangeHasError) {
|
||||
if (!previousRange) {
|
||||
// trim whitespaces starting from the beginning of the span up to the current line
|
||||
let originalStart = sourceFile.getLineAndCharacterOfPosition(originalRange.pos);
|
||||
const originalStart = sourceFile.getLineAndCharacterOfPosition(originalRange.pos);
|
||||
trimTrailingWhitespacesForLines(originalStart.line, rangeStart.line);
|
||||
}
|
||||
else {
|
||||
lineAdded =
|
||||
processPair(range, rangeStart.line, parent, previousRange, previousRangeStartLine, previousParent, contextNode, dynamicIndentation)
|
||||
processPair(range, rangeStart.line, parent, previousRange, previousRangeStartLine, previousParent, contextNode, dynamicIndentation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -818,7 +832,7 @@ namespace ts.formatting {
|
||||
|
||||
formattingContext.updateContext(previousItem, previousParent, currentItem, currentParent, contextNode);
|
||||
|
||||
let rule = rulesProvider.getRulesMap().GetRule(formattingContext);
|
||||
const rule = rulesProvider.getRulesMap().GetRule(formattingContext);
|
||||
|
||||
let trimTrailingWhitespaces: boolean;
|
||||
let lineAdded: boolean;
|
||||
@@ -827,19 +841,19 @@ namespace ts.formatting {
|
||||
|
||||
if (rule.Operation.Action & (RuleAction.Space | RuleAction.Delete) && currentStartLine !== previousStartLine) {
|
||||
lineAdded = false;
|
||||
// Handle the case where the next line is moved to be the end of this line.
|
||||
// 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) {
|
||||
dynamicIndentation.recomputeIndentation(/*lineAdded*/ false);
|
||||
dynamicIndentation.recomputeIndentation(/*lineAddedByFormatting*/ false);
|
||||
}
|
||||
}
|
||||
else if (rule.Operation.Action & RuleAction.NewLine && currentStartLine === previousStartLine) {
|
||||
lineAdded = true;
|
||||
// Handle the case where token2 is moved to the new line.
|
||||
// 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) {
|
||||
dynamicIndentation.recomputeIndentation(/*lineAdded*/ true);
|
||||
dynamicIndentation.recomputeIndentation(/*lineAddedByFormatting*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -859,25 +873,29 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
function insertIndentation(pos: number, indentation: number, lineAdded: boolean): void {
|
||||
let indentationString = getIndentationString(indentation, options);
|
||||
const 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 {
|
||||
let tokenStart = sourceFile.getLineAndCharacterOfPosition(pos);
|
||||
if (indentation !== tokenStart.character) {
|
||||
let startLinePosition = getStartPositionOfLine(tokenStart.line, sourceFile);
|
||||
const tokenStart = sourceFile.getLineAndCharacterOfPosition(pos);
|
||||
const startLinePosition = getStartPositionOfLine(tokenStart.line, sourceFile);
|
||||
if (indentation !== tokenStart.character || indentationIsDifferent(indentationString, startLinePosition)) {
|
||||
recordReplace(startLinePosition, tokenStart.character, indentationString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function indentationIsDifferent(indentationString: string, startLinePosition: number): boolean {
|
||||
return indentationString !== sourceFile.text.substr(startLinePosition , indentationString.length);
|
||||
}
|
||||
|
||||
function indentMultilineComment(commentRange: TextRange, indentation: number, firstLineIsIndented: boolean) {
|
||||
// split comment in lines
|
||||
let startLine = sourceFile.getLineAndCharacterOfPosition(commentRange.pos).line;
|
||||
let endLine = sourceFile.getLineAndCharacterOfPosition(commentRange.end).line;
|
||||
const endLine = sourceFile.getLineAndCharacterOfPosition(commentRange.end).line;
|
||||
let parts: TextRange[];
|
||||
if (startLine === endLine) {
|
||||
if (!firstLineIsIndented) {
|
||||
@@ -889,8 +907,8 @@ namespace ts.formatting {
|
||||
else {
|
||||
parts = [];
|
||||
let startPos = commentRange.pos;
|
||||
for (let line = startLine; line < endLine; ++line) {
|
||||
let endOfLine = getEndLinePosition(line, sourceFile);
|
||||
for (let line = startLine; line < endLine; line++) {
|
||||
const endOfLine = getEndLinePosition(line, sourceFile);
|
||||
parts.push({ pos: startPos, end: endOfLine });
|
||||
startPos = getStartPositionOfLine(line + 1, sourceFile);
|
||||
}
|
||||
@@ -898,9 +916,9 @@ namespace ts.formatting {
|
||||
parts.push({ pos: startPos, end: commentRange.end });
|
||||
}
|
||||
|
||||
let startLinePos = getStartPositionOfLine(startLine, sourceFile);
|
||||
const startLinePos = getStartPositionOfLine(startLine, sourceFile);
|
||||
|
||||
let nonWhitespaceColumnInFirstPart =
|
||||
const nonWhitespaceColumnInFirstPart =
|
||||
SmartIndenter.findFirstNonWhitespaceCharacterAndColumn(startLinePos, parts[0].pos, sourceFile, options);
|
||||
|
||||
if (indentation === nonWhitespaceColumnInFirstPart.column) {
|
||||
@@ -914,17 +932,17 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
// shift all parts on the delta size
|
||||
let delta = indentation - nonWhitespaceColumnInFirstPart.column;
|
||||
for (let i = startIndex, len = parts.length; i < len; ++i, ++startLine) {
|
||||
let startLinePos = getStartPositionOfLine(startLine, sourceFile);
|
||||
let nonWhitespaceCharacterAndColumn =
|
||||
const delta = indentation - nonWhitespaceColumnInFirstPart.column;
|
||||
for (let i = startIndex, len = parts.length; i < len; i++, startLine++) {
|
||||
const startLinePos = getStartPositionOfLine(startLine, sourceFile);
|
||||
const nonWhitespaceCharacterAndColumn =
|
||||
i === 0
|
||||
? nonWhitespaceColumnInFirstPart
|
||||
: SmartIndenter.findFirstNonWhitespaceCharacterAndColumn(parts[i].pos, parts[i].end, sourceFile, options);
|
||||
|
||||
let newIndentation = nonWhitespaceCharacterAndColumn.column + delta;
|
||||
const newIndentation = nonWhitespaceCharacterAndColumn.column + delta;
|
||||
if (newIndentation > 0) {
|
||||
let indentationString = getIndentationString(newIndentation, options);
|
||||
const indentationString = getIndentationString(newIndentation, options);
|
||||
recordReplace(startLinePos, nonWhitespaceCharacterAndColumn.character, indentationString);
|
||||
}
|
||||
else {
|
||||
@@ -934,16 +952,16 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
function trimTrailingWhitespacesForLines(line1: number, line2: number, range?: TextRangeWithKind) {
|
||||
for (let line = line1; line < line2; ++line) {
|
||||
let lineStartPosition = getStartPositionOfLine(line, sourceFile);
|
||||
let lineEndPosition = getEndLinePosition(line, sourceFile);
|
||||
for (let line = line1; line < line2; line++) {
|
||||
const lineStartPosition = getStartPositionOfLine(line, sourceFile);
|
||||
const lineEndPosition = getEndLinePosition(line, sourceFile);
|
||||
|
||||
// do not trim whitespaces in comments or template expression
|
||||
if (range && (isComment(range.kind) || isStringOrRegularExpressionOrTemplateLiteral(range.kind)) && range.pos <= lineEndPosition && range.end > lineEndPosition) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let whitespaceStart = getTrailingWhitespaceStartPosition(lineStartPosition, lineEndPosition);
|
||||
const whitespaceStart = getTrailingWhitespaceStartPosition(lineStartPosition, lineEndPosition);
|
||||
if (whitespaceStart !== -1) {
|
||||
Debug.assert(whitespaceStart === lineStartPosition || !isWhiteSpace(sourceFile.text.charCodeAt(whitespaceStart - 1)));
|
||||
recordDelete(whitespaceStart, lineEndPosition + 1 - whitespaceStart);
|
||||
@@ -970,16 +988,16 @@ namespace ts.formatting {
|
||||
* Trimming will be done for lines after the previous range
|
||||
*/
|
||||
function trimTrailingWhitespacesForRemainingRange() {
|
||||
let startPosition = previousRange ? previousRange.end : originalRange.pos;
|
||||
const startPosition = previousRange ? previousRange.end : originalRange.pos;
|
||||
|
||||
let startLine = sourceFile.getLineAndCharacterOfPosition(startPosition).line;
|
||||
let endLine = sourceFile.getLineAndCharacterOfPosition(originalRange.end).line;
|
||||
const startLine = sourceFile.getLineAndCharacterOfPosition(startPosition).line;
|
||||
const endLine = sourceFile.getLineAndCharacterOfPosition(originalRange.end).line;
|
||||
|
||||
trimTrailingWhitespacesForLines(startLine, endLine + 1, previousRange);
|
||||
}
|
||||
|
||||
function newTextChange(start: number, len: number, newText: string): TextChange {
|
||||
return { span: createTextSpan(start, len), newText }
|
||||
return { span: createTextSpan(start, len), newText };
|
||||
}
|
||||
|
||||
function recordDelete(start: number, len: number) {
|
||||
@@ -1000,7 +1018,6 @@ namespace ts.formatting {
|
||||
currentRange: TextRangeWithKind,
|
||||
currentStartLine: number): void {
|
||||
|
||||
let between: TextRange;
|
||||
switch (rule.Operation.Action) {
|
||||
case RuleAction.Ignore:
|
||||
// no action required
|
||||
@@ -1020,7 +1037,7 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
// edit should not be applied only if we have one line feed between elements
|
||||
let lineDelta = currentStartLine - previousStartLine;
|
||||
const lineDelta = currentStartLine - previousStartLine;
|
||||
if (lineDelta !== 1) {
|
||||
recordReplace(previousRange.end, currentRange.pos - previousRange.end, options.NewLineCharacter);
|
||||
}
|
||||
@@ -1031,7 +1048,7 @@ namespace ts.formatting {
|
||||
return;
|
||||
}
|
||||
|
||||
let posDelta = currentRange.pos - previousRange.end;
|
||||
const posDelta = currentRange.pos - previousRange.end;
|
||||
if (posDelta !== 1 || sourceFile.text.charCodeAt(previousRange.end) !== CharacterCodes.space) {
|
||||
recordReplace(previousRange.end, currentRange.pos - previousRange.end, " ");
|
||||
}
|
||||
@@ -1040,15 +1057,6 @@ namespace ts.formatting {
|
||||
}
|
||||
}
|
||||
|
||||
function isSomeBlock(kind: SyntaxKind): boolean {
|
||||
switch (kind) {
|
||||
case SyntaxKind.Block:
|
||||
case SyntaxKind.ModuleBlock:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getOpenTokenForList(node: Node, list: Node[]) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
@@ -1093,13 +1101,13 @@ namespace ts.formatting {
|
||||
return SyntaxKind.Unknown;
|
||||
}
|
||||
|
||||
var internedSizes: { tabSize: number; indentSize: number };
|
||||
var internedTabsIndentation: string[];
|
||||
var internedSpacesIndentation: string[];
|
||||
let internedSizes: { tabSize: number; indentSize: number };
|
||||
let internedTabsIndentation: string[];
|
||||
let internedSpacesIndentation: string[];
|
||||
|
||||
export function getIndentationString(indentation: number, options: FormatCodeOptions): string {
|
||||
// reset interned strings if FormatCodeOptions were changed
|
||||
let resetInternedStrings =
|
||||
const resetInternedStrings =
|
||||
!internedSizes || (internedSizes.tabSize !== options.TabSize || internedSizes.indentSize !== options.IndentSize);
|
||||
|
||||
if (resetInternedStrings) {
|
||||
@@ -1108,8 +1116,8 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
if (!options.ConvertTabsToSpaces) {
|
||||
let tabs = Math.floor(indentation / options.TabSize);
|
||||
let spaces = indentation - tabs * options.TabSize;
|
||||
const tabs = Math.floor(indentation / options.TabSize);
|
||||
const spaces = indentation - tabs * options.TabSize;
|
||||
|
||||
let tabString: string;
|
||||
if (!internedTabsIndentation) {
|
||||
@@ -1117,7 +1125,7 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
if (internedTabsIndentation[tabs] === undefined) {
|
||||
internedTabsIndentation[tabs] = tabString = repeat('\t', tabs);
|
||||
internedTabsIndentation[tabs] = tabString = repeat("\t", tabs);
|
||||
}
|
||||
else {
|
||||
tabString = internedTabsIndentation[tabs];
|
||||
@@ -1127,8 +1135,8 @@ namespace ts.formatting {
|
||||
}
|
||||
else {
|
||||
let spacesString: string;
|
||||
let quotient = Math.floor(indentation / options.IndentSize);
|
||||
let remainder = indentation % options.IndentSize;
|
||||
const quotient = Math.floor(indentation / options.IndentSize);
|
||||
const remainder = indentation % options.IndentSize;
|
||||
if (!internedSpacesIndentation) {
|
||||
internedSpacesIndentation = [];
|
||||
}
|
||||
@@ -1146,11 +1154,11 @@ namespace ts.formatting {
|
||||
|
||||
function repeat(value: string, count: number): string {
|
||||
let s = "";
|
||||
for (let i = 0; i < count; ++i) {
|
||||
for (let i = 0; i < count; i++) {
|
||||
s += value;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +57,8 @@ namespace ts.formatting {
|
||||
|
||||
public TokensAreOnSameLine(): boolean {
|
||||
if (this.tokensAreOnSameLine === undefined) {
|
||||
let startLine = this.sourceFile.getLineAndCharacterOfPosition(this.currentTokenSpan.pos).line;
|
||||
let endLine = this.sourceFile.getLineAndCharacterOfPosition(this.nextTokenSpan.pos).line;
|
||||
const startLine = this.sourceFile.getLineAndCharacterOfPosition(this.currentTokenSpan.pos).line;
|
||||
const endLine = this.sourceFile.getLineAndCharacterOfPosition(this.nextTokenSpan.pos).line;
|
||||
this.tokensAreOnSameLine = (startLine === endLine);
|
||||
}
|
||||
|
||||
@@ -82,17 +82,17 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
private NodeIsOnOneLine(node: Node): boolean {
|
||||
let startLine = this.sourceFile.getLineAndCharacterOfPosition(node.getStart(this.sourceFile)).line;
|
||||
let endLine = this.sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line;
|
||||
const startLine = this.sourceFile.getLineAndCharacterOfPosition(node.getStart(this.sourceFile)).line;
|
||||
const endLine = this.sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line;
|
||||
return startLine === endLine;
|
||||
}
|
||||
|
||||
private BlockIsOnOneLine(node: Node): boolean {
|
||||
let openBrace = findChildOfKind(node, SyntaxKind.OpenBraceToken, this.sourceFile);
|
||||
let closeBrace = findChildOfKind(node, SyntaxKind.CloseBraceToken, this.sourceFile);
|
||||
const openBrace = findChildOfKind(node, SyntaxKind.OpenBraceToken, this.sourceFile);
|
||||
const closeBrace = findChildOfKind(node, SyntaxKind.CloseBraceToken, this.sourceFile);
|
||||
if (openBrace && closeBrace) {
|
||||
let startLine = this.sourceFile.getLineAndCharacterOfPosition(openBrace.getEnd()).line;
|
||||
let endLine = this.sourceFile.getLineAndCharacterOfPosition(closeBrace.getStart(this.sourceFile)).line;
|
||||
const startLine = this.sourceFile.getLineAndCharacterOfPosition(openBrace.getEnd()).line;
|
||||
const endLine = this.sourceFile.getLineAndCharacterOfPosition(closeBrace.getStart(this.sourceFile)).line;
|
||||
return startLine === endLine;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace ts.formatting {
|
||||
scanner.setText(sourceFile.text);
|
||||
scanner.setTextPos(startPos);
|
||||
|
||||
let wasNewLine: boolean = true;
|
||||
let wasNewLine = true;
|
||||
let leadingTrivia: TextRangeWithKind[];
|
||||
let trailingTrivia: TextRangeWithKind[];
|
||||
|
||||
@@ -56,13 +56,13 @@ namespace ts.formatting {
|
||||
scanner.setText(undefined);
|
||||
scanner = undefined;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function advance(): void {
|
||||
Debug.assert(scanner !== undefined);
|
||||
|
||||
lastTokenInfo = undefined;
|
||||
let isStarted = scanner.getStartPos() !== startPos;
|
||||
const isStarted = scanner.getStartPos() !== startPos;
|
||||
|
||||
if (isStarted) {
|
||||
if (trailingTrivia) {
|
||||
@@ -81,23 +81,22 @@ namespace ts.formatting {
|
||||
scanner.scan();
|
||||
}
|
||||
|
||||
let t: SyntaxKind;
|
||||
let pos = scanner.getStartPos();
|
||||
|
||||
// Read leading trivia and token
|
||||
while (pos < endPos) {
|
||||
let t = scanner.getToken();
|
||||
const t = scanner.getToken();
|
||||
if (!isTrivia(t)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// consume leading trivia
|
||||
scanner.scan();
|
||||
let item = {
|
||||
const item = {
|
||||
pos: pos,
|
||||
end: scanner.getStartPos(),
|
||||
kind: t
|
||||
}
|
||||
};
|
||||
|
||||
pos = scanner.getStartPos();
|
||||
|
||||
@@ -166,16 +165,16 @@ namespace ts.formatting {
|
||||
|
||||
// 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.
|
||||
let expectedScanAction =
|
||||
const expectedScanAction =
|
||||
shouldRescanGreaterThanToken(n)
|
||||
? ScanAction.RescanGreaterThanToken
|
||||
: shouldRescanSlashToken(n)
|
||||
? ScanAction.RescanSlashToken
|
||||
: shouldRescanSlashToken(n)
|
||||
? ScanAction.RescanSlashToken
|
||||
: shouldRescanTemplateToken(n)
|
||||
? ScanAction.RescanTemplateToken
|
||||
: shouldRescanJsxIdentifier(n)
|
||||
? ScanAction.RescanJsxIdentifier
|
||||
: ScanAction.Scan
|
||||
? ScanAction.RescanJsxIdentifier
|
||||
: ScanAction.Scan;
|
||||
|
||||
if (lastTokenInfo && expectedScanAction === lastScanAction) {
|
||||
// readTokenInfo was called before with the same expected scan action.
|
||||
@@ -218,11 +217,11 @@ namespace ts.formatting {
|
||||
lastScanAction = ScanAction.Scan;
|
||||
}
|
||||
|
||||
let token: TextRangeWithKind = {
|
||||
const token: TextRangeWithKind = {
|
||||
pos: scanner.getStartPos(),
|
||||
end: scanner.getTextPos(),
|
||||
kind: currentToken
|
||||
}
|
||||
};
|
||||
|
||||
// consume trailing trivia
|
||||
if (trailingTrivia) {
|
||||
@@ -233,7 +232,7 @@ namespace ts.formatting {
|
||||
if (!isTrivia(currentToken)) {
|
||||
break;
|
||||
}
|
||||
let trivia = {
|
||||
const trivia = {
|
||||
pos: scanner.getStartPos(),
|
||||
end: scanner.getTextPos(),
|
||||
kind: currentToken
|
||||
@@ -256,7 +255,7 @@ namespace ts.formatting {
|
||||
leadingTrivia: leadingTrivia,
|
||||
trailingTrivia: trailingTrivia,
|
||||
token: token
|
||||
}
|
||||
};
|
||||
|
||||
return fixTokenKind(lastTokenInfo, n);
|
||||
}
|
||||
@@ -264,14 +263,14 @@ namespace ts.formatting {
|
||||
function isOnToken(): boolean {
|
||||
Debug.assert(scanner !== undefined);
|
||||
|
||||
let current = (lastTokenInfo && lastTokenInfo.token.kind) || scanner.getToken();
|
||||
let startPos = (lastTokenInfo && lastTokenInfo.token.pos) || scanner.getStartPos();
|
||||
const current = (lastTokenInfo && lastTokenInfo.token.kind) || scanner.getToken();
|
||||
const startPos = (lastTokenInfo && lastTokenInfo.token.pos) || scanner.getStartPos();
|
||||
return startPos < endPos && current !== SyntaxKind.EndOfFileToken && !isTrivia(current);
|
||||
}
|
||||
|
||||
// when containing node in the tree is token
|
||||
// when containing node in the tree is token
|
||||
// but its kind differs from the kind that was returned by the scanner,
|
||||
// then kind needs to be fixed. This might happen in cases
|
||||
// then kind needs to be fixed. This might happen in cases
|
||||
// when parser interprets token differently, i.e keyword treated as identifier
|
||||
function fixTokenKind(tokenInfo: TokenInfo, container: Node): TokenInfo {
|
||||
if (isToken(container) && tokenInfo.token.kind !== container.kind) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user