mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into master-13893
This commit is contained in:
@@ -57,3 +57,4 @@ internal/
|
||||
!tests/cases/projects/NodeModulesSearch/**/*
|
||||
!tests/baselines/reference/project/nodeModules*/**/*
|
||||
.idea
|
||||
yarn.lock
|
||||
+19
-46
@@ -2,6 +2,7 @@
|
||||
import * as cp from "child_process";
|
||||
import * as path from "path";
|
||||
import * as fs from "fs";
|
||||
import child_process = require("child_process");
|
||||
import originalGulp = require("gulp");
|
||||
import helpMaker = require("gulp-help");
|
||||
import runSequence = require("run-sequence");
|
||||
@@ -21,10 +22,6 @@ declare module "gulp-typescript" {
|
||||
import * as insert from "gulp-insert";
|
||||
import * as sourcemaps from "gulp-sourcemaps";
|
||||
import Q = require("q");
|
||||
declare global {
|
||||
// `del` further depends on `Promise` (and is also not included), so we just, patch the global scope's Promise to Q's (which we already include in our deps because gulp depends on it)
|
||||
type Promise<T> = Q.Promise<T>;
|
||||
}
|
||||
import del = require("del");
|
||||
import mkdirP = require("mkdirp");
|
||||
import minimist = require("minimist");
|
||||
@@ -394,7 +391,7 @@ gulp.task(builtLocalCompiler, false, [servicesFile], () => {
|
||||
.pipe(localCompilerProject())
|
||||
.pipe(prependCopyright())
|
||||
.pipe(sourcemaps.write("."))
|
||||
.pipe(gulp.dest("."));
|
||||
.pipe(gulp.dest("src/compiler"));
|
||||
});
|
||||
|
||||
gulp.task(servicesFile, false, ["lib", "generate-diagnostics"], () => {
|
||||
@@ -420,13 +417,13 @@ gulp.task(servicesFile, false, ["lib", "generate-diagnostics"], () => {
|
||||
file.path = nodeDefinitionsFile;
|
||||
return content + "\r\nexport = ts;";
|
||||
}))
|
||||
.pipe(gulp.dest(".")),
|
||||
.pipe(gulp.dest("src/services")),
|
||||
completedDts.pipe(clone())
|
||||
.pipe(insert.transform((content, file) => {
|
||||
file.path = nodeStandaloneDefinitionsFile;
|
||||
return content.replace(/declare (namespace|module) ts/g, 'declare module "typescript"');
|
||||
}))
|
||||
]).pipe(gulp.dest("."));
|
||||
]).pipe(gulp.dest("src/services"));
|
||||
});
|
||||
|
||||
// cancellationToken.js
|
||||
@@ -452,7 +449,7 @@ gulp.task(typingsInstallerJs, false, [servicesFile], () => {
|
||||
.pipe(cancellationTokenProject())
|
||||
.pipe(prependCopyright())
|
||||
.pipe(sourcemaps.write("."))
|
||||
.pipe(gulp.dest("."));
|
||||
.pipe(gulp.dest("src/server/typingsInstaller"));
|
||||
});
|
||||
|
||||
const serverFile = path.join(builtLocalDirectory, "tsserver.js");
|
||||
@@ -465,7 +462,7 @@ gulp.task(serverFile, false, [servicesFile, typingsInstallerJs, cancellationToke
|
||||
.pipe(serverProject())
|
||||
.pipe(prependCopyright())
|
||||
.pipe(sourcemaps.write("."))
|
||||
.pipe(gulp.dest("."));
|
||||
.pipe(gulp.dest("src/server"));
|
||||
});
|
||||
|
||||
const tsserverLibraryFile = path.join(builtLocalDirectory, "tsserverlibrary.js");
|
||||
@@ -481,12 +478,12 @@ gulp.task(tsserverLibraryFile, false, [servicesFile], (done) => {
|
||||
return merge2([
|
||||
js.pipe(prependCopyright())
|
||||
.pipe(sourcemaps.write("."))
|
||||
.pipe(gulp.dest(".")),
|
||||
.pipe(gulp.dest("src/server")),
|
||||
dts.pipe(prependCopyright(/*outputCopyright*/true))
|
||||
.pipe(insert.transform((content) => {
|
||||
return content + "\r\nexport = ts;\r\nexport as namespace ts;";
|
||||
}))
|
||||
.pipe(gulp.dest("."))
|
||||
.pipe(gulp.dest("src/server"))
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -560,7 +557,7 @@ gulp.task(run, false, [servicesFile], () => {
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(testProject())
|
||||
.pipe(sourcemaps.write(".", { includeContent: false, sourceRoot: "../../" }))
|
||||
.pipe(gulp.dest("."));
|
||||
.pipe(gulp.dest("src/harness"));
|
||||
});
|
||||
|
||||
const internalTests = "internal/";
|
||||
@@ -753,7 +750,7 @@ gulp.task("browserify", "Runs browserify on run.js to produce a file suitable fo
|
||||
const originalMap = file.sourceMap;
|
||||
const prebundledContent = file.contents.toString();
|
||||
// Make paths absolute to help sorcery deal with all the terrible paths being thrown around
|
||||
originalMap.sources = originalMap.sources.map(s => path.resolve(s));
|
||||
originalMap.sources = originalMap.sources.map(s => path.resolve(path.join("src/harness", s)));
|
||||
// intoStream (below) makes browserify think the input file is named this, so this is what it puts in the sourcemap
|
||||
originalMap.file = "built/local/_stream_0.js";
|
||||
|
||||
@@ -782,7 +779,7 @@ gulp.task("browserify", "Runs browserify on run.js to produce a file suitable fo
|
||||
});
|
||||
}))
|
||||
.pipe(sourcemaps.write(".", { includeContent: false }))
|
||||
.pipe(gulp.dest("."));
|
||||
.pipe(gulp.dest("src/harness"));
|
||||
});
|
||||
|
||||
|
||||
@@ -964,7 +961,7 @@ gulp.task("update-sublime", "Updates the sublime plugin's tsserver", ["local", s
|
||||
});
|
||||
|
||||
gulp.task("build-rules", "Compiles tslint rules to js", () => {
|
||||
const settings: tsc.Settings = getCompilerSettings({ module: "commonjs" }, /*useBuiltCompiler*/ false);
|
||||
const settings: tsc.Settings = getCompilerSettings({ module: "commonjs", "lib": ["es6"] }, /*useBuiltCompiler*/ false);
|
||||
const dest = path.join(builtLocalDirectory, "tslint");
|
||||
return gulp.src("scripts/tslint/**/*.ts")
|
||||
.pipe(newer({
|
||||
@@ -1023,40 +1020,16 @@ function spawnLintWorker(files: {path: string}[], callback: (failures: number) =
|
||||
}
|
||||
|
||||
gulp.task("lint", "Runs tslint on the compiler sources. Optional arguments are: --f[iles]=regex", ["build-rules"], () => {
|
||||
const fileMatcher = RegExp(cmdLineOptions["files"]);
|
||||
if (fold.isTravis()) console.log(fold.start("lint"));
|
||||
|
||||
let files: {stat: fs.Stats, path: string}[] = [];
|
||||
return gulp.src(lintTargets, { read: false })
|
||||
.pipe(through2.obj((chunk, enc, cb) => {
|
||||
files.push(chunk);
|
||||
cb();
|
||||
}, (cb) => {
|
||||
files = files.filter(file => fileMatcher.test(file.path)).sort((filea, fileb) => filea.stat.size - fileb.stat.size);
|
||||
const workerCount = cmdLineOptions["workers"];
|
||||
for (let i = 0; i < workerCount; i++) {
|
||||
spawnLintWorker(files, finished);
|
||||
}
|
||||
|
||||
let completed = 0;
|
||||
let failures = 0;
|
||||
function finished(fails) {
|
||||
completed++;
|
||||
failures += fails;
|
||||
if (completed === workerCount) {
|
||||
if (fold.isTravis()) console.log(fold.end("lint"));
|
||||
if (failures > 0) {
|
||||
throw new Error(`Linter errors: ${failures}`);
|
||||
}
|
||||
else {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
const fileMatcher = cmdLineOptions["files"];
|
||||
const files = fileMatcher
|
||||
? `src/**/${fileMatcher}`
|
||||
: "Gulpfile.ts 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts' --exclude 'src/harness/unittests/services/**/*.ts'";
|
||||
const cmd = `node node_modules/tslint/bin/tslint ${files} --format stylish`;
|
||||
console.log("Linting: " + cmd);
|
||||
child_process.execSync(cmd, { stdio: [0, 1, 2] });
|
||||
});
|
||||
|
||||
|
||||
gulp.task("default", "Runs 'local'", ["local"]);
|
||||
|
||||
gulp.task("watch", "Watches the src/ directory for changes and executes runtests-parallel.", [], () => {
|
||||
|
||||
+29
-52
@@ -11,11 +11,7 @@ var ts = require("./lib/typescript");
|
||||
|
||||
// Variables
|
||||
var compilerDirectory = "src/compiler/";
|
||||
var servicesDirectory = "src/services/";
|
||||
var serverDirectory = "src/server/";
|
||||
var typingsInstallerDirectory = "src/server/typingsInstaller";
|
||||
var cancellationTokenDirectory = "src/server/cancellationToken";
|
||||
var watchGuardDirectory = "src/server/watchGuard";
|
||||
var harnessDirectory = "src/harness/";
|
||||
var libraryDirectory = "src/lib/";
|
||||
var scriptsDirectory = "scripts/";
|
||||
@@ -131,6 +127,7 @@ var harnessSources = harnessCoreSources.concat([
|
||||
"matchFiles.ts",
|
||||
"initializeTSConfig.ts",
|
||||
"printer.ts",
|
||||
"textChanges.ts",
|
||||
"transform.ts",
|
||||
"customTransforms.ts",
|
||||
].map(function (f) {
|
||||
@@ -328,8 +325,14 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts
|
||||
if (opts.stripInternal) {
|
||||
options += " --stripInternal";
|
||||
}
|
||||
|
||||
options += " --target es5 --lib es5,scripthost --noUnusedLocals --noUnusedParameters";
|
||||
options += " --target es5";
|
||||
if (opts.lib) {
|
||||
options += " --lib " + opts.lib
|
||||
}
|
||||
else {
|
||||
options += " --lib es5"
|
||||
}
|
||||
options += " --noUnusedLocals --noUnusedParameters";
|
||||
|
||||
var cmd = host + " " + compilerPath + " " + options + " ";
|
||||
cmd = cmd + sources.join(" ");
|
||||
@@ -416,7 +419,7 @@ compileFile(buildProtocolJs,
|
||||
[buildProtocolTs],
|
||||
[],
|
||||
/*useBuiltCompiler*/ false,
|
||||
{noOutFile: true});
|
||||
{ noOutFile: true, lib: "es6" });
|
||||
|
||||
file(buildProtocolDts, [buildProtocolTs, buildProtocolJs, typescriptServicesDts], function() {
|
||||
|
||||
@@ -578,16 +581,16 @@ compileFile(
|
||||
file(typescriptServicesDts, [servicesFile]);
|
||||
|
||||
var cancellationTokenFile = path.join(builtLocalDirectory, "cancellationToken.js");
|
||||
compileFile(cancellationTokenFile, cancellationTokenSources, [builtLocalDirectory].concat(cancellationTokenSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { outDir: builtLocalDirectory, noOutFile: true });
|
||||
compileFile(cancellationTokenFile, cancellationTokenSources, [builtLocalDirectory].concat(cancellationTokenSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { types: ["node"], outDir: builtLocalDirectory, noOutFile: true, lib: "es6" });
|
||||
|
||||
var typingsInstallerFile = path.join(builtLocalDirectory, "typingsInstaller.js");
|
||||
compileFile(typingsInstallerFile, typingsInstallerSources, [builtLocalDirectory].concat(typingsInstallerSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { outDir: builtLocalDirectory, noOutFile: false });
|
||||
compileFile(typingsInstallerFile, typingsInstallerSources, [builtLocalDirectory].concat(typingsInstallerSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { types: ["node"], outDir: builtLocalDirectory, noOutFile: false, lib: "es6" });
|
||||
|
||||
var watchGuardFile = path.join(builtLocalDirectory, "watchGuard.js");
|
||||
compileFile(watchGuardFile, watchGuardSources, [builtLocalDirectory].concat(watchGuardSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { outDir: builtLocalDirectory, noOutFile: false });
|
||||
compileFile(watchGuardFile, watchGuardSources, [builtLocalDirectory].concat(watchGuardSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { types: ["node"], outDir: builtLocalDirectory, noOutFile: false, lib: "es6" });
|
||||
|
||||
var serverFile = path.join(builtLocalDirectory, "tsserver.js");
|
||||
compileFile(serverFile, serverSources, [builtLocalDirectory, copyright, cancellationTokenFile, typingsInstallerFile, watchGuardFile].concat(serverSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { types: ["node"], preserveConstEnums: true });
|
||||
compileFile(serverFile, serverSources, [builtLocalDirectory, copyright, cancellationTokenFile, typingsInstallerFile, watchGuardFile].concat(serverSources).concat(servicesSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { types: ["node"], preserveConstEnums: true, lib: "es6" });
|
||||
var tsserverLibraryFile = path.join(builtLocalDirectory, "tsserverlibrary.js");
|
||||
var tsserverLibraryDefinitionFile = path.join(builtLocalDirectory, "tsserverlibrary.d.ts");
|
||||
compileFile(
|
||||
@@ -711,7 +714,7 @@ compileFile(
|
||||
/*prereqs*/[builtLocalDirectory, tscFile].concat(libraryTargets).concat(servicesSources).concat(harnessSources),
|
||||
/*prefixes*/[],
|
||||
/*useBuiltCompiler:*/ true,
|
||||
/*opts*/ { inlineSourceMap: true, types: ["node", "mocha", "chai"] });
|
||||
/*opts*/ { inlineSourceMap: true, types: ["node", "mocha", "chai"], lib: "es6" });
|
||||
|
||||
var internalTests = "internal/";
|
||||
|
||||
@@ -1098,7 +1101,8 @@ var tslintRules = [
|
||||
"noInOperatorRule",
|
||||
"noIncrementDecrementRule",
|
||||
"objectLiteralSurroundingSpaceRule",
|
||||
"noTypeAssertionWhitespaceRule"
|
||||
"noTypeAssertionWhitespaceRule",
|
||||
"noBomRule"
|
||||
];
|
||||
var tslintRulesFiles = tslintRules.map(function (p) {
|
||||
return path.join(tslintRuleDir, p + ".ts");
|
||||
@@ -1110,7 +1114,7 @@ desc("Compiles tslint rules to js");
|
||||
task("build-rules", ["build-rules-start"].concat(tslintRulesOutFiles).concat(["build-rules-end"]));
|
||||
tslintRulesFiles.forEach(function (ruleFile, i) {
|
||||
compileFile(tslintRulesOutFiles[i], [ruleFile], [ruleFile], [], /*useBuiltCompiler*/ false,
|
||||
{ noOutFile: true, generateDeclarations: false, outDir: path.join(builtLocalDirectory, "tslint") });
|
||||
{ noOutFile: true, generateDeclarations: false, outDir: path.join(builtLocalDirectory, "tslint"), lib: "es6" });
|
||||
});
|
||||
|
||||
desc("Emit the start of the build-rules fold");
|
||||
@@ -1173,43 +1177,16 @@ function spawnLintWorker(files, callback) {
|
||||
}
|
||||
|
||||
desc("Runs tslint on the compiler sources. Optional arguments are: f[iles]=regex");
|
||||
task("lint", ["build-rules"], function () {
|
||||
task("lint", ["build-rules"], () => {
|
||||
if (fold.isTravis()) console.log(fold.start("lint"));
|
||||
var startTime = mark();
|
||||
var failed = 0;
|
||||
var fileMatcher = RegExp(process.env.f || process.env.file || process.env.files || "");
|
||||
var done = {};
|
||||
for (var i in lintTargets) {
|
||||
var target = lintTargets[i];
|
||||
if (!done[target] && fileMatcher.test(target)) {
|
||||
done[target] = fs.statSync(target).size;
|
||||
}
|
||||
}
|
||||
|
||||
var workerCount = (process.env.workerCount && +process.env.workerCount) || os.cpus().length;
|
||||
|
||||
var names = Object.keys(done).sort(function (namea, nameb) {
|
||||
return done[namea] - done[nameb];
|
||||
const fileMatcher = process.env.f || process.env.file || process.env.files;
|
||||
const files = fileMatcher
|
||||
? `src/**/${fileMatcher}`
|
||||
: "Gulpfile.ts 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts' --exclude 'src/harness/unittests/services/**/*.ts'";
|
||||
const cmd = `node node_modules/tslint/bin/tslint ${files} --format stylish`;
|
||||
console.log("Linting: " + cmd);
|
||||
jake.exec([cmd], { interactive: true }, () => {
|
||||
if (fold.isTravis()) console.log(fold.end("lint"));
|
||||
complete();
|
||||
});
|
||||
|
||||
for (var i = 0; i < workerCount; i++) {
|
||||
spawnLintWorker(names, finished);
|
||||
}
|
||||
|
||||
var completed = 0;
|
||||
var failures = 0;
|
||||
function finished(fails) {
|
||||
completed++;
|
||||
failures += fails;
|
||||
if (completed === workerCount) {
|
||||
measure(startTime);
|
||||
if (fold.isTravis()) console.log(fold.end("lint"));
|
||||
if (failures > 0) {
|
||||
fail('Linter errors.', failed);
|
||||
}
|
||||
else {
|
||||
complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, { async: true });
|
||||
});
|
||||
|
||||
@@ -39,8 +39,8 @@ with any additional questions or comments.
|
||||
|
||||
## Documentation
|
||||
|
||||
* [Quick tutorial](http://www.typescriptlang.org/Tutorial)
|
||||
* [Programming handbook](http://www.typescriptlang.org/Handbook)
|
||||
* [Quick tutorial](http://www.typescriptlang.org/docs/tutorial.html)
|
||||
* [Programming handbook](http://www.typescriptlang.org/docs/handbook/basic-types.html)
|
||||
* [Language specification](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md)
|
||||
* [Homepage](http://www.typescriptlang.org/)
|
||||
|
||||
@@ -95,4 +95,4 @@ node built/local/tsc.js hello.ts
|
||||
|
||||
## Roadmap
|
||||
|
||||
For details on our planned features and future direction please refer to our [roadmap](https://github.com/Microsoft/TypeScript/wiki/Roadmap).
|
||||
For details on our planned features and future direction please refer to our [roadmap](https://github.com/Microsoft/TypeScript/wiki/Roadmap).
|
||||
|
||||
+10
-15
@@ -1,15 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" id="logo-typescript" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 283.09 69.57">
|
||||
<g fill="#007ACC">
|
||||
<path d="M34.98 7.56H20.43v45.07h-5.91V7.56H0V2.21h34.98V7.56z"/>
|
||||
<path d="M57.94 16.63L41.38 58.39c-2.95 7.45-7.1 11.18-12.45 11.18 -1.5 0-2.75-0.15-3.76-0.46v-5.17c1.24 0.42 2.38 0.63 3.41 0.63 2.91 0 5.09-1.73 6.54-5.2l2.88-6.82L23.94 16.63h6.4l9.74 27.7c0.12 0.35 0.36 1.27 0.74 2.74h0.21c0.12-0.56 0.35-1.45 0.7-2.67l10.23-27.77H57.94z"/>
|
||||
<path d="M67.37 47.43h-0.14v21.76h-5.77V16.63h5.77v6.33h0.14c2.84-4.78 6.98-7.17 12.45-7.17 4.64 0 8.26 1.61 10.86 4.83 2.6 3.22 3.9 7.54 3.9 12.96 0 6.02-1.46 10.85-4.39 14.47 -2.93 3.62-6.94 5.43-12.02 5.43C73.5 53.47 69.9 51.46 67.37 47.43zM67.23 32.91v5.03c0 2.98 0.97 5.5 2.9 7.58s4.39 3.11 7.37 3.11c3.49 0 6.23-1.34 8.21-4.01 1.98-2.67 2.97-6.39 2.97-11.14 0-4.01-0.93-7.15-2.78-9.42 -1.85-2.27-4.36-3.41-7.52-3.41 -3.35 0-6.05 1.17-8.09 3.5C68.25 26.47 67.23 29.39 67.23 32.91z"/>
|
||||
<path d="M129.56 36.07h-25.42c0.09 4.01 1.17 7.1 3.23 9.28 2.06 2.18 4.9 3.27 8.51 3.27 4.05 0 7.78-1.34 11.18-4.01v5.41c-3.16 2.3-7.35 3.45-12.55 3.45 -5.09 0-9.08-1.63-11.99-4.9 -2.91-3.27-4.36-7.87-4.36-13.8 0-5.6 1.59-10.17 4.76-13.69 3.18-3.53 7.12-5.29 11.83-5.29s8.35 1.52 10.93 4.57c2.58 3.05 3.87 7.28 3.87 12.69V36.07zM123.65 31.18c-0.02-3.33-0.83-5.92-2.41-7.77 -1.58-1.85-3.78-2.78-6.59-2.78 -2.72 0-5.03 0.97-6.93 2.92 -1.9 1.95-3.07 4.49-3.52 7.63H123.65z"/>
|
||||
<path d="M134.6 50.59v-6.96c0.73 0.7 1.6 1.34 2.62 1.9 1.02 0.56 2.09 1.04 3.22 1.42s2.26 0.69 3.39 0.9c1.14 0.21 2.19 0.32 3.15 0.32 3.32 0 5.81-0.67 7.45-2.02 1.64-1.35 2.46-3.29 2.46-5.82 0-1.36-0.27-2.54-0.82-3.55 -0.55-1.01-1.3-1.93-2.27-2.76s-2.11-1.63-3.43-2.39c-1.32-0.76-2.74-1.56-4.26-2.41 -1.61-0.89-3.11-1.79-4.5-2.71 -1.39-0.91-2.61-1.92-3.63-3.02 -1.03-1.1-1.84-2.35-2.43-3.74 -0.59-1.39-0.88-3.03-0.88-4.9 0-2.3 0.46-4.29 1.38-5.99 0.92-1.7 2.13-3.1 3.64-4.2 1.5-1.1 3.21-1.92 5.13-2.46 1.92-0.54 3.88-0.81 5.87-0.81 4.55 0 7.86 0.6 9.94 1.79v6.64c-2.72-2.06-6.22-3.09-10.49-3.09 -1.18 0-2.36 0.14-3.54 0.4 -1.18 0.27-2.23 0.71-3.15 1.32 -0.92 0.61-1.67 1.39-2.25 2.36 -0.58 0.96-0.87 2.13-0.87 3.52 0 1.29 0.22 2.4 0.66 3.34 0.44 0.94 1.09 1.79 1.95 2.57 0.86 0.77 1.9 1.52 3.14 2.25 1.23 0.73 2.65 1.52 4.26 2.39 1.65 0.89 3.22 1.83 4.7 2.81s2.78 2.07 3.89 3.27c1.11 1.2 2 2.52 2.65 3.97 0.65 1.45 0.98 3.12 0.98 4.99 0 2.48-0.45 4.59-1.33 6.31 -0.89 1.72-2.09 3.12-3.6 4.2 -1.51 1.08-3.25 1.86-5.23 2.34 -1.97 0.48-4.05 0.72-6.24 0.72 -0.73 0-1.63-0.06-2.7-0.19s-2.17-0.32-3.28-0.56c-1.12-0.25-2.17-0.55-3.17-0.91C136 51.44 135.21 51.03 134.6 50.59z"/>
|
||||
<path d="M193.25 50.98c-2.77 1.66-6.05 2.5-9.84 2.5 -5.13 0-9.28-1.67-12.43-5.01s-4.73-7.67-4.73-12.99c0-5.93 1.7-10.69 5.1-14.29 3.4-3.6 7.93-5.4 13.61-5.4 3.16 0 5.95 0.59 8.37 1.76v5.91c-2.67-1.88-5.53-2.81-8.58-2.81 -3.68 0-6.7 1.32-9.05 3.96s-3.53 6.1-3.53 10.39c0 4.22 1.11 7.55 3.32 9.98s5.19 3.66 8.91 3.66c3.14 0 6.09-1.04 8.86-3.13V50.98z"/>
|
||||
<path d="M215.56 22.46c-1.01-0.77-2.46-1.16-4.36-1.16 -2.46 0-4.52 1.16-6.17 3.48s-2.48 5.48-2.48 9.49v18.35h-5.77v-36h5.77v7.42h0.14c0.82-2.53 2.07-4.51 3.76-5.92 1.69-1.42 3.57-2.13 5.66-2.13 1.5 0 2.65 0.16 3.45 0.49V22.46z"/>
|
||||
<path d="M222.18 7.49c-1.03 0-1.91-0.35-2.64-1.05s-1.09-1.59-1.09-2.67c0-1.08 0.36-1.97 1.09-2.69 0.73-0.71 1.61-1.07 2.64-1.07 1.05 0 1.95 0.36 2.69 1.07 0.74 0.72 1.11 1.61 1.11 2.69 0 1.03-0.37 1.91-1.11 2.64C224.13 7.12 223.23 7.49 222.18 7.49zM224.99 52.63h-5.77v-36h5.77V52.63z"/>
|
||||
<path d="M234.29 47.43h-0.14v21.76h-5.77V16.63h5.77v6.33h0.14c2.84-4.78 6.98-7.17 12.45-7.17 4.64 0 8.26 1.61 10.86 4.83 2.6 3.22 3.9 7.54 3.9 12.96 0 6.02-1.46 10.85-4.39 14.47s-6.94 5.43-12.02 5.43C240.42 53.47 236.82 51.46 234.29 47.43zM234.15 32.91v5.03c0 2.98 0.97 5.5 2.9 7.58s4.39 3.11 7.37 3.11c3.49 0 6.23-1.34 8.21-4.01s2.97-6.39 2.97-11.14c0-4.01-0.93-7.15-2.78-9.42 -1.85-2.27-4.36-3.41-7.52-3.41 -3.35 0-6.05 1.17-8.09 3.5C235.17 26.47 234.15 29.39 234.15 32.91z"/>
|
||||
<path d="M283.09 52.28c-1.36 0.75-3.15 1.12-5.38 1.12 -6.3 0-9.46-3.52-9.46-10.55v-21.3h-6.19v-4.92h6.19V7.84l5.77-1.86v10.65h9.07v4.92h-9.07v20.28c0 2.41 0.41 4.14 1.23 5.17s2.18 1.55 4.08 1.55c1.45 0 2.71-0.4 3.76-1.2V52.28z"/>
|
||||
</g>
|
||||
</svg>
|
||||
<svg id="logo-typescript" xmlns="http://www.w3.org/2000/svg" viewBox="-64.9 417 216.5 51.9">
|
||||
<style>
|
||||
.st0 {
|
||||
fill: #000
|
||||
}
|
||||
</style>
|
||||
<path class="st0" d="M-38.2 421.7h-11.1V456h-4.5v-34.3h-11.1v-4.1h26.6v4.1h.1z" />
|
||||
<path class="st0" d="M-16.9 428.6l-12.6 31.8c-2.3 5.7-5.4 8.5-9.5 8.5-1.1 0-2.1-.1-2.9-.3v-3.9c.9.3 1.8.5 2.6.5 2.2 0 3.9-1.3 5-4l2.2-5.2-10.7-27.4h4.9l7.4 21.1c.1.3.3 1 .6 2.1h.2c.1-.4.3-1.1.5-2l7.8-21.2h4.5zM-9.5 452.1h-.1v16.6H-14v-40h4.4v4.8h.1c2.2-3.6 5.3-5.5 9.5-5.5 3.5 0 6.3 1.2 8.3 3.7s3 5.7 3 9.9c0 4.6-1.1 8.3-3.3 11s-5.3 4.1-9.2 4.1c-3.6 0-6.3-1.5-8.3-4.6zm-.1-11.1v3.8c0 2.3.7 4.2 2.2 5.8s3.3 2.4 5.6 2.4c2.7 0 4.7-1 6.3-3.1 1.6-2.1 2.3-4.9 2.3-8.5 0-3.1-.7-5.4-2.1-7.2-1.4-1.7-3.3-2.6-5.7-2.6-2.6 0-4.6.9-6.2 2.7-1.6 1.8-2.4 4-2.4 6.7zM38.4 443.4H19c.1 3.1.9 5.4 2.5 7.1s3.7 2.5 6.5 2.5c3.1 0 5.9-1 8.5-3.1v4.1c-2.4 1.8-5.6 2.6-9.6 2.6-3.9 0-6.9-1.2-9.1-3.7-2.2-2.5-3.3-6-3.3-10.5 0-4.3 1.2-7.7 3.6-10.4 2.4-2.7 5.4-4 9-4s6.4 1.2 8.3 3.5c2 2.3 2.9 5.5 2.9 9.7v2.2h.1zm-4.5-3.7c0-2.5-.6-4.5-1.8-5.9-1.2-1.4-2.9-2.1-5-2.1s-3.8.7-5.3 2.2c-1.4 1.5-2.3 3.4-2.7 5.8h14.8zM40.8 454.7v-3c2.8 1.8 5.5 2.6 8.4 2.6 3 0 5.3-.6 6.8-1.9 1.6-1.2 2.3-3 2.3-5.2 0-2-.5-3.5-1.6-4.7-1-1.2-3.3-2.8-6.8-4.8-3.9-2.3-6.4-4.2-7.4-5.7s-1.6-3.3-1.6-5.3c0-2.7 1.1-5 3.2-6.9 2.1-1.9 4.9-2.8 8.4-2.8 2.3 0 4.6.4 6.9 1.2v2.8c-2.3-1-4.7-1.5-7.2-1.5-2.6 0-4.7.7-6.2 2s-2.3 3-2.3 5 .5 3.5 1.6 4.7c1 1.2 3.3 2.7 6.8 4.7 3.6 2 6 3.8 7.2 5.4 1.2 1.6 1.8 3.4 1.8 5.5 0 2.9-1 5.3-3.1 7.2-2 1.9-4.9 2.8-8.7 2.8-1.3 0-2.8-.2-4.6-.6-1.6-.5-2.9-1-3.9-1.5zM84.3 454.8c-2 1.2-4.5 1.9-7.3 1.9-3.7 0-6.7-1.3-9-3.8-2.3-2.6-3.4-5.9-3.4-10.1 0-4.4 1.3-7.9 3.9-10.7 2.6-2.8 5.9-4.2 9.9-4.2 2.1 0 4.1.4 6.1 1.3v2.8c-2-1.2-4.1-1.8-6.5-1.8-3.2 0-5.8 1.2-7.8 3.5s-3 5.3-3 9c0 3.6.9 6.4 2.7 8.6 1.8 2.2 4.2 3.2 7.2 3.2 2.7 0 5.1-.7 7.2-2.2v2.5zM100.9 431.2c-.8-.6-1.8-.9-2.9-.9-2.2 0-4 1.1-5.4 3.3-1.5 2.2-2.2 5.4-2.2 9.5V456H88v-27.4h2.4v6.1h.1c.6-2.1 1.6-3.7 3-4.9 1.4-1.2 2.9-1.7 4.7-1.7 1 0 1.9.2 2.7.5v2.6zM105.1 421.7c-.5 0-1-.2-1.4-.6s-.6-.9-.6-1.5.2-1.1.6-1.4c.4-.4.9-.5 1.4-.5.6 0 1 .2 1.5.5.4.4.6.8.6 1.4s-.2 1.1-.6 1.5c-.5.4-.9.6-1.5.6zm-1.2 34.4v-27.4h2.5v27.4h-2.5zM115 451.2h-.1v17.5h-2.5v-40h2.5v5.7h.1c1-2 2.4-3.6 4.2-4.7 1.8-1.1 3.8-1.6 6-1.6 3.5 0 6.2 1.2 8.2 3.6 2 2.4 2.9 5.7 2.9 9.8 0 4.6-1.1 8.3-3.4 11.1-2.2 2.8-5.2 4.2-8.9 4.2-4-.1-7-1.9-9-5.6zm-.1-10.2v3.5c0 2.8.9 5.1 2.6 7.1s4 3 6.8 3 5.1-1.2 6.8-3.6c1.7-2.4 2.6-5.6 2.6-9.5 0-3.4-.8-6.2-2.4-8.2s-3.8-3-6.4-3c-3.2 0-5.7 1.1-7.4 3.2-1.7 2.1-2.6 4.6-2.6 7.5zM151.6 455.7c-1.3.6-2.5.9-3.6.9-4.1 0-6.1-2.4-6.1-7.3v-18.4H137v-2.3h4.9v-7.1c.4-.1.8-.3 1.2-.4.4-.1.8-.3 1.2-.4v8h7.2v2.3h-7.2v18.1c0 1.9.3 3.3.9 4.1.6.8 1.6 1.3 3 1.3 1 0 2.1-.3 3.3-1v2.2h.1z"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 2.7 KiB |
+1
-1
@@ -2,7 +2,7 @@
|
||||
<!-- QUESTIONS: This is not a general support forum! Ask Qs at http://stackoverflow.com/questions/tagged/typescript -->
|
||||
<!-- SUGGESTIONS: See https://github.com/Microsoft/TypeScript-wiki/blob/master/Writing-Good-Design-Proposals.md -->
|
||||
|
||||
**TypeScript Version:** 2.1.1 / nightly (2.2.0-dev.201xxxxx)
|
||||
**TypeScript Version:** 2.2.1 / nightly (2.2.0-dev.201xxxxx)
|
||||
|
||||
**Code**
|
||||
|
||||
|
||||
Vendored
+1
@@ -1742,6 +1742,7 @@ declare namespace ts.server.protocol {
|
||||
insertSpaceAfterFunctionKeywordForAnonymousFunctions?: boolean;
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis?: boolean;
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets?: boolean;
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces?: boolean;
|
||||
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces?: boolean;
|
||||
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean;
|
||||
insertSpaceBeforeFunctionParenthesis?: boolean;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
var tslint = require("tslint");
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
|
||||
function getLinterOptions() {
|
||||
return {
|
||||
@@ -9,7 +10,7 @@ function getLinterOptions() {
|
||||
};
|
||||
}
|
||||
function getLinterConfiguration() {
|
||||
return require("../tslint.json");
|
||||
return tslint.Configuration.loadConfigurationFromPath(path.join(__dirname, "../tslint.json"));
|
||||
}
|
||||
|
||||
function lintFileContents(options, configuration, path, contents) {
|
||||
|
||||
@@ -2,52 +2,62 @@ import * as Lint from "tslint/lib";
|
||||
import * as ts from "typescript";
|
||||
|
||||
export class Rule extends Lint.Rules.AbstractRule {
|
||||
public static FAILURE_STRING_FACTORY = (name: string, currently: string) => `Tag boolean argument as '${name}' (currently '${currently}')`;
|
||||
public static FAILURE_STRING_FACTORY(name: string, currently?: string): string {
|
||||
const current = currently ? ` (currently '${currently}')` : "";
|
||||
return `Tag boolean argument as '${name}'${current}`;
|
||||
}
|
||||
|
||||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
||||
// Cheat to get type checker
|
||||
const program = ts.createProgram([sourceFile.fileName], Lint.createCompilerOptions());
|
||||
const checker = program.getTypeChecker();
|
||||
return this.applyWithWalker(new BooleanTriviaWalker(checker, program.getSourceFile(sourceFile.fileName), this.getOptions()));
|
||||
return this.applyWithFunction(program.getSourceFile(sourceFile.fileName), ctx => walk(ctx, checker));
|
||||
}
|
||||
}
|
||||
|
||||
class BooleanTriviaWalker extends Lint.RuleWalker {
|
||||
constructor(private checker: ts.TypeChecker, file: ts.SourceFile, opts: Lint.IOptions) {
|
||||
super(file, opts);
|
||||
function walk(ctx: Lint.WalkContext<void>, checker: ts.TypeChecker): void {
|
||||
ts.forEachChild(ctx.sourceFile, recur);
|
||||
function recur(node: ts.Node): void {
|
||||
if (node.kind === ts.SyntaxKind.CallExpression) {
|
||||
checkCall(node as ts.CallExpression);
|
||||
}
|
||||
ts.forEachChild(node, recur);
|
||||
}
|
||||
|
||||
visitCallExpression(node: ts.CallExpression) {
|
||||
super.visitCallExpression(node);
|
||||
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();
|
||||
const source = this.getSourceFile();
|
||||
for (let index = 0; index < targetParameters.length; index++) {
|
||||
const param = targetParameters[index];
|
||||
const arg = node.arguments[index];
|
||||
if (!(arg && param)) {
|
||||
continue;
|
||||
}
|
||||
function checkCall(node: ts.CallExpression): void {
|
||||
if (!node.arguments || !node.arguments.some(arg => arg.kind === ts.SyntaxKind.TrueKeyword || arg.kind === ts.SyntaxKind.FalseKeyword)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const argType = this.checker.getContextualType(arg);
|
||||
if (argType && (argType.getFlags() & ts.TypeFlags.Boolean)) {
|
||||
if (arg.kind !== ts.SyntaxKind.TrueKeyword && arg.kind !== ts.SyntaxKind.FalseKeyword) {
|
||||
continue;
|
||||
}
|
||||
let triviaContent: string;
|
||||
const ranges = ts.getLeadingCommentRanges(arg.getFullText(), 0);
|
||||
if (ranges && ranges.length === 1 && ranges[0].kind === ts.SyntaxKind.MultiLineCommentTrivia) {
|
||||
triviaContent = arg.getFullText().slice(ranges[0].pos + 2, ranges[0].end - 2); // +/-2 to remove /**/
|
||||
}
|
||||
const targetCallSignature = checker.getResolvedSignature(node);
|
||||
if (!targetCallSignature) {
|
||||
return;
|
||||
}
|
||||
|
||||
const paramName = param.getName();
|
||||
if (triviaContent !== paramName && triviaContent !== paramName + ":") {
|
||||
this.addFailure(this.createFailure(arg.getStart(source), arg.getWidth(source), Rule.FAILURE_STRING_FACTORY(param.getName(), triviaContent)));
|
||||
}
|
||||
}
|
||||
const targetParameters = targetCallSignature.getParameters();
|
||||
for (let index = 0; index < targetParameters.length; index++) {
|
||||
const param = targetParameters[index];
|
||||
const arg = node.arguments[index];
|
||||
if (!(arg && param)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const argType = checker.getContextualType(arg);
|
||||
if (argType && (argType.getFlags() & ts.TypeFlags.Boolean)) {
|
||||
if (arg.kind !== ts.SyntaxKind.TrueKeyword && arg.kind !== ts.SyntaxKind.FalseKeyword) {
|
||||
continue;
|
||||
}
|
||||
let triviaContent: string | undefined;
|
||||
const ranges = ts.getLeadingCommentRanges(arg.getFullText(), 0);
|
||||
if (ranges && ranges.length === 1 && ranges[0].kind === ts.SyntaxKind.MultiLineCommentTrivia) {
|
||||
triviaContent = arg.getFullText().slice(ranges[0].pos + 2, ranges[0].end - 2); // +/-2 to remove /**/
|
||||
}
|
||||
|
||||
const paramName = param.getName();
|
||||
if (triviaContent !== paramName && triviaContent !== paramName + ":") {
|
||||
ctx.addFailureAtNode(arg, Rule.FAILURE_STRING_FACTORY(param.getName(), triviaContent));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,50 +9,56 @@ export class Rule extends Lint.Rules.AbstractRule {
|
||||
public static ELSE_FAILURE_STRING = "'else' should not be on the same line as the preceeding block's curly brace";
|
||||
|
||||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
||||
return this.applyWithWalker(new NextLineWalker(sourceFile, this.getOptions()));
|
||||
const options = this.getOptions().ruleArguments;
|
||||
const checkCatch = options.indexOf(OPTION_CATCH) !== -1;
|
||||
const checkElse = options.indexOf(OPTION_ELSE) !== -1;
|
||||
return this.applyWithFunction(sourceFile, ctx => walk(ctx, checkCatch, checkElse));
|
||||
}
|
||||
}
|
||||
|
||||
class NextLineWalker extends Lint.RuleWalker {
|
||||
public visitIfStatement(node: ts.IfStatement) {
|
||||
const sourceFile = node.getSourceFile();
|
||||
const thenStatement = node.thenStatement;
|
||||
|
||||
const elseStatement = node.elseStatement;
|
||||
if (!!elseStatement) {
|
||||
// find the else keyword
|
||||
const elseKeyword = getFirstChildOfKind(node, ts.SyntaxKind.ElseKeyword);
|
||||
if (this.hasOption(OPTION_ELSE) && !!elseKeyword) {
|
||||
const thenStatementEndLoc = sourceFile.getLineAndCharacterOfPosition(thenStatement.getEnd());
|
||||
const elseKeywordLoc = sourceFile.getLineAndCharacterOfPosition(elseKeyword.getStart(sourceFile));
|
||||
if (thenStatementEndLoc.line === elseKeywordLoc.line) {
|
||||
const failure = this.createFailure(elseKeyword.getStart(sourceFile), elseKeyword.getWidth(sourceFile), Rule.ELSE_FAILURE_STRING);
|
||||
this.addFailure(failure);
|
||||
}
|
||||
}
|
||||
function walk(ctx: Lint.WalkContext<void>, checkCatch: boolean, checkElse: boolean): void {
|
||||
const { sourceFile } = ctx;
|
||||
function recur(node: ts.Node): void {
|
||||
switch (node.kind) {
|
||||
case ts.SyntaxKind.IfStatement:
|
||||
checkIf(node as ts.IfStatement);
|
||||
break;
|
||||
case ts.SyntaxKind.TryStatement:
|
||||
checkTry(node as ts.TryStatement);
|
||||
break;
|
||||
}
|
||||
|
||||
super.visitIfStatement(node);
|
||||
ts.forEachChild(node, recur);
|
||||
}
|
||||
|
||||
public visitTryStatement(node: ts.TryStatement) {
|
||||
const sourceFile = node.getSourceFile();
|
||||
const catchClause = node.catchClause;
|
||||
function checkIf(node: ts.IfStatement): void {
|
||||
const { thenStatement, elseStatement } = node;
|
||||
if (!elseStatement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// "visit" try block
|
||||
const tryBlock = node.tryBlock;
|
||||
|
||||
if (this.hasOption(OPTION_CATCH) && !!catchClause) {
|
||||
const tryClosingBrace = tryBlock.getLastToken(sourceFile);
|
||||
const catchKeyword = catchClause.getFirstToken(sourceFile);
|
||||
const tryClosingBraceLoc = sourceFile.getLineAndCharacterOfPosition(tryClosingBrace.getEnd());
|
||||
const catchKeywordLoc = sourceFile.getLineAndCharacterOfPosition(catchKeyword.getStart(sourceFile));
|
||||
if (tryClosingBraceLoc.line === catchKeywordLoc.line) {
|
||||
const failure = this.createFailure(catchKeyword.getStart(sourceFile), catchKeyword.getWidth(sourceFile), Rule.CATCH_FAILURE_STRING);
|
||||
this.addFailure(failure);
|
||||
// find the else keyword
|
||||
const elseKeyword = getFirstChildOfKind(node, ts.SyntaxKind.ElseKeyword);
|
||||
if (checkElse && !!elseKeyword) {
|
||||
const thenStatementEndLoc = sourceFile.getLineAndCharacterOfPosition(thenStatement.getEnd());
|
||||
const elseKeywordLoc = sourceFile.getLineAndCharacterOfPosition(elseKeyword.getStart(sourceFile));
|
||||
if (thenStatementEndLoc.line === elseKeywordLoc.line) {
|
||||
ctx.addFailureAtNode(elseKeyword, Rule.ELSE_FAILURE_STRING);
|
||||
}
|
||||
}
|
||||
super.visitTryStatement(node);
|
||||
}
|
||||
|
||||
function checkTry({ tryBlock, catchClause }: ts.TryStatement): void {
|
||||
if (!checkCatch || !catchClause) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tryClosingBrace = tryBlock.getLastToken(sourceFile);
|
||||
const catchKeyword = catchClause.getFirstToken(sourceFile);
|
||||
const tryClosingBraceLoc = sourceFile.getLineAndCharacterOfPosition(tryClosingBrace.getEnd());
|
||||
const catchKeywordLoc = sourceFile.getLineAndCharacterOfPosition(catchKeyword.getStart(sourceFile));
|
||||
if (tryClosingBraceLoc.line === catchKeywordLoc.line) {
|
||||
ctx.addFailureAtNode(catchKeyword, Rule.CATCH_FAILURE_STRING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import * as Lint from "tslint/lib";
|
||||
import * as ts from "typescript";
|
||||
|
||||
export class Rule extends Lint.Rules.AbstractRule {
|
||||
public static FAILURE_STRING = "This file has a BOM.";
|
||||
|
||||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
||||
return this.applyWithFunction(sourceFile, walk);
|
||||
}
|
||||
}
|
||||
|
||||
function walk(ctx: Lint.WalkContext<void>): void {
|
||||
if (ctx.sourceFile.text[0] === "\ufeff") {
|
||||
ctx.addFailure(0, 1, Rule.FAILURE_STRING);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,19 @@
|
||||
import * as Lint from "tslint/lib";
|
||||
import * as ts from "typescript";
|
||||
|
||||
|
||||
export class Rule extends Lint.Rules.AbstractRule {
|
||||
public static FAILURE_STRING = "Don't use the 'in' keyword - use 'hasProperty' to check for key presence instead";
|
||||
|
||||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
||||
return this.applyWithWalker(new InWalker(sourceFile, this.getOptions()));
|
||||
return this.applyWithFunction(sourceFile, walk);
|
||||
}
|
||||
}
|
||||
|
||||
class InWalker extends Lint.RuleWalker {
|
||||
visitNode(node: ts.Node) {
|
||||
super.visitNode(node);
|
||||
if (node.kind === ts.SyntaxKind.InKeyword && node.parent && node.parent.kind === ts.SyntaxKind.BinaryExpression) {
|
||||
this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING));
|
||||
function walk(ctx: Lint.WalkContext<void>): void {
|
||||
ts.forEachChild(ctx.sourceFile, recur);
|
||||
function recur(node: ts.Node): void {
|
||||
if (node.kind === ts.SyntaxKind.InKeyword && node.parent.kind === ts.SyntaxKind.BinaryExpression) {
|
||||
ctx.addFailureAtNode(node, Rule.FAILURE_STRING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +1,55 @@
|
||||
import * as Lint from "tslint/lib";
|
||||
import * as ts from "typescript";
|
||||
|
||||
|
||||
export class Rule extends Lint.Rules.AbstractRule {
|
||||
public static POSTFIX_FAILURE_STRING = "Don't use '++' or '--' postfix operators outside statements or for loops.";
|
||||
public static PREFIX_FAILURE_STRING = "Don't use '++' or '--' prefix operators.";
|
||||
|
||||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
||||
return this.applyWithWalker(new IncrementDecrementWalker(sourceFile, this.getOptions()));
|
||||
return this.applyWithFunction(sourceFile, walk);
|
||||
}
|
||||
}
|
||||
|
||||
class IncrementDecrementWalker extends Lint.RuleWalker {
|
||||
function walk(ctx: Lint.WalkContext<void>): void {
|
||||
ts.forEachChild(ctx.sourceFile, recur);
|
||||
function recur(node: ts.Node): void {
|
||||
switch (node.kind) {
|
||||
case ts.SyntaxKind.PrefixUnaryExpression:
|
||||
const { operator } = node as ts.PrefixUnaryExpression;
|
||||
if (operator === ts.SyntaxKind.PlusPlusToken || operator === ts.SyntaxKind.MinusMinusToken) {
|
||||
check(node as ts.PrefixUnaryExpression);
|
||||
}
|
||||
break;
|
||||
|
||||
visitPostfixUnaryExpression(node: ts.PostfixUnaryExpression) {
|
||||
super.visitPostfixUnaryExpression(node);
|
||||
if (node.operator === ts.SyntaxKind.PlusPlusToken || node.operator == ts.SyntaxKind.MinusMinusToken) {
|
||||
this.visitIncrementDecrement(node);
|
||||
case ts.SyntaxKind.PostfixUnaryExpression:
|
||||
check(node as ts.PostfixUnaryExpression);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
visitPrefixUnaryExpression(node: ts.PrefixUnaryExpression) {
|
||||
super.visitPrefixUnaryExpression(node);
|
||||
if (node.operator === ts.SyntaxKind.PlusPlusToken || node.operator == ts.SyntaxKind.MinusMinusToken) {
|
||||
this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.PREFIX_FAILURE_STRING));
|
||||
function check(node: ts.UnaryExpression): void {
|
||||
if (!isAllowedLocation(node.parent!)) {
|
||||
ctx.addFailureAtNode(node, Rule.POSTFIX_FAILURE_STRING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
visitIncrementDecrement(node: ts.UnaryExpression) {
|
||||
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));
|
||||
function isAllowedLocation(node: ts.Node): boolean {
|
||||
switch (node.kind) {
|
||||
// Can be a statement
|
||||
case ts.SyntaxKind.ExpressionStatement:
|
||||
return true;
|
||||
|
||||
// Can be directly in a for-statement
|
||||
case ts.SyntaxKind.ForStatement:
|
||||
return true;
|
||||
|
||||
// Can be in a comma operator in a for statement (`for (let a = 0, b = 10; a < b; a++, b--)`)
|
||||
case ts.SyntaxKind.BinaryExpression:
|
||||
return (node as ts.BinaryExpression).operatorToken.kind === ts.SyntaxKind.CommaToken &&
|
||||
node.parent!.kind === ts.SyntaxKind.ForStatement;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import * as Lint from "tslint/lib";
|
||||
import * as ts from "typescript";
|
||||
|
||||
|
||||
export class Rule extends Lint.Rules.AbstractRule {
|
||||
public static TRAILING_FAILURE_STRING = "Excess trailing whitespace found around type assertion.";
|
||||
|
||||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
||||
return this.applyWithWalker(new TypeAssertionWhitespaceWalker(sourceFile, this.getOptions()));
|
||||
return this.applyWithFunction(sourceFile, walk);
|
||||
}
|
||||
}
|
||||
|
||||
class TypeAssertionWhitespaceWalker extends Lint.RuleWalker {
|
||||
public visitNode(node: ts.Node) {
|
||||
function walk(ctx: Lint.WalkContext<void>): void {
|
||||
ts.forEachChild(ctx.sourceFile, recur);
|
||||
function recur(node: ts.Node) {
|
||||
if (node.kind === ts.SyntaxKind.TypeAssertionExpression) {
|
||||
const refined = node as ts.TypeAssertion;
|
||||
const leftSideWhitespaceStart = refined.type.getEnd() + 1;
|
||||
const rightSideWhitespaceEnd = refined.expression.getStart();
|
||||
if (leftSideWhitespaceStart !== rightSideWhitespaceEnd) {
|
||||
this.addFailure(this.createFailure(leftSideWhitespaceStart, rightSideWhitespaceEnd, Rule.TRAILING_FAILURE_STRING));
|
||||
ctx.addFailure(leftSideWhitespaceStart, rightSideWhitespaceEnd, Rule.TRAILING_FAILURE_STRING);
|
||||
}
|
||||
}
|
||||
super.visitNode(node);
|
||||
ts.forEachChild(node, recur);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import * as Lint from "tslint/lib";
|
||||
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.";
|
||||
@@ -9,34 +8,37 @@ export class Rule extends Lint.Rules.AbstractRule {
|
||||
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()));
|
||||
return this.applyWithFunction(sourceFile, walk);
|
||||
}
|
||||
}
|
||||
|
||||
class ObjectLiteralSpaceWalker extends Lint.RuleWalker {
|
||||
public visitNode(node: ts.Node) {
|
||||
function walk(ctx: Lint.WalkContext<void>): void {
|
||||
const { sourceFile } = ctx;
|
||||
ts.forEachChild(sourceFile, recur);
|
||||
function recur(node: ts.Node): void {
|
||||
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);
|
||||
}
|
||||
}
|
||||
check(node as ts.ObjectLiteralExpression);
|
||||
}
|
||||
ts.forEachChild(node, recur);
|
||||
}
|
||||
|
||||
function check(node: ts.ObjectLiteralExpression): void {
|
||||
const text = node.getText(sourceFile);
|
||||
if (!text.match(/^{[^\n]+}$/g)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (text.charAt(1) !== " ") {
|
||||
ctx.addFailureAtNode(node, Rule.LEADING_FAILURE_STRING);
|
||||
}
|
||||
if (text.charAt(2) === " ") {
|
||||
ctx.addFailureAt(node.pos + 2, 1, Rule.LEADING_EXCESS_FAILURE_STRING);
|
||||
}
|
||||
if (text.charAt(text.length - 2) !== " ") {
|
||||
ctx.addFailureAtNode(node, Rule.TRAILING_FAILURE_STRING);
|
||||
}
|
||||
if (text.charAt(text.length - 3) === " ") {
|
||||
ctx.addFailureAt(node.pos + node.getWidth() - 3, 1, Rule.TRAILING_EXCESS_FAILURE_STRING);
|
||||
}
|
||||
super.visitNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noImplicitAny": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"strictNullChecks": true,
|
||||
"module": "commonjs",
|
||||
"outDir": "../../built/local/tslint"
|
||||
}
|
||||
|
||||
@@ -1,34 +1,36 @@
|
||||
import * as Lint from "tslint/lib";
|
||||
import * as ts from "typescript";
|
||||
|
||||
|
||||
export class Rule extends Lint.Rules.AbstractRule {
|
||||
public static FAILURE_STRING = "The '|' and '&' operators must be surrounded by single spaces";
|
||||
|
||||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
||||
return this.applyWithWalker(new TypeOperatorSpacingWalker(sourceFile, this.getOptions()));
|
||||
return this.applyWithFunction(sourceFile, walk);
|
||||
}
|
||||
}
|
||||
|
||||
class TypeOperatorSpacingWalker extends Lint.RuleWalker {
|
||||
public visitNode(node: ts.Node) {
|
||||
function walk(ctx: Lint.WalkContext<void>): void {
|
||||
const { sourceFile } = ctx;
|
||||
ts.forEachChild(sourceFile, recur);
|
||||
function recur(node: ts.Node): void {
|
||||
if (node.kind === ts.SyntaxKind.UnionType || node.kind === ts.SyntaxKind.IntersectionType) {
|
||||
const types = (<ts.UnionOrIntersectionTypeNode>node).types;
|
||||
let expectedStart = types[0].end + 2; // space, | or &
|
||||
for (let i = 1; i < types.length; i++) {
|
||||
const currentType = types[i];
|
||||
if (expectedStart !== currentType.pos || currentType.getLeadingTriviaWidth() !== 1) {
|
||||
const sourceFile = currentType.getSourceFile();
|
||||
const previousTypeEndPos = sourceFile.getLineAndCharacterOfPosition(types[i - 1].end);
|
||||
const currentTypeStartPos = sourceFile.getLineAndCharacterOfPosition(currentType.pos);
|
||||
if (previousTypeEndPos.line === currentTypeStartPos.line) {
|
||||
const failure = this.createFailure(currentType.pos, currentType.getWidth(), Rule.FAILURE_STRING);
|
||||
this.addFailure(failure);
|
||||
}
|
||||
check((node as ts.UnionOrIntersectionTypeNode).types);
|
||||
}
|
||||
ts.forEachChild(node, recur);
|
||||
}
|
||||
|
||||
function check(types: ts.TypeNode[]): void {
|
||||
let expectedStart = types[0].end + 2; // space, | or &
|
||||
for (let i = 1; i < types.length; i++) {
|
||||
const currentType = types[i];
|
||||
if (expectedStart !== currentType.pos || currentType.getLeadingTriviaWidth() !== 1) {
|
||||
const previousTypeEndPos = sourceFile.getLineAndCharacterOfPosition(types[i - 1].end);
|
||||
const currentTypeStartPos = sourceFile.getLineAndCharacterOfPosition(currentType.pos);
|
||||
if (previousTypeEndPos.line === currentTypeStartPos.line) {
|
||||
ctx.addFailureAtNode(currentType, Rule.FAILURE_STRING);
|
||||
}
|
||||
expectedStart = currentType.end + 2;
|
||||
}
|
||||
expectedStart = currentType.end + 2;
|
||||
}
|
||||
super.visitNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
+129
-19
@@ -182,7 +182,7 @@ namespace ts {
|
||||
return bindSourceFile;
|
||||
|
||||
function bindInStrictMode(file: SourceFile, opts: CompilerOptions): boolean {
|
||||
if (opts.alwaysStrict && !isDeclarationFile(file)) {
|
||||
if ((opts.alwaysStrict === undefined ? opts.strict : opts.alwaysStrict) && !isDeclarationFile(file)) {
|
||||
// bind in strict mode source files with alwaysStrict option
|
||||
return true;
|
||||
}
|
||||
@@ -670,6 +670,12 @@ namespace ts {
|
||||
case SyntaxKind.CallExpression:
|
||||
bindCallExpressionFlow(<CallExpression>node);
|
||||
break;
|
||||
case SyntaxKind.JSDocComment:
|
||||
bindJSDocComment(<JSDoc>node);
|
||||
break;
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
bindJSDocTypedefTag(<JSDocTypedefTag>node);
|
||||
break;
|
||||
default:
|
||||
bindEachChild(node);
|
||||
break;
|
||||
@@ -1335,6 +1341,26 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function bindJSDocComment(node: JSDoc) {
|
||||
forEachChild(node, n => {
|
||||
if (n.kind !== SyntaxKind.JSDocTypedefTag) {
|
||||
bind(n);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function bindJSDocTypedefTag(node: JSDocTypedefTag) {
|
||||
forEachChild(node, n => {
|
||||
// if the node has a fullName "A.B.C", that means symbol "C" was already bound
|
||||
// when we visit "fullName"; so when we visit the name "C" as the next child of
|
||||
// the jsDocTypedefTag, we should skip binding it.
|
||||
if (node.fullName && n === node.name && node.fullName.kind !== SyntaxKind.Identifier) {
|
||||
return;
|
||||
}
|
||||
bind(n);
|
||||
});
|
||||
}
|
||||
|
||||
function bindCallExpressionFlow(node: CallExpression) {
|
||||
// If the target of the call expression is a function expression or arrow function we have
|
||||
// an immediately invoked function expression (IIFE). Initialize the flowNode property to
|
||||
@@ -1874,6 +1900,18 @@ namespace ts {
|
||||
}
|
||||
node.parent = parent;
|
||||
const saveInStrictMode = inStrictMode;
|
||||
|
||||
// Even though in the AST the jsdoc @typedef node belongs to the current node,
|
||||
// its symbol might be in the same scope with the current node's symbol. Consider:
|
||||
//
|
||||
// /** @typedef {string | number} MyType */
|
||||
// function foo();
|
||||
//
|
||||
// Here the current node is "foo", which is a container, but the scope of "MyType" should
|
||||
// not be inside "foo". Therefore we always bind @typedef before bind the parent node,
|
||||
// and skip binding this tag later when binding all the other jsdoc tags.
|
||||
bindJSDocTypedefTagIfAny(node);
|
||||
|
||||
// First we bind declaration nodes to a symbol if possible. We'll both create a symbol
|
||||
// and then potentially add the symbol to an appropriate symbol table. Possible
|
||||
// destination symbol tables are:
|
||||
@@ -1908,6 +1946,27 @@ namespace ts {
|
||||
inStrictMode = saveInStrictMode;
|
||||
}
|
||||
|
||||
function bindJSDocTypedefTagIfAny(node: Node) {
|
||||
if (!node.jsDoc) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const jsDoc of node.jsDoc) {
|
||||
if (!jsDoc.tags) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const tag of jsDoc.tags) {
|
||||
if (tag.kind === SyntaxKind.JSDocTypedefTag) {
|
||||
const savedParent = parent;
|
||||
parent = jsDoc;
|
||||
bind(tag);
|
||||
parent = savedParent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateStrictModeStatementList(statements: NodeArray<Statement>) {
|
||||
if (!inStrictMode) {
|
||||
for (const statement of statements) {
|
||||
@@ -2230,7 +2289,42 @@ namespace ts {
|
||||
declareSymbol(file.symbol.exports, file.symbol, <PropertyAccessExpression>node.left, SymbolFlags.Property | SymbolFlags.Export, SymbolFlags.None);
|
||||
}
|
||||
|
||||
function isExportsOrModuleExportsOrAlias(node: Node): boolean {
|
||||
return isExportsIdentifier(node) ||
|
||||
isModuleExportsPropertyAccessExpression(node) ||
|
||||
isNameOfExportsOrModuleExportsAliasDeclaration(node);
|
||||
}
|
||||
|
||||
function isNameOfExportsOrModuleExportsAliasDeclaration(node: Node) {
|
||||
if (node.kind === SyntaxKind.Identifier) {
|
||||
const symbol = container.locals.get((<Identifier>node).text);
|
||||
if (symbol && symbol.valueDeclaration && symbol.valueDeclaration.kind === SyntaxKind.VariableDeclaration) {
|
||||
const declaration = symbol.valueDeclaration as VariableDeclaration;
|
||||
if (declaration.initializer) {
|
||||
return isExportsOrModuleExportsOrAliasOrAssignemnt(declaration.initializer);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isExportsOrModuleExportsOrAliasOrAssignemnt(node: Node): boolean {
|
||||
return isExportsOrModuleExportsOrAlias(node) ||
|
||||
(isAssignmentExpression(node, /*excludeCompoundAssignements*/ true) && (isExportsOrModuleExportsOrAliasOrAssignemnt(node.left) || isExportsOrModuleExportsOrAliasOrAssignemnt(node.right)));
|
||||
}
|
||||
|
||||
function bindModuleExportsAssignment(node: BinaryExpression) {
|
||||
// A common practice in node modules is to set 'export = module.exports = {}', this ensures that 'exports'
|
||||
// is still pointing to 'module.exports'.
|
||||
// We do not want to consider this as 'export=' since a module can have only one of these.
|
||||
// Similarlly we do not want to treat 'module.exports = exports' as an 'export='.
|
||||
const assignedExpression = getRightMostAssignedExpression(node.right);
|
||||
if (isEmptyObjectLiteral(assignedExpression) || isExportsOrModuleExportsOrAlias(assignedExpression)) {
|
||||
// Mark it as a module in case there are no other exports in the file
|
||||
setCommonJsModuleIndicator(node);
|
||||
return;
|
||||
}
|
||||
|
||||
// 'module.exports = expr' assignment
|
||||
setCommonJsModuleIndicator(node);
|
||||
declareSymbol(file.symbol.exports, file.symbol, node, SymbolFlags.Property | SymbolFlags.Export | SymbolFlags.ValueModule, SymbolFlags.None);
|
||||
@@ -2238,23 +2332,30 @@ namespace ts {
|
||||
|
||||
function bindThisPropertyAssignment(node: BinaryExpression) {
|
||||
Debug.assert(isInJavaScriptFile(node));
|
||||
// Declare a 'member' if the container is an ES5 class or ES6 constructor
|
||||
if (container.kind === SyntaxKind.FunctionDeclaration || container.kind === SyntaxKind.FunctionExpression) {
|
||||
container.symbol.members = container.symbol.members || createMap<Symbol>();
|
||||
// It's acceptable for multiple 'this' assignments of the same identifier to occur
|
||||
declareSymbol(container.symbol.members, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property);
|
||||
}
|
||||
else if (container.kind === SyntaxKind.Constructor) {
|
||||
// this.foo assignment in a JavaScript class
|
||||
// Bind this property to the containing class
|
||||
const saveContainer = container;
|
||||
container = container.parent;
|
||||
const symbol = bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property, SymbolFlags.None);
|
||||
if (symbol) {
|
||||
// constructor-declared symbols can be overwritten by subsequent method declarations
|
||||
(symbol as Symbol).isReplaceableByMethod = true;
|
||||
}
|
||||
container = saveContainer;
|
||||
const container = getThisContainer(node, /*includeArrowFunctions*/false);
|
||||
switch (container.kind) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
// Declare a 'member' if the container is an ES5 class or ES6 constructor
|
||||
container.symbol.members = container.symbol.members || createMap<Symbol>();
|
||||
// It's acceptable for multiple 'this' assignments of the same identifier to occur
|
||||
declareSymbol(container.symbol.members, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property);
|
||||
break;
|
||||
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
// this.foo assignment in a JavaScript class
|
||||
// Bind this property to the containing class
|
||||
const containingClass = container.parent;
|
||||
const symbol = declareSymbol(hasModifier(container, ModifierFlags.Static) ? containingClass.symbol.exports : containingClass.symbol.members, containingClass.symbol, node, SymbolFlags.Property, SymbolFlags.None);
|
||||
if (symbol) {
|
||||
// symbols declared through 'this' property assignements can be overwritten by subsequent method declarations
|
||||
(symbol as Symbol).isReplaceableByMethod = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2287,11 +2388,20 @@ namespace ts {
|
||||
leftSideOfAssignment.parent = node;
|
||||
target.parent = leftSideOfAssignment;
|
||||
|
||||
bindPropertyAssignment(target.text, leftSideOfAssignment, /*isPrototypeProperty*/ false);
|
||||
if (isNameOfExportsOrModuleExportsAliasDeclaration(target)) {
|
||||
// This can be an alias for the 'exports' or 'module.exports' names, e.g.
|
||||
// var util = module.exports;
|
||||
// util.property = function ...
|
||||
bindExportsPropertyAssignment(node);
|
||||
}
|
||||
else {
|
||||
bindPropertyAssignment(target.text, leftSideOfAssignment, /*isPrototypeProperty*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
function bindPropertyAssignment(functionName: string, propertyAccessExpression: PropertyAccessExpression, isPrototypeProperty: boolean) {
|
||||
let targetSymbol = container.locals.get(functionName);
|
||||
|
||||
if (targetSymbol && isDeclarationOfFunctionOrClassExpression(targetSymbol)) {
|
||||
targetSymbol = (targetSymbol.valueDeclaration as VariableDeclaration).initializer.symbol;
|
||||
}
|
||||
|
||||
+438
-278
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
/// <reference path="sys.ts"/>
|
||||
/// <reference path="sys.ts"/>
|
||||
/// <reference path="types.ts"/>
|
||||
/// <reference path="core.ts"/>
|
||||
/// <reference path="diagnosticInformationMap.generated.ts"/>
|
||||
@@ -467,6 +467,11 @@ namespace ts {
|
||||
type: "boolean",
|
||||
description: Diagnostics.Parse_in_strict_mode_and_emit_use_strict_for_each_source_file
|
||||
},
|
||||
{
|
||||
name: "strict",
|
||||
type: "boolean",
|
||||
description: Diagnostics.Enable_all_strict_type_checks
|
||||
},
|
||||
{
|
||||
// A list of plugins to load in the language service
|
||||
name: "plugins",
|
||||
@@ -520,7 +525,7 @@ namespace ts {
|
||||
export const defaultInitCompilerOptions: CompilerOptions = {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
strict: true,
|
||||
sourceMap: false,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="types.ts"/>
|
||||
/// <reference path="types.ts"/>
|
||||
/// <reference path="performance.ts" />
|
||||
|
||||
namespace ts {
|
||||
@@ -84,7 +84,7 @@ namespace ts {
|
||||
this.index++;
|
||||
return { value: this.selector(this.data, this.keys[index]), done: false };
|
||||
}
|
||||
return { value: undefined as never, done: true }
|
||||
return { value: undefined as never, done: true };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ namespace ts {
|
||||
action(this.data[key], key);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createFileMap<T>(keyMapper?: (key: string) => string): FileMap<T> {
|
||||
|
||||
@@ -1164,7 +1164,7 @@ namespace ts {
|
||||
emitTypeParameters(node.typeParameters);
|
||||
const baseTypeNode = getClassExtendsHeritageClauseElement(node);
|
||||
if (baseTypeNode) {
|
||||
node.name
|
||||
node.name;
|
||||
emitHeritageClause(node.name, [baseTypeNode], /*isImplementsList*/ false);
|
||||
}
|
||||
emitHeritageClause(node.name, getClassImplementsHeritageClauseElements(node), /*isImplementsList*/ true);
|
||||
|
||||
@@ -2417,10 +2417,6 @@
|
||||
"category": "Error",
|
||||
"code": 5012
|
||||
},
|
||||
"Unsupported file encoding.": {
|
||||
"category": "Error",
|
||||
"code": 5013
|
||||
},
|
||||
"Failed to parse file '{0}': {1}.": {
|
||||
"category": "Error",
|
||||
"code": 5014
|
||||
@@ -3049,6 +3045,10 @@
|
||||
"category": "Message",
|
||||
"code": 6149
|
||||
},
|
||||
"Enable all strict type checks.": {
|
||||
"category": "Message",
|
||||
"code": 6150
|
||||
},
|
||||
"Variable '{0}' implicitly has an '{1}' type.": {
|
||||
"category": "Error",
|
||||
"code": 7005
|
||||
@@ -3273,7 +3273,7 @@
|
||||
"category": "Error",
|
||||
"code": 17011
|
||||
},
|
||||
"'{0}' is not a valid meta-property for keyword '{1}'. Did you mean '{0}'?": {
|
||||
"'{0}' is not a valid meta-property for keyword '{1}'. Did you mean '{2}'?": {
|
||||
"category": "Error",
|
||||
"code": 17012
|
||||
},
|
||||
|
||||
+33
-4
@@ -1,4 +1,4 @@
|
||||
/// <reference path="checker.ts" />
|
||||
/// <reference path="checker.ts" />
|
||||
/// <reference path="transformer.ts" />
|
||||
/// <reference path="declarationEmitter.ts" />
|
||||
/// <reference path="sourcemap.ts" />
|
||||
@@ -199,6 +199,8 @@ namespace ts {
|
||||
onEmitHelpers,
|
||||
onSetSourceFile,
|
||||
substituteNode,
|
||||
onBeforeEmitNodeArray,
|
||||
onAfterEmitNodeArray
|
||||
} = handlers;
|
||||
|
||||
const newLine = getNewLineCharacter(printerOptions);
|
||||
@@ -631,6 +633,11 @@ namespace ts {
|
||||
if (isExpression(node)) {
|
||||
return pipelineEmitExpression(trySubstituteNode(EmitHint.Expression, node));
|
||||
}
|
||||
|
||||
if (isToken(node)) {
|
||||
writeTokenText(kind);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function pipelineEmitExpression(node: Node): void {
|
||||
@@ -819,8 +826,8 @@ namespace ts {
|
||||
writeIfPresent(node.dotDotDotToken, "...");
|
||||
emit(node.name);
|
||||
writeIfPresent(node.questionToken, "?");
|
||||
emitExpressionWithPrefix(" = ", node.initializer);
|
||||
emitWithPrefix(": ", node.type);
|
||||
emitExpressionWithPrefix(" = ", node.initializer);
|
||||
}
|
||||
|
||||
function emitDecorator(decorator: Decorator) {
|
||||
@@ -1553,6 +1560,10 @@ namespace ts {
|
||||
emitSignatureAndBody(node, emitSignatureHead);
|
||||
}
|
||||
|
||||
function emitBlockCallback(_hint: EmitHint, body: Node): void {
|
||||
emitBlockFunctionBody(<Block>body);
|
||||
}
|
||||
|
||||
function emitSignatureAndBody(node: FunctionLikeDeclaration, emitSignatureHead: (node: SignatureDeclaration) => void) {
|
||||
const body = node.body;
|
||||
if (body) {
|
||||
@@ -1564,12 +1575,22 @@ namespace ts {
|
||||
|
||||
if (getEmitFlags(node) & EmitFlags.ReuseTempVariableScope) {
|
||||
emitSignatureHead(node);
|
||||
emitBlockFunctionBody(body);
|
||||
if (onEmitNode) {
|
||||
onEmitNode(EmitHint.Unspecified, body, emitBlockCallback);
|
||||
}
|
||||
else {
|
||||
emitBlockFunctionBody(body);
|
||||
}
|
||||
}
|
||||
else {
|
||||
pushNameGenerationScope();
|
||||
emitSignatureHead(node);
|
||||
emitBlockFunctionBody(body);
|
||||
if (onEmitNode) {
|
||||
onEmitNode(EmitHint.Unspecified, body, emitBlockCallback);
|
||||
}
|
||||
else {
|
||||
emitBlockFunctionBody(body);
|
||||
}
|
||||
popNameGenerationScope();
|
||||
}
|
||||
|
||||
@@ -2200,6 +2221,10 @@ namespace ts {
|
||||
write(getOpeningBracket(format));
|
||||
}
|
||||
|
||||
if (onBeforeEmitNodeArray) {
|
||||
onBeforeEmitNodeArray(children);
|
||||
}
|
||||
|
||||
if (isEmpty) {
|
||||
// Write a line terminator if the parent node was multi-line
|
||||
if (format & ListFormat.MultiLine) {
|
||||
@@ -2315,6 +2340,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
if (onAfterEmitNodeArray) {
|
||||
onAfterEmitNodeArray(children);
|
||||
}
|
||||
|
||||
if (format & ListFormat.BracketsMask) {
|
||||
write(getClosingBracket(format));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="core.ts"/>
|
||||
/// <reference path="core.ts"/>
|
||||
/// <reference path="utilities.ts"/>
|
||||
|
||||
namespace ts {
|
||||
@@ -1099,6 +1099,10 @@ namespace ts {
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createKeywordTypeNode(kind: KeywordTypeNode["kind"]): KeywordTypeNode {
|
||||
return <KeywordTypeNode>createSynthesizedNode(kind);
|
||||
}
|
||||
|
||||
export function createFunctionDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
|
||||
const node = <FunctionDeclaration>createSynthesizedNode(SyntaxKind.FunctionDeclaration);
|
||||
node.decorators = asNodeArray(decorators);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="core.ts" />
|
||||
/// <reference path="core.ts" />
|
||||
/// <reference path="diagnosticInformationMap.generated.ts" />
|
||||
|
||||
namespace ts {
|
||||
@@ -675,7 +675,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache): ResolvedModuleWithFailedLookupLocations {
|
||||
return nodeModuleNameResolverWorker(moduleName, containingFile, compilerOptions, host, cache, /* jsOnly*/ false);
|
||||
return nodeModuleNameResolverWorker(moduleName, containingFile, compilerOptions, host, cache, /*jsOnly*/ false);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -962,7 +962,7 @@ namespace ts {
|
||||
const result = cache && cache.get(containingDirectory);
|
||||
if (result) {
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache, moduleName)
|
||||
trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache, moduleName);
|
||||
}
|
||||
return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, extension: result.resolvedModule.extension } };
|
||||
}
|
||||
|
||||
+28
-24
@@ -1309,7 +1309,7 @@ namespace ts {
|
||||
case ParsingContext.ObjectBindingElements:
|
||||
return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName();
|
||||
case ParsingContext.HeritageClauseElement:
|
||||
// If we see { } then only consume it as an expression if it is followed by , or {
|
||||
// If we see `{ ... }` then only consume it as an expression if it is followed by `,` or `{`
|
||||
// That way we won't consume the body of a class in its heritage clause.
|
||||
if (token() === SyntaxKind.OpenBraceToken) {
|
||||
return lookAhead(isValidHeritageClauseObjectLiteral);
|
||||
@@ -2113,7 +2113,7 @@ namespace ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseTypeParameters(): NodeArray<TypeParameterDeclaration> {
|
||||
function parseTypeParameters(): NodeArray<TypeParameterDeclaration> | undefined {
|
||||
if (token() === SyntaxKind.LessThanToken) {
|
||||
return parseBracketedList(ParsingContext.TypeParameters, parseTypeParameter, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken);
|
||||
}
|
||||
@@ -2183,7 +2183,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function fillSignature(
|
||||
returnToken: SyntaxKind,
|
||||
returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken,
|
||||
yieldContext: boolean,
|
||||
awaitContext: boolean,
|
||||
requireCompleteParameterList: boolean,
|
||||
@@ -2373,14 +2373,14 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isTypeMemberStart(): boolean {
|
||||
let idToken: SyntaxKind;
|
||||
// Return true if we have the start of a signature member
|
||||
if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
|
||||
return true;
|
||||
}
|
||||
let idToken: boolean;
|
||||
// Eat up all modifiers, but hold on to the last one in case it is actually an identifier
|
||||
while (isModifierKind(token())) {
|
||||
idToken = token();
|
||||
idToken = true;
|
||||
nextToken();
|
||||
}
|
||||
// Index signatures and computed property names are type members
|
||||
@@ -2389,7 +2389,7 @@ namespace ts {
|
||||
}
|
||||
// Try to get the first property-like token following all modifiers
|
||||
if (isLiteralPropertyName()) {
|
||||
idToken = token();
|
||||
idToken = true;
|
||||
nextToken();
|
||||
}
|
||||
// If we were able to get any potential identifier, check that it is
|
||||
@@ -2497,7 +2497,7 @@ namespace ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseKeywordAndNoDot(): TypeNode {
|
||||
function parseKeywordAndNoDot(): TypeNode | undefined {
|
||||
const node = parseTokenNode<TypeNode>();
|
||||
return token() === SyntaxKind.DotToken ? undefined : node;
|
||||
}
|
||||
@@ -2635,7 +2635,7 @@ namespace ts {
|
||||
return parseArrayTypeOrHigher();
|
||||
}
|
||||
|
||||
function parseUnionOrIntersectionType(kind: SyntaxKind, parseConstituentType: () => TypeNode, operator: SyntaxKind): TypeNode {
|
||||
function parseUnionOrIntersectionType(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, parseConstituentType: () => TypeNode, operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken): TypeNode {
|
||||
parseOptional(operator);
|
||||
let type = parseConstituentType();
|
||||
if (token() === operator) {
|
||||
@@ -3863,6 +3863,9 @@ namespace ts {
|
||||
parseErrorAtPosition(openingTagName.pos, openingTagName.end - openingTagName.pos, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTagName));
|
||||
break;
|
||||
}
|
||||
else if (token() === SyntaxKind.ConflictMarkerTrivia) {
|
||||
break;
|
||||
}
|
||||
result.push(parseJsxChild());
|
||||
}
|
||||
|
||||
@@ -5281,8 +5284,8 @@ namespace ts {
|
||||
*
|
||||
* In such situations, 'permitInvalidConstAsModifier' should be set to true.
|
||||
*/
|
||||
function parseModifiers(permitInvalidConstAsModifier?: boolean): NodeArray<Modifier> {
|
||||
let modifiers: NodeArray<Modifier>;
|
||||
function parseModifiers(permitInvalidConstAsModifier?: boolean): NodeArray<Modifier> | undefined {
|
||||
let modifiers: NodeArray<Modifier> | undefined;
|
||||
while (true) {
|
||||
const modifierStart = scanner.getStartPos();
|
||||
const modifierKind = token();
|
||||
@@ -5422,7 +5425,7 @@ namespace ts {
|
||||
return token() === SyntaxKind.ImplementsKeyword && lookAhead(nextTokenIsIdentifierOrKeyword);
|
||||
}
|
||||
|
||||
function parseHeritageClauses(): NodeArray<HeritageClause> {
|
||||
function parseHeritageClauses(): NodeArray<HeritageClause> | undefined {
|
||||
// ClassTail[Yield,Await] : (Modified) See 14.5
|
||||
// ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt }
|
||||
|
||||
@@ -5433,7 +5436,7 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function parseHeritageClause() {
|
||||
function parseHeritageClause(): HeritageClause | undefined {
|
||||
if (token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword) {
|
||||
const node = <HeritageClause>createNode(SyntaxKind.HeritageClause);
|
||||
node.token = token();
|
||||
@@ -5459,7 +5462,7 @@ namespace ts {
|
||||
return token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword;
|
||||
}
|
||||
|
||||
function parseClassMembers() {
|
||||
function parseClassMembers(): NodeArray<ClassElement> {
|
||||
return parseList(ParsingContext.ClassMembers, parseClassElement);
|
||||
}
|
||||
|
||||
@@ -5618,17 +5621,7 @@ namespace ts {
|
||||
if (isIdentifier()) {
|
||||
identifier = parseIdentifier();
|
||||
if (token() !== SyntaxKind.CommaToken && token() !== SyntaxKind.FromKeyword) {
|
||||
// ImportEquals declaration of type:
|
||||
// import x = require("mod"); or
|
||||
// import x = M.x;
|
||||
const importEqualsDeclaration = <ImportEqualsDeclaration>createNode(SyntaxKind.ImportEqualsDeclaration, fullStart);
|
||||
importEqualsDeclaration.decorators = decorators;
|
||||
importEqualsDeclaration.modifiers = modifiers;
|
||||
importEqualsDeclaration.name = identifier;
|
||||
parseExpected(SyntaxKind.EqualsToken);
|
||||
importEqualsDeclaration.moduleReference = parseModuleReference();
|
||||
parseSemicolon();
|
||||
return addJSDocComment(finishNode(importEqualsDeclaration));
|
||||
return parseImportEqualsDeclaration(fullStart, decorators, modifiers, identifier);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5652,6 +5645,17 @@ namespace ts {
|
||||
return finishNode(importDeclaration);
|
||||
}
|
||||
|
||||
function parseImportEqualsDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: NodeArray<Modifier>, identifier: ts.Identifier): ImportEqualsDeclaration {
|
||||
const importEqualsDeclaration = <ImportEqualsDeclaration>createNode(SyntaxKind.ImportEqualsDeclaration, fullStart);
|
||||
importEqualsDeclaration.decorators = decorators;
|
||||
importEqualsDeclaration.modifiers = modifiers;
|
||||
importEqualsDeclaration.name = identifier;
|
||||
parseExpected(SyntaxKind.EqualsToken);
|
||||
importEqualsDeclaration.moduleReference = parseModuleReference();
|
||||
parseSemicolon();
|
||||
return addJSDocComment(finishNode(importEqualsDeclaration));
|
||||
}
|
||||
|
||||
function parseImportClause(identifier: Identifier, fullStart: number) {
|
||||
// ImportClause:
|
||||
// ImportedDefaultBinding
|
||||
|
||||
+45
-8
@@ -87,9 +87,6 @@ namespace ts {
|
||||
return sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
}
|
||||
|
||||
// returned by CScript sys environment
|
||||
const unsupportedFileEncodingErrorCode = -2147024809;
|
||||
|
||||
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile {
|
||||
let text: string;
|
||||
try {
|
||||
@@ -100,9 +97,7 @@ namespace ts {
|
||||
}
|
||||
catch (e) {
|
||||
if (onError) {
|
||||
onError(e.number === unsupportedFileEncodingErrorCode
|
||||
? createCompilerDiagnostic(Diagnostics.Unsupported_file_encoding).messageText
|
||||
: e.message);
|
||||
onError(e.message);
|
||||
}
|
||||
text = "";
|
||||
}
|
||||
@@ -290,6 +285,11 @@ namespace ts {
|
||||
return resolutions;
|
||||
}
|
||||
|
||||
interface DiagnosticCache {
|
||||
perFile?: FileMap<Diagnostic[]>;
|
||||
allDiagnostics?: Diagnostic[];
|
||||
}
|
||||
|
||||
export function createProgram(rootNames: string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program): Program {
|
||||
let program: Program;
|
||||
let files: SourceFile[] = [];
|
||||
@@ -298,6 +298,9 @@ namespace ts {
|
||||
let noDiagnosticsTypeChecker: TypeChecker;
|
||||
let classifiableNames: Map<string>;
|
||||
|
||||
const cachedSemanticDiagnosticsForFile: DiagnosticCache = {};
|
||||
const cachedDeclarationDiagnosticsForFile: DiagnosticCache = {};
|
||||
|
||||
let resolvedTypeReferenceDirectives = createMap<ResolvedTypeReferenceDirective>();
|
||||
let fileProcessingDiagnostics = createDiagnosticCollection();
|
||||
|
||||
@@ -899,6 +902,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getSemanticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
|
||||
return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedSemanticDiagnosticsForFile, getSemanticDiagnosticsForFileNoCache);
|
||||
}
|
||||
|
||||
function getSemanticDiagnosticsForFileNoCache(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
|
||||
return runWithCancellationToken(() => {
|
||||
const typeChecker = getDiagnosticsProducingTypeChecker();
|
||||
|
||||
@@ -1094,7 +1101,11 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
function getDeclarationDiagnosticsWorker(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
|
||||
function getDeclarationDiagnosticsWorker(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken): Diagnostic[] {
|
||||
return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedDeclarationDiagnosticsForFile, getDeclarationDiagnosticsForFileNoCache);
|
||||
}
|
||||
|
||||
function getDeclarationDiagnosticsForFileNoCache(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken) {
|
||||
return runWithCancellationToken(() => {
|
||||
const resolver = getDiagnosticsProducingTypeChecker().getEmitResolver(sourceFile, cancellationToken);
|
||||
// Don't actually write any files since we're just getting diagnostics.
|
||||
@@ -1102,6 +1113,32 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
function getAndCacheDiagnostics(
|
||||
sourceFile: SourceFile | undefined,
|
||||
cancellationToken: CancellationToken,
|
||||
cache: DiagnosticCache,
|
||||
getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken) => Diagnostic[]) {
|
||||
|
||||
const cachedResult = sourceFile
|
||||
? cache.perFile && cache.perFile.get(sourceFile.path)
|
||||
: cache.allDiagnostics;
|
||||
|
||||
if (cachedResult) {
|
||||
return cachedResult;
|
||||
}
|
||||
const result = getDiagnostics(sourceFile, cancellationToken) || emptyArray;
|
||||
if (sourceFile) {
|
||||
if (!cache.perFile) {
|
||||
cache.perFile = createFileMap<Diagnostic[]>();
|
||||
}
|
||||
cache.perFile.set(sourceFile.path, result);
|
||||
}
|
||||
else {
|
||||
cache.allDiagnostics = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
|
||||
return isDeclarationFile(sourceFile) ? [] : getDeclarationDiagnosticsWorker(sourceFile, cancellationToken);
|
||||
}
|
||||
@@ -1630,7 +1667,7 @@ namespace ts {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "lib", "noLib"));
|
||||
}
|
||||
|
||||
if (options.noImplicitUseStrict && options.alwaysStrict) {
|
||||
if (options.noImplicitUseStrict && (options.alwaysStrict === undefined ? options.strict : options.alwaysStrict)) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noImplicitUseStrict", "alwaysStrict"));
|
||||
}
|
||||
|
||||
|
||||
@@ -333,7 +333,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function getLineStarts(sourceFile: SourceFile): number[] {
|
||||
export function getLineStarts(sourceFile: SourceFileLike): number[] {
|
||||
return sourceFile.lineMap || (sourceFile.lineMap = computeLineStarts(sourceFile.text));
|
||||
}
|
||||
|
||||
@@ -1716,7 +1716,14 @@ namespace ts {
|
||||
while (pos < end) {
|
||||
pos++;
|
||||
char = text.charCodeAt(pos);
|
||||
if ((char === CharacterCodes.openBrace) || (char === CharacterCodes.lessThan)) {
|
||||
if (char === CharacterCodes.openBrace) {
|
||||
break;
|
||||
}
|
||||
if (char === CharacterCodes.lessThan) {
|
||||
if (isConflictMarkerTrivia(text, pos)) {
|
||||
pos = scanConflictMarkerTrivia(text, pos, error);
|
||||
return token = SyntaxKind.ConflictMarkerTrivia;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-158
@@ -1,4 +1,4 @@
|
||||
/// <reference path="core.ts"/>
|
||||
/// <reference path="core.ts"/>
|
||||
|
||||
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
|
||||
declare function clearTimeout(handle: any): void;
|
||||
@@ -74,13 +74,6 @@ namespace ts {
|
||||
return parseInt(version.substring(1, dot));
|
||||
}
|
||||
|
||||
declare class Enumerator {
|
||||
public atEnd(): boolean;
|
||||
public moveNext(): boolean;
|
||||
public item(): any;
|
||||
constructor(o: any);
|
||||
}
|
||||
|
||||
declare var ChakraHost: {
|
||||
args: string[];
|
||||
currentDirectory: string;
|
||||
@@ -104,152 +97,6 @@ namespace ts {
|
||||
};
|
||||
|
||||
export let 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*/;
|
||||
|
||||
const binaryStream = new ActiveXObject("ADODB.Stream");
|
||||
binaryStream.Type = 1 /*binary*/;
|
||||
|
||||
const args: string[] = [];
|
||||
for (let i = 0; i < WScript.Arguments.length; i++) {
|
||||
args[i] = WScript.Arguments.Item(i);
|
||||
}
|
||||
|
||||
function readFile(fileName: string, encoding?: string): string {
|
||||
if (!fso.FileExists(fileName)) {
|
||||
return undefined;
|
||||
}
|
||||
fileStream.Open();
|
||||
try {
|
||||
if (encoding) {
|
||||
fileStream.Charset = encoding;
|
||||
fileStream.LoadFromFile(fileName);
|
||||
}
|
||||
else {
|
||||
// Load file and read the first two bytes into a string with no interpretation
|
||||
fileStream.Charset = "x-ansi";
|
||||
fileStream.LoadFromFile(fileName);
|
||||
const bom = fileStream.ReadText(2) || "";
|
||||
// Position must be at 0 before encoding can be changed
|
||||
fileStream.Position = 0;
|
||||
// [0xFF,0xFE] and [0xFE,0xFF] mean utf-16 (little or big endian), otherwise default to utf-8
|
||||
fileStream.Charset = bom.length >= 2 && (bom.charCodeAt(0) === 0xFF && bom.charCodeAt(1) === 0xFE || bom.charCodeAt(0) === 0xFE && bom.charCodeAt(1) === 0xFF) ? "unicode" : "utf-8";
|
||||
}
|
||||
// ReadText method always strips byte order mark from resulting string
|
||||
return fileStream.ReadText();
|
||||
}
|
||||
catch (e) {
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
fileStream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
function writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void {
|
||||
fileStream.Open();
|
||||
binaryStream.Open();
|
||||
try {
|
||||
// Write characters in UTF-8 encoding
|
||||
fileStream.Charset = "utf-8";
|
||||
fileStream.WriteText(data);
|
||||
// If we don't want the BOM, then skip it by setting the starting location to 3 (size of BOM).
|
||||
// If not, start from position 0, as the BOM will be added automatically when charset==utf8.
|
||||
if (writeByteOrderMark) {
|
||||
fileStream.Position = 0;
|
||||
}
|
||||
else {
|
||||
fileStream.Position = 3;
|
||||
}
|
||||
fileStream.CopyTo(binaryStream);
|
||||
binaryStream.SaveToFile(fileName, 2 /*overwrite*/);
|
||||
}
|
||||
finally {
|
||||
binaryStream.Close();
|
||||
fileStream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
function getNames(collection: any): string[] {
|
||||
const result: string[] = [];
|
||||
for (const e = new Enumerator(collection); !e.atEnd(); e.moveNext()) {
|
||||
result.push(e.item().Name);
|
||||
}
|
||||
return result.sort();
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
const wscriptSystem: System = {
|
||||
args,
|
||||
newLine: "\r\n",
|
||||
useCaseSensitiveFileNames: false,
|
||||
write(s: string): void {
|
||||
WScript.StdOut.Write(s);
|
||||
},
|
||||
readFile,
|
||||
writeFile,
|
||||
resolvePath(path: string): string {
|
||||
return fso.GetAbsolutePathName(path);
|
||||
},
|
||||
fileExists(path: string): boolean {
|
||||
return fso.FileExists(path);
|
||||
},
|
||||
directoryExists(path: string) {
|
||||
return fso.FolderExists(path);
|
||||
},
|
||||
createDirectory(directoryName: string) {
|
||||
if (!wscriptSystem.directoryExists(directoryName)) {
|
||||
fso.CreateFolder(directoryName);
|
||||
}
|
||||
},
|
||||
getExecutingFilePath() {
|
||||
return WScript.ScriptFullName;
|
||||
},
|
||||
getCurrentDirectory() {
|
||||
return shell.CurrentDirectory;
|
||||
},
|
||||
getDirectories,
|
||||
getEnvironmentVariable(name: string) {
|
||||
return new ActiveXObject("WScript.Shell").ExpandEnvironmentStrings(`%${name}%`);
|
||||
},
|
||||
readDirectory,
|
||||
exit(exitCode?: number): void {
|
||||
try {
|
||||
WScript.Quit(exitCode);
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
}
|
||||
};
|
||||
return wscriptSystem;
|
||||
}
|
||||
|
||||
function getNodeSystem(): System {
|
||||
const _fs = require("fs");
|
||||
const _path = require("path");
|
||||
@@ -355,7 +202,7 @@ namespace ts {
|
||||
if (len >= 2 && buffer[0] === 0xFE && buffer[1] === 0xFF) {
|
||||
// Big endian UTF-16 byte order mark detected. Since big endian is not supported by node.js,
|
||||
// flip all byte pairs and treat as little endian.
|
||||
len &= ~1;
|
||||
len &= ~1; // Round down to a multiple of 2
|
||||
for (let i = 0; i < len; i += 2) {
|
||||
const temp = buffer[i];
|
||||
buffer[i] = buffer[i + 1];
|
||||
@@ -646,9 +493,6 @@ namespace ts {
|
||||
if (typeof ChakraHost !== "undefined") {
|
||||
sys = getChakraSystem();
|
||||
}
|
||||
else if (typeof WScript !== "undefined" && typeof ActiveXObject === "function") {
|
||||
sys = getWScriptSystem();
|
||||
}
|
||||
else if (typeof process !== "undefined" && process.nextTick && !process.browser && typeof require !== "undefined") {
|
||||
// process and process.nextTick checks if current environment is node-like
|
||||
// process.browser check excludes webpack and browserify
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="visitor.ts" />
|
||||
/// <reference path="visitor.ts" />
|
||||
/// <reference path="transformers/ts.ts" />
|
||||
/// <reference path="transformers/jsx.ts" />
|
||||
/// <reference path="transformers/esnext.ts" />
|
||||
@@ -121,13 +121,13 @@ namespace ts {
|
||||
enableEmitNotification,
|
||||
isSubstitutionEnabled,
|
||||
isEmitNotificationEnabled,
|
||||
get onSubstituteNode() { return onSubstituteNode },
|
||||
get onSubstituteNode() { return onSubstituteNode; },
|
||||
set onSubstituteNode(value) {
|
||||
Debug.assert(state < TransformationState.Initialized, "Cannot modify transformation hooks after initialization has completed.");
|
||||
Debug.assert(value !== undefined, "Value must not be 'undefined'");
|
||||
onSubstituteNode = value;
|
||||
},
|
||||
get onEmitNode() { return onEmitNode },
|
||||
get onEmitNode() { return onEmitNode; },
|
||||
set onEmitNode(value) {
|
||||
Debug.assert(state < TransformationState.Initialized, "Cannot modify transformation hooks after initialization has completed.");
|
||||
Debug.assert(value !== undefined, "Value must not be 'undefined'");
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace ts {
|
||||
let value: Expression;
|
||||
if (isDestructuringAssignment(node)) {
|
||||
value = node.right;
|
||||
while (isEmptyObjectLiteralOrArrayLiteral(node.left)) {
|
||||
while (isEmptyArrayLiteral(node.left) || isEmptyObjectLiteral(node.left)) {
|
||||
if (isDestructuringAssignment(value)) {
|
||||
location = node = value;
|
||||
value = node.right;
|
||||
|
||||
@@ -2690,7 +2690,7 @@ namespace ts {
|
||||
if (loopOutParameters.length) {
|
||||
copyOutParameters(loopOutParameters, CopyDirection.ToOutParameter, statements);
|
||||
}
|
||||
addRange(statements, lexicalEnvironment)
|
||||
addRange(statements, lexicalEnvironment);
|
||||
loopBody = createBlock(statements, /*multiline*/ true);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="../factory.ts" />
|
||||
/// <reference path="../factory.ts" />
|
||||
/// <reference path="../visitor.ts" />
|
||||
|
||||
// Transforms generator functions into a compatible ES5 representation with similar runtime
|
||||
@@ -1942,7 +1942,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function substituteExpressionIdentifier(node: Identifier) {
|
||||
if (renamedCatchVariables && renamedCatchVariables.has(node.text)) {
|
||||
if (!isGeneratedIdentifier(node) && renamedCatchVariables && renamedCatchVariables.has(node.text)) {
|
||||
const original = getOriginalNode(node);
|
||||
if (isIdentifier(original) && original.parent) {
|
||||
const declaration = resolver.getReferencedValueDeclaration(original);
|
||||
@@ -2108,17 +2108,24 @@ namespace ts {
|
||||
function beginCatchBlock(variable: VariableDeclaration): void {
|
||||
Debug.assert(peekBlockKind() === CodeBlockKind.Exception);
|
||||
|
||||
const text = (<Identifier>variable.name).text;
|
||||
const name = declareLocal(text);
|
||||
|
||||
if (!renamedCatchVariables) {
|
||||
renamedCatchVariables = createMap<boolean>();
|
||||
renamedCatchVariableDeclarations = [];
|
||||
context.enableSubstitution(SyntaxKind.Identifier);
|
||||
// generated identifiers should already be unique within a file
|
||||
let name: Identifier;
|
||||
if (isGeneratedIdentifier(variable.name)) {
|
||||
name = variable.name;
|
||||
hoistVariableDeclaration(variable.name);
|
||||
}
|
||||
else {
|
||||
const text = (<Identifier>variable.name).text;
|
||||
name = declareLocal(text);
|
||||
if (!renamedCatchVariables) {
|
||||
renamedCatchVariables = createMap<boolean>();
|
||||
renamedCatchVariableDeclarations = [];
|
||||
context.enableSubstitution(SyntaxKind.Identifier);
|
||||
}
|
||||
|
||||
renamedCatchVariables.set(text, true);
|
||||
renamedCatchVariableDeclarations[getOriginalNodeId(variable)] = name;
|
||||
renamedCatchVariables.set(text, true);
|
||||
renamedCatchVariableDeclarations[getOriginalNodeId(variable)] = name;
|
||||
}
|
||||
|
||||
const exception = <ExceptionBlock>peekBlock();
|
||||
Debug.assert(exception.state < ExceptionBlockState.Catch);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="../../factory.ts" />
|
||||
/// <reference path="../../factory.ts" />
|
||||
/// <reference path="../../visitor.ts" />
|
||||
/// <reference path="../destructuring.ts" />
|
||||
|
||||
@@ -55,9 +55,7 @@ namespace ts {
|
||||
* @param node The SourceFile node.
|
||||
*/
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
if (isDeclarationFile(node)
|
||||
|| !(isExternalModule(node)
|
||||
|| compilerOptions.isolatedModules)) {
|
||||
if (isDeclarationFile(node) || !(isExternalModule(node) || compilerOptions.isolatedModules)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -74,6 +72,14 @@ namespace ts {
|
||||
return aggregateTransformFlags(updated);
|
||||
}
|
||||
|
||||
|
||||
function shouldEmitUnderscoreUnderscoreESModule() {
|
||||
if (!currentModuleInfo.exportEquals && isExternalModule(currentSourceFile)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a SourceFile into a CommonJS module.
|
||||
*
|
||||
@@ -83,9 +89,10 @@ namespace ts {
|
||||
startLexicalEnvironment();
|
||||
|
||||
const statements: Statement[] = [];
|
||||
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor);
|
||||
const ensureUseStrict = compilerOptions.alwaysStrict || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile));
|
||||
const statementOffset = addPrologueDirectives(statements, node.statements, ensureUseStrict, sourceElementVisitor);
|
||||
|
||||
if (!currentModuleInfo.exportEquals) {
|
||||
if (shouldEmitUnderscoreUnderscoreESModule()) {
|
||||
append(statements, createUnderscoreUnderscoreESModule());
|
||||
}
|
||||
|
||||
@@ -378,7 +385,7 @@ namespace ts {
|
||||
const statements: Statement[] = [];
|
||||
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor);
|
||||
|
||||
if (!currentModuleInfo.exportEquals) {
|
||||
if (shouldEmitUnderscoreUnderscoreESModule()) {
|
||||
append(statements, createUnderscoreUnderscoreESModule());
|
||||
}
|
||||
|
||||
@@ -1152,7 +1159,7 @@ namespace ts {
|
||||
createIdentifier("__esModule"),
|
||||
createLiteral(true)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
statement = createStatement(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="../../factory.ts" />
|
||||
/// <reference path="../../factory.ts" />
|
||||
/// <reference path="../../visitor.ts" />
|
||||
/// <reference path="../destructuring.ts" />
|
||||
|
||||
@@ -225,7 +225,8 @@ namespace ts {
|
||||
startLexicalEnvironment();
|
||||
|
||||
// Add any prologue directives.
|
||||
const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor);
|
||||
const ensureUseStrict = compilerOptions.alwaysStrict || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile));
|
||||
const statementOffset = addPrologueDirectives(statements, node.statements, ensureUseStrict, sourceElementVisitor);
|
||||
|
||||
// var __moduleName = context_1 && context_1.id;
|
||||
statements.push(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="../factory.ts" />
|
||||
/// <reference path="../factory.ts" />
|
||||
/// <reference path="../visitor.ts" />
|
||||
/// <reference path="./destructuring.ts" />
|
||||
|
||||
@@ -472,7 +472,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function visitSourceFile(node: SourceFile) {
|
||||
const alwaysStrict = compilerOptions.alwaysStrict && !(isExternalModule(node) && moduleKind === ModuleKind.ES2015);
|
||||
const alwaysStrict = (compilerOptions.alwaysStrict === undefined ? compilerOptions.strict : compilerOptions.alwaysStrict) &&
|
||||
!(isExternalModule(node) && moduleKind === ModuleKind.ES2015);
|
||||
return updateSourceFileNode(
|
||||
node,
|
||||
visitLexicalEnvironment(node.statements, sourceElementVisitor, context, /*start*/ 0, alwaysStrict));
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/// <reference path="program.ts"/>
|
||||
/// <reference path="program.ts"/>
|
||||
/// <reference path="commandLineParser.ts"/>
|
||||
|
||||
namespace ts {
|
||||
|
||||
+78
-24
@@ -1,4 +1,4 @@
|
||||
namespace ts {
|
||||
namespace ts {
|
||||
/**
|
||||
* Type of objects whose values are all of the same type.
|
||||
* The `in` and `for-in` operators can *not* be safely used,
|
||||
@@ -381,9 +381,6 @@
|
||||
JSDocPropertyTag,
|
||||
JSDocTypeLiteral,
|
||||
JSDocLiteralType,
|
||||
JSDocNullKeyword,
|
||||
JSDocUndefinedKeyword,
|
||||
JSDocNeverKeyword,
|
||||
|
||||
// Synthesized list
|
||||
SyntaxList,
|
||||
@@ -423,9 +420,9 @@
|
||||
LastBinaryOperator = CaretEqualsToken,
|
||||
FirstNode = QualifiedName,
|
||||
FirstJSDocNode = JSDocTypeExpression,
|
||||
LastJSDocNode = JSDocNeverKeyword,
|
||||
LastJSDocNode = JSDocLiteralType,
|
||||
FirstJSDocTagNode = JSDocComment,
|
||||
LastJSDocTagNode = JSDocNeverKeyword
|
||||
LastJSDocTagNode = JSDocLiteralType
|
||||
}
|
||||
|
||||
export const enum NodeFlags {
|
||||
@@ -522,6 +519,8 @@
|
||||
/* @internal */ localSymbol?: Symbol; // Local symbol declared by node (initialized by binding only for exported nodes)
|
||||
/* @internal */ flowNode?: FlowNode; // Associated FlowNode (initialized by binding)
|
||||
/* @internal */ emitNode?: EmitNode; // Associated EmitNode (initialized by transforms)
|
||||
/* @internal */ contextualType?: Type; // Used to temporarily assign a contextual type during overload resolution
|
||||
/* @internal */ contextualMapper?: TypeMapper; // Mapper for contextual type
|
||||
}
|
||||
|
||||
export interface NodeArray<T extends Node> extends Array<T>, TextRange {
|
||||
@@ -624,6 +623,7 @@
|
||||
|
||||
export interface TypeParameterDeclaration extends Declaration {
|
||||
kind: SyntaxKind.TypeParameter;
|
||||
parent?: DeclarationWithTypeParameters;
|
||||
name: Identifier;
|
||||
constraint?: TypeNode;
|
||||
default?: TypeNode;
|
||||
@@ -651,7 +651,7 @@
|
||||
|
||||
export interface VariableDeclaration extends Declaration {
|
||||
kind: SyntaxKind.VariableDeclaration;
|
||||
parent?: VariableDeclarationList;
|
||||
parent?: VariableDeclarationList | CatchClause;
|
||||
name: BindingName; // Declared variable name
|
||||
type?: TypeNode; // Optional type annotation
|
||||
initializer?: Expression; // Optional initializer
|
||||
@@ -659,11 +659,13 @@
|
||||
|
||||
export interface VariableDeclarationList extends Node {
|
||||
kind: SyntaxKind.VariableDeclarationList;
|
||||
parent?: VariableStatement | ForStatement | ForOfStatement | ForInStatement;
|
||||
declarations: NodeArray<VariableDeclaration>;
|
||||
}
|
||||
|
||||
export interface ParameterDeclaration extends Declaration {
|
||||
kind: SyntaxKind.Parameter;
|
||||
parent?: SignatureDeclaration;
|
||||
dotDotDotToken?: DotDotDotToken; // Present on rest parameter
|
||||
name: BindingName; // Declared parameter name
|
||||
questionToken?: QuestionToken; // Present on optional parameter
|
||||
@@ -673,6 +675,7 @@
|
||||
|
||||
export interface BindingElement extends Declaration {
|
||||
kind: SyntaxKind.BindingElement;
|
||||
parent?: BindingPattern;
|
||||
propertyName?: PropertyName; // Binding property name (in object binding pattern)
|
||||
dotDotDotToken?: DotDotDotToken; // Present on rest element (in object binding pattern)
|
||||
name: BindingName; // Declared binding element name
|
||||
@@ -754,11 +757,13 @@
|
||||
|
||||
export interface ObjectBindingPattern extends Node {
|
||||
kind: SyntaxKind.ObjectBindingPattern;
|
||||
parent?: VariableDeclaration | ParameterDeclaration | BindingElement;
|
||||
elements: NodeArray<BindingElement>;
|
||||
}
|
||||
|
||||
export interface ArrayBindingPattern extends Node {
|
||||
kind: SyntaxKind.ArrayBindingPattern;
|
||||
parent?: VariableDeclaration | ParameterDeclaration | BindingElement;
|
||||
elements: NodeArray<ArrayBindingElement>;
|
||||
}
|
||||
|
||||
@@ -960,7 +965,6 @@
|
||||
|
||||
export interface Expression extends Node {
|
||||
_expressionBrand: any;
|
||||
contextualType?: Type; // Used to temporarily assign a contextual type during overload resolution
|
||||
}
|
||||
|
||||
export interface OmittedExpression extends Expression {
|
||||
@@ -1327,14 +1331,17 @@
|
||||
|
||||
export interface TemplateHead extends LiteralLikeNode {
|
||||
kind: SyntaxKind.TemplateHead;
|
||||
parent?: TemplateExpression;
|
||||
}
|
||||
|
||||
export interface TemplateMiddle extends LiteralLikeNode {
|
||||
kind: SyntaxKind.TemplateMiddle;
|
||||
parent?: TemplateSpan;
|
||||
}
|
||||
|
||||
export interface TemplateTail extends LiteralLikeNode {
|
||||
kind: SyntaxKind.TemplateTail;
|
||||
parent?: TemplateSpan;
|
||||
}
|
||||
|
||||
export type TemplateLiteral = TemplateExpression | NoSubstitutionTemplateLiteral;
|
||||
@@ -1349,6 +1356,7 @@
|
||||
// The template literal must have kind TemplateMiddleLiteral or TemplateTailLiteral.
|
||||
export interface TemplateSpan extends Node {
|
||||
kind: SyntaxKind.TemplateSpan;
|
||||
parent?: TemplateExpression;
|
||||
expression: Expression;
|
||||
literal: TemplateMiddle | TemplateTail;
|
||||
}
|
||||
@@ -1436,6 +1444,7 @@
|
||||
|
||||
export interface ExpressionWithTypeArguments extends TypeNode {
|
||||
kind: SyntaxKind.ExpressionWithTypeArguments;
|
||||
parent?: HeritageClause;
|
||||
expression: LeftHandSideExpression;
|
||||
typeArguments?: NodeArray<TypeNode>;
|
||||
}
|
||||
@@ -1503,6 +1512,7 @@
|
||||
/// The opening element of a <Tag>...</Tag> JsxElement
|
||||
export interface JsxOpeningElement extends Expression {
|
||||
kind: SyntaxKind.JsxOpeningElement;
|
||||
parent?: JsxElement;
|
||||
tagName: JsxTagNameExpression;
|
||||
attributes: JsxAttributes;
|
||||
}
|
||||
@@ -1516,6 +1526,7 @@
|
||||
|
||||
export interface JsxAttribute extends ObjectLiteralElement {
|
||||
kind: SyntaxKind.JsxAttribute;
|
||||
parent?: JsxOpeningLikeElement;
|
||||
name: Identifier;
|
||||
/// JSX attribute initializers are optional; <X y /> is sugar for <X y={true} />
|
||||
initializer?: StringLiteral | JsxExpression;
|
||||
@@ -1523,22 +1534,26 @@
|
||||
|
||||
export interface JsxSpreadAttribute extends ObjectLiteralElement {
|
||||
kind: SyntaxKind.JsxSpreadAttribute;
|
||||
parent?: JsxOpeningLikeElement;
|
||||
expression: Expression;
|
||||
}
|
||||
|
||||
export interface JsxClosingElement extends Node {
|
||||
kind: SyntaxKind.JsxClosingElement;
|
||||
parent?: JsxElement;
|
||||
tagName: JsxTagNameExpression;
|
||||
}
|
||||
|
||||
export interface JsxExpression extends Expression {
|
||||
kind: SyntaxKind.JsxExpression;
|
||||
parent?: JsxElement | JsxAttributeLike;
|
||||
dotDotDotToken?: Token<SyntaxKind.DotDotDotToken>;
|
||||
expression?: Expression;
|
||||
}
|
||||
|
||||
export interface JsxText extends Node {
|
||||
kind: SyntaxKind.JsxText;
|
||||
parent?: JsxElement;
|
||||
}
|
||||
|
||||
export type JsxChild = JsxText | JsxExpression | JsxElement | JsxSelfClosingElement;
|
||||
@@ -1680,17 +1695,20 @@
|
||||
|
||||
export interface CaseBlock extends Node {
|
||||
kind: SyntaxKind.CaseBlock;
|
||||
parent?: SwitchStatement;
|
||||
clauses: NodeArray<CaseOrDefaultClause>;
|
||||
}
|
||||
|
||||
export interface CaseClause extends Node {
|
||||
kind: SyntaxKind.CaseClause;
|
||||
parent?: CaseBlock;
|
||||
expression: Expression;
|
||||
statements: NodeArray<Statement>;
|
||||
}
|
||||
|
||||
export interface DefaultClause extends Node {
|
||||
kind: SyntaxKind.DefaultClause;
|
||||
parent?: CaseBlock;
|
||||
statements: NodeArray<Statement>;
|
||||
}
|
||||
|
||||
@@ -1716,6 +1734,7 @@
|
||||
|
||||
export interface CatchClause extends Node {
|
||||
kind: SyntaxKind.CatchClause;
|
||||
parent?: TryStatement;
|
||||
variableDeclaration: VariableDeclaration;
|
||||
block: Block;
|
||||
}
|
||||
@@ -1759,6 +1778,7 @@
|
||||
|
||||
export interface HeritageClause extends Node {
|
||||
kind: SyntaxKind.HeritageClause;
|
||||
parent?: InterfaceDeclaration | ClassDeclaration | ClassExpression;
|
||||
token: SyntaxKind;
|
||||
types?: NodeArray<ExpressionWithTypeArguments>;
|
||||
}
|
||||
@@ -1772,6 +1792,7 @@
|
||||
|
||||
export interface EnumMember extends Declaration {
|
||||
kind: SyntaxKind.EnumMember;
|
||||
parent?: EnumDeclaration;
|
||||
// This does include ComputedPropertyName, but the parser will give an error
|
||||
// if it parses a ComputedPropertyName in an EnumMember
|
||||
name: PropertyName;
|
||||
@@ -1790,8 +1811,9 @@
|
||||
|
||||
export interface ModuleDeclaration extends DeclarationStatement {
|
||||
kind: SyntaxKind.ModuleDeclaration;
|
||||
name: Identifier | StringLiteral;
|
||||
body?: ModuleBody | JSDocNamespaceDeclaration | Identifier;
|
||||
parent?: ModuleBody | SourceFile;
|
||||
name: ModuleName;
|
||||
body?: ModuleBody | JSDocNamespaceDeclaration;
|
||||
}
|
||||
|
||||
export type NamespaceBody = ModuleBlock | NamespaceDeclaration;
|
||||
@@ -1810,13 +1832,20 @@
|
||||
|
||||
export interface ModuleBlock extends Node, Statement {
|
||||
kind: SyntaxKind.ModuleBlock;
|
||||
parent?: ModuleDeclaration;
|
||||
statements: NodeArray<Statement>;
|
||||
}
|
||||
|
||||
export type ModuleReference = EntityName | ExternalModuleReference;
|
||||
|
||||
/**
|
||||
* One of:
|
||||
* - import x = require("mod");
|
||||
* - import x = M.x;
|
||||
*/
|
||||
export interface ImportEqualsDeclaration extends DeclarationStatement {
|
||||
kind: SyntaxKind.ImportEqualsDeclaration;
|
||||
parent?: SourceFile | ModuleBlock;
|
||||
name: Identifier;
|
||||
|
||||
// 'EntityName' for an internal module reference, 'ExternalModuleReference' for an external
|
||||
@@ -1826,6 +1855,7 @@
|
||||
|
||||
export interface ExternalModuleReference extends Node {
|
||||
kind: SyntaxKind.ExternalModuleReference;
|
||||
parent?: ImportEqualsDeclaration;
|
||||
expression?: Expression;
|
||||
}
|
||||
|
||||
@@ -1835,6 +1865,7 @@
|
||||
// ImportClause information is shown at its declaration below.
|
||||
export interface ImportDeclaration extends Statement {
|
||||
kind: SyntaxKind.ImportDeclaration;
|
||||
parent?: SourceFile | ModuleBlock;
|
||||
importClause?: ImportClause;
|
||||
moduleSpecifier: Expression;
|
||||
}
|
||||
@@ -1849,34 +1880,38 @@
|
||||
// import d, { a, b as x } from "mod" => name = d, namedBinding: NamedImports = { elements: [{ name: a }, { name: x, propertyName: b}]}
|
||||
export interface ImportClause extends Declaration {
|
||||
kind: SyntaxKind.ImportClause;
|
||||
parent?: ImportDeclaration;
|
||||
name?: Identifier; // Default binding
|
||||
namedBindings?: NamedImportBindings;
|
||||
}
|
||||
|
||||
export interface NamespaceImport extends Declaration {
|
||||
kind: SyntaxKind.NamespaceImport;
|
||||
parent?: ImportClause;
|
||||
name: Identifier;
|
||||
}
|
||||
|
||||
export interface NamespaceExportDeclaration extends DeclarationStatement {
|
||||
kind: SyntaxKind.NamespaceExportDeclaration;
|
||||
name: Identifier;
|
||||
moduleReference: LiteralLikeNode;
|
||||
}
|
||||
|
||||
export interface ExportDeclaration extends DeclarationStatement {
|
||||
kind: SyntaxKind.ExportDeclaration;
|
||||
parent?: SourceFile | ModuleBlock;
|
||||
exportClause?: NamedExports;
|
||||
moduleSpecifier?: Expression;
|
||||
}
|
||||
|
||||
export interface NamedImports extends Node {
|
||||
kind: SyntaxKind.NamedImports;
|
||||
parent?: ImportClause;
|
||||
elements: NodeArray<ImportSpecifier>;
|
||||
}
|
||||
|
||||
export interface NamedExports extends Node {
|
||||
kind: SyntaxKind.NamedExports;
|
||||
parent?: ExportDeclaration;
|
||||
elements: NodeArray<ExportSpecifier>;
|
||||
}
|
||||
|
||||
@@ -1884,12 +1919,14 @@
|
||||
|
||||
export interface ImportSpecifier extends Declaration {
|
||||
kind: SyntaxKind.ImportSpecifier;
|
||||
parent?: NamedImports;
|
||||
propertyName?: Identifier; // Name preceding "as" keyword (or undefined when "as" is absent)
|
||||
name: Identifier; // Declared name
|
||||
}
|
||||
|
||||
export interface ExportSpecifier extends Declaration {
|
||||
kind: SyntaxKind.ExportSpecifier;
|
||||
parent?: NamedExports;
|
||||
propertyName?: Identifier; // Name preceding "as" keyword (or undefined when "as" is absent)
|
||||
name: Identifier; // Declared name
|
||||
}
|
||||
@@ -1898,6 +1935,7 @@
|
||||
|
||||
export interface ExportAssignment extends DeclarationStatement {
|
||||
kind: SyntaxKind.ExportAssignment;
|
||||
parent?: SourceFile;
|
||||
isExportEquals?: boolean;
|
||||
expression: Expression;
|
||||
}
|
||||
@@ -2171,6 +2209,16 @@
|
||||
name: string;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
/**
|
||||
* Subset of properties from SourceFile that are used in multiple utility functions
|
||||
*/
|
||||
export interface SourceFileLike {
|
||||
readonly text: string;
|
||||
lineMap: number[];
|
||||
}
|
||||
|
||||
|
||||
// Source files are declarations when they are external modules.
|
||||
export interface SourceFile extends Declaration {
|
||||
kind: SyntaxKind.SourceFile;
|
||||
@@ -2178,7 +2226,7 @@
|
||||
endOfFileToken: Token<SyntaxKind.EndOfFileToken>;
|
||||
|
||||
fileName: string;
|
||||
/* internal */ path: Path;
|
||||
/* @internal */ path: Path;
|
||||
text: string;
|
||||
|
||||
amdDependencies: AmdDependency[];
|
||||
@@ -2777,13 +2825,15 @@
|
||||
export const enum CheckFlags {
|
||||
Instantiated = 1 << 0, // Instantiated symbol
|
||||
SyntheticProperty = 1 << 1, // Property in union or intersection type
|
||||
Readonly = 1 << 2, // Readonly transient symbol
|
||||
Partial = 1 << 3, // Synthetic property present in some but not all constituents
|
||||
HasNonUniformType = 1 << 4, // Synthetic property with non-uniform type in constituents
|
||||
ContainsPublic = 1 << 5, // Synthetic property with public constituent(s)
|
||||
ContainsProtected = 1 << 6, // Synthetic property with protected constituent(s)
|
||||
ContainsPrivate = 1 << 7, // Synthetic property with private constituent(s)
|
||||
ContainsStatic = 1 << 8, // Synthetic property with static constituent(s)
|
||||
SyntheticMethod = 1 << 2, // Method in union or intersection type
|
||||
Readonly = 1 << 3, // Readonly transient symbol
|
||||
Partial = 1 << 4, // Synthetic property present in some but not all constituents
|
||||
HasNonUniformType = 1 << 5, // Synthetic property with non-uniform type in constituents
|
||||
ContainsPublic = 1 << 6, // Synthetic property with public constituent(s)
|
||||
ContainsProtected = 1 << 7, // Synthetic property with protected constituent(s)
|
||||
ContainsPrivate = 1 << 8, // Synthetic property with private constituent(s)
|
||||
ContainsStatic = 1 << 9, // Synthetic property with static constituent(s)
|
||||
Synthetic = SyntheticProperty | SyntheticMethod
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -3201,6 +3251,7 @@
|
||||
mapper?: TypeMapper; // Type mapper for this inference context
|
||||
failedTypeParameterIndex?: number; // Index of type parameter for which inference failed
|
||||
// It is optional because in contextual signature instantiation, nothing fails
|
||||
useAnyForNoInferences?: boolean; // Use any instead of {} for no inferences
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -3264,7 +3315,7 @@
|
||||
}
|
||||
|
||||
export interface PluginImport {
|
||||
name: string
|
||||
name: string;
|
||||
}
|
||||
|
||||
export type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike<string[]> | PluginImport[];
|
||||
@@ -3275,7 +3326,7 @@
|
||||
allowSyntheticDefaultImports?: boolean;
|
||||
allowUnreachableCode?: boolean;
|
||||
allowUnusedLabels?: boolean;
|
||||
alwaysStrict?: boolean;
|
||||
alwaysStrict?: boolean; // Always combine with strict property
|
||||
baseUrl?: string;
|
||||
charset?: string;
|
||||
/* @internal */ configFilePath?: string;
|
||||
@@ -3311,9 +3362,9 @@
|
||||
noEmitOnError?: boolean;
|
||||
noErrorTruncation?: boolean;
|
||||
noFallthroughCasesInSwitch?: boolean;
|
||||
noImplicitAny?: boolean;
|
||||
noImplicitAny?: boolean; // Always combine with strict property
|
||||
noImplicitReturns?: boolean;
|
||||
noImplicitThis?: boolean;
|
||||
noImplicitThis?: boolean; // Always combine with strict property
|
||||
noUnusedLocals?: boolean;
|
||||
noUnusedParameters?: boolean;
|
||||
noImplicitUseStrict?: boolean;
|
||||
@@ -3336,7 +3387,8 @@
|
||||
skipDefaultLibCheck?: boolean;
|
||||
sourceMap?: boolean;
|
||||
sourceRoot?: string;
|
||||
strictNullChecks?: boolean;
|
||||
strict?: boolean;
|
||||
strictNullChecks?: boolean; // Always combine with strict property
|
||||
/* @internal */ stripInternal?: boolean;
|
||||
suppressExcessPropertyErrors?: boolean;
|
||||
suppressImplicitAnyIndexErrors?: boolean;
|
||||
@@ -4096,6 +4148,8 @@
|
||||
/*@internal*/ onEmitSourceMapOfPosition?: (pos: number) => void;
|
||||
/*@internal*/ onEmitHelpers?: (node: Node, writeLines: (text: string) => void) => void;
|
||||
/*@internal*/ onSetSourceFile?: (node: SourceFile) => void;
|
||||
/*@internal*/ onBeforeEmitNodeArray?: (nodes: NodeArray<any>) => void;
|
||||
/*@internal*/ onAfterEmitNodeArray?: (nodes: NodeArray<any>) => void;
|
||||
}
|
||||
|
||||
export interface PrinterOptions {
|
||||
|
||||
+48
-18
@@ -1,4 +1,4 @@
|
||||
/// <reference path="sys.ts" />
|
||||
/// <reference path="sys.ts" />
|
||||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
@@ -184,7 +184,7 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getStartPositionOfLine(line: number, sourceFile: SourceFile): number {
|
||||
export function getStartPositionOfLine(line: number, sourceFile: SourceFileLike): number {
|
||||
Debug.assert(line >= 0);
|
||||
return getLineStarts(sourceFile)[line];
|
||||
}
|
||||
@@ -204,7 +204,7 @@ namespace ts {
|
||||
return value !== undefined;
|
||||
}
|
||||
|
||||
export function getEndLinePosition(line: number, sourceFile: SourceFile): number {
|
||||
export function getEndLinePosition(line: number, sourceFile: SourceFileLike): number {
|
||||
Debug.assert(line >= 0);
|
||||
const lineStarts = getLineStarts(sourceFile);
|
||||
|
||||
@@ -255,7 +255,11 @@ namespace ts {
|
||||
return !nodeIsMissing(node);
|
||||
}
|
||||
|
||||
export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile, includeJsDoc?: boolean): number {
|
||||
export function isToken(n: Node): boolean {
|
||||
return n.kind >= SyntaxKind.FirstToken && n.kind <= SyntaxKind.LastToken;
|
||||
}
|
||||
|
||||
export function getTokenPosOfNode(node: Node, sourceFile?: SourceFileLike, includeJsDoc?: 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)) {
|
||||
@@ -289,7 +293,7 @@ namespace ts {
|
||||
return node.kind >= SyntaxKind.FirstJSDocTagNode && node.kind <= SyntaxKind.LastJSDocTagNode;
|
||||
}
|
||||
|
||||
export function getNonDecoratorTokenPosOfNode(node: Node, sourceFile?: SourceFile): number {
|
||||
export function getNonDecoratorTokenPosOfNode(node: Node, sourceFile?: SourceFileLike): number {
|
||||
if (nodeIsMissing(node) || !node.decorators) {
|
||||
return getTokenPosOfNode(node, sourceFile);
|
||||
}
|
||||
@@ -435,8 +439,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** Given a symbol for a module, checks that it is either an untyped import or a shorthand ambient module. */
|
||||
export function isShorthandAmbientModuleSymbol(moduleSymbol: Symbol): boolean {
|
||||
return isShorthandAmbientModule(moduleSymbol.valueDeclaration);
|
||||
export function isUntypedOrShorthandAmbientModuleSymbol(moduleSymbol: Symbol): boolean {
|
||||
return !moduleSymbol.declarations || isShorthandAmbientModule(moduleSymbol.valueDeclaration);
|
||||
}
|
||||
|
||||
function isShorthandAmbientModule(node: Node): boolean {
|
||||
@@ -1425,6 +1429,21 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getRightMostAssignedExpression(node: Node) {
|
||||
while (isAssignmentExpression(node, /*excludeCompoundAssignements*/ true)) {
|
||||
node = node.right;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
export function isExportsIdentifier(node: Node) {
|
||||
return isIdentifier(node) && node.text === "exports";
|
||||
}
|
||||
|
||||
export function isModuleExportsPropertyAccessExpression(node: Node) {
|
||||
return isPropertyAccessExpression(node) && isIdentifier(node.expression) && node.expression.text === "module" && node.name.text === "exports";
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
@@ -1554,7 +1573,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
result.push(...filter((doc as JSDoc).tags, tag => tag.kind === kind));
|
||||
const tags = (doc as JSDoc).tags;
|
||||
if (tags) {
|
||||
result.push(...filter(tags, tag => tag.kind === kind));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -2473,7 +2495,7 @@ namespace ts {
|
||||
return indentStrings[1].length;
|
||||
}
|
||||
|
||||
export function createTextWriter(newLine: String): EmitTextWriter {
|
||||
export function createTextWriter(newLine: string): EmitTextWriter {
|
||||
let output: string;
|
||||
let indent: number;
|
||||
let lineStart: boolean;
|
||||
@@ -3126,6 +3148,15 @@ namespace ts {
|
||||
return tryGetClassExtendingExpressionWithTypeArguments(node) !== undefined;
|
||||
}
|
||||
|
||||
export function isExpressionWithTypeArgumentsInClassImplementsClause(node: Node): node is ExpressionWithTypeArguments {
|
||||
return node.kind === SyntaxKind.ExpressionWithTypeArguments
|
||||
&& isEntityNameExpression((node as ExpressionWithTypeArguments).expression)
|
||||
&& node.parent
|
||||
&& (<HeritageClause>node.parent).token === SyntaxKind.ImplementsKeyword
|
||||
&& node.parent.parent
|
||||
&& isClassLike(node.parent.parent);
|
||||
}
|
||||
|
||||
export function isEntityNameExpression(node: Expression): node is EntityNameExpression {
|
||||
return node.kind === SyntaxKind.Identifier ||
|
||||
node.kind === SyntaxKind.PropertyAccessExpression && isEntityNameExpression((<PropertyAccessExpression>node).expression);
|
||||
@@ -3136,15 +3167,14 @@ namespace ts {
|
||||
(node.parent.kind === SyntaxKind.PropertyAccessExpression && (<PropertyAccessExpression>node.parent).name === node);
|
||||
}
|
||||
|
||||
export function isEmptyObjectLiteralOrArrayLiteral(expression: Node): boolean {
|
||||
const kind = expression.kind;
|
||||
if (kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
return (<ObjectLiteralExpression>expression).properties.length === 0;
|
||||
}
|
||||
if (kind === SyntaxKind.ArrayLiteralExpression) {
|
||||
return (<ArrayLiteralExpression>expression).elements.length === 0;
|
||||
}
|
||||
return false;
|
||||
export function isEmptyObjectLiteral(expression: Node): boolean {
|
||||
return expression.kind === SyntaxKind.ObjectLiteralExpression &&
|
||||
(<ObjectLiteralExpression>expression).properties.length === 0;
|
||||
}
|
||||
|
||||
export function isEmptyArrayLiteral(expression: Node): boolean {
|
||||
return expression.kind === SyntaxKind.ArrayLiteralExpression &&
|
||||
(<ArrayLiteralExpression>expression).elements.length === 0;
|
||||
}
|
||||
|
||||
export function getLocalSymbolForExportDefault(symbol: Symbol) {
|
||||
|
||||
+76
-76
@@ -1,4 +1,4 @@
|
||||
/// <reference path="checker.ts" />
|
||||
/// <reference path="checker.ts" />
|
||||
/// <reference path="factory.ts" />
|
||||
/// <reference path="utilities.ts" />
|
||||
|
||||
@@ -154,9 +154,9 @@ namespace ts {
|
||||
* Starts a new lexical environment and visits a parameter list, suspending the lexical
|
||||
* environment upon completion.
|
||||
*/
|
||||
export function visitParameterList(nodes: NodeArray<ParameterDeclaration>, visitor: Visitor, context: TransformationContext) {
|
||||
export function visitParameterList(nodes: NodeArray<ParameterDeclaration>, visitor: Visitor, context: TransformationContext, nodesVisitor = visitNodes) {
|
||||
context.startLexicalEnvironment();
|
||||
const updated = visitNodes(nodes, visitor, isParameterDeclaration);
|
||||
const updated = nodesVisitor(nodes, visitor, isParameterDeclaration);
|
||||
context.suspendLexicalEnvironment();
|
||||
return updated;
|
||||
}
|
||||
@@ -204,9 +204,9 @@ namespace ts {
|
||||
* @param visitor The callback used to visit each child.
|
||||
* @param context A lexical environment context for the visitor.
|
||||
*/
|
||||
export function visitEachChild<T extends Node>(node: T | undefined, visitor: Visitor, context: TransformationContext): T | undefined;
|
||||
export function visitEachChild<T extends Node>(node: T | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: typeof visitNodes): T | undefined;
|
||||
|
||||
export function visitEachChild(node: Node, visitor: Visitor, context: TransformationContext): Node {
|
||||
export function visitEachChild(node: Node, visitor: Visitor, context: TransformationContext, nodesVisitor = visitNodes): Node {
|
||||
if (node === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -243,8 +243,8 @@ namespace ts {
|
||||
// Signature elements
|
||||
case SyntaxKind.Parameter:
|
||||
return updateParameter(<ParameterDeclaration>node,
|
||||
visitNodes((<ParameterDeclaration>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<ParameterDeclaration>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<ParameterDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<ParameterDeclaration>node).modifiers, visitor, isModifier),
|
||||
(<ParameterDeclaration>node).dotDotDotToken,
|
||||
visitNode((<ParameterDeclaration>node).name, visitor, isBindingName),
|
||||
visitNode((<ParameterDeclaration>node).type, visitor, isTypeNode),
|
||||
@@ -257,55 +257,55 @@ namespace ts {
|
||||
// Type member
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
return updateProperty(<PropertyDeclaration>node,
|
||||
visitNodes((<PropertyDeclaration>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<PropertyDeclaration>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<PropertyDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<PropertyDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<PropertyDeclaration>node).name, visitor, isPropertyName),
|
||||
visitNode((<PropertyDeclaration>node).type, visitor, isTypeNode),
|
||||
visitNode((<PropertyDeclaration>node).initializer, visitor, isExpression));
|
||||
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
return updateMethod(<MethodDeclaration>node,
|
||||
visitNodes((<MethodDeclaration>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<MethodDeclaration>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<MethodDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<MethodDeclaration>node).modifiers, visitor, isModifier),
|
||||
(<MethodDeclaration>node).asteriskToken,
|
||||
visitNode((<MethodDeclaration>node).name, visitor, isPropertyName),
|
||||
visitNodes((<MethodDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
visitParameterList((<MethodDeclaration>node).parameters, visitor, context),
|
||||
nodesVisitor((<MethodDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
visitParameterList((<MethodDeclaration>node).parameters, visitor, context, nodesVisitor),
|
||||
visitNode((<MethodDeclaration>node).type, visitor, isTypeNode),
|
||||
visitFunctionBody((<MethodDeclaration>node).body, visitor, context));
|
||||
|
||||
case SyntaxKind.Constructor:
|
||||
return updateConstructor(<ConstructorDeclaration>node,
|
||||
visitNodes((<ConstructorDeclaration>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<ConstructorDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitParameterList((<ConstructorDeclaration>node).parameters, visitor, context),
|
||||
nodesVisitor((<ConstructorDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<ConstructorDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitParameterList((<ConstructorDeclaration>node).parameters, visitor, context, nodesVisitor),
|
||||
visitFunctionBody((<ConstructorDeclaration>node).body, visitor, context));
|
||||
|
||||
case SyntaxKind.GetAccessor:
|
||||
return updateGetAccessor(<GetAccessorDeclaration>node,
|
||||
visitNodes((<GetAccessorDeclaration>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<GetAccessorDeclaration>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<GetAccessorDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<GetAccessorDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<GetAccessorDeclaration>node).name, visitor, isPropertyName),
|
||||
visitParameterList((<GetAccessorDeclaration>node).parameters, visitor, context),
|
||||
visitParameterList((<GetAccessorDeclaration>node).parameters, visitor, context, nodesVisitor),
|
||||
visitNode((<GetAccessorDeclaration>node).type, visitor, isTypeNode),
|
||||
visitFunctionBody((<GetAccessorDeclaration>node).body, visitor, context));
|
||||
|
||||
case SyntaxKind.SetAccessor:
|
||||
return updateSetAccessor(<SetAccessorDeclaration>node,
|
||||
visitNodes((<SetAccessorDeclaration>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<SetAccessorDeclaration>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<SetAccessorDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<SetAccessorDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<SetAccessorDeclaration>node).name, visitor, isPropertyName),
|
||||
visitParameterList((<SetAccessorDeclaration>node).parameters, visitor, context),
|
||||
visitParameterList((<SetAccessorDeclaration>node).parameters, visitor, context, nodesVisitor),
|
||||
visitFunctionBody((<SetAccessorDeclaration>node).body, visitor, context));
|
||||
|
||||
// Binding patterns
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
return updateObjectBindingPattern(<ObjectBindingPattern>node,
|
||||
visitNodes((<ObjectBindingPattern>node).elements, visitor, isBindingElement));
|
||||
nodesVisitor((<ObjectBindingPattern>node).elements, visitor, isBindingElement));
|
||||
|
||||
case SyntaxKind.ArrayBindingPattern:
|
||||
return updateArrayBindingPattern(<ArrayBindingPattern>node,
|
||||
visitNodes((<ArrayBindingPattern>node).elements, visitor, isArrayBindingElement));
|
||||
nodesVisitor((<ArrayBindingPattern>node).elements, visitor, isArrayBindingElement));
|
||||
|
||||
case SyntaxKind.BindingElement:
|
||||
return updateBindingElement(<BindingElement>node,
|
||||
@@ -317,11 +317,11 @@ namespace ts {
|
||||
// Expression
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
return updateArrayLiteral(<ArrayLiteralExpression>node,
|
||||
visitNodes((<ArrayLiteralExpression>node).elements, visitor, isExpression));
|
||||
nodesVisitor((<ArrayLiteralExpression>node).elements, visitor, isExpression));
|
||||
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
return updateObjectLiteral(<ObjectLiteralExpression>node,
|
||||
visitNodes((<ObjectLiteralExpression>node).properties, visitor, isObjectLiteralElementLike));
|
||||
nodesVisitor((<ObjectLiteralExpression>node).properties, visitor, isObjectLiteralElementLike));
|
||||
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
return updatePropertyAccess(<PropertyAccessExpression>node,
|
||||
@@ -336,14 +336,14 @@ namespace ts {
|
||||
case SyntaxKind.CallExpression:
|
||||
return updateCall(<CallExpression>node,
|
||||
visitNode((<CallExpression>node).expression, visitor, isExpression),
|
||||
visitNodes((<CallExpression>node).typeArguments, visitor, isTypeNode),
|
||||
visitNodes((<CallExpression>node).arguments, visitor, isExpression));
|
||||
nodesVisitor((<CallExpression>node).typeArguments, visitor, isTypeNode),
|
||||
nodesVisitor((<CallExpression>node).arguments, visitor, isExpression));
|
||||
|
||||
case SyntaxKind.NewExpression:
|
||||
return updateNew(<NewExpression>node,
|
||||
visitNode((<NewExpression>node).expression, visitor, isExpression),
|
||||
visitNodes((<NewExpression>node).typeArguments, visitor, isTypeNode),
|
||||
visitNodes((<NewExpression>node).arguments, visitor, isExpression));
|
||||
nodesVisitor((<NewExpression>node).typeArguments, visitor, isTypeNode),
|
||||
nodesVisitor((<NewExpression>node).arguments, visitor, isExpression));
|
||||
|
||||
case SyntaxKind.TaggedTemplateExpression:
|
||||
return updateTaggedTemplate(<TaggedTemplateExpression>node,
|
||||
@@ -361,19 +361,19 @@ namespace ts {
|
||||
|
||||
case SyntaxKind.FunctionExpression:
|
||||
return updateFunctionExpression(<FunctionExpression>node,
|
||||
visitNodes((<FunctionExpression>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<FunctionExpression>node).modifiers, visitor, isModifier),
|
||||
(<FunctionExpression>node).asteriskToken,
|
||||
visitNode((<FunctionExpression>node).name, visitor, isIdentifier),
|
||||
visitNodes((<FunctionExpression>node).typeParameters, visitor, isTypeParameter),
|
||||
visitParameterList((<FunctionExpression>node).parameters, visitor, context),
|
||||
nodesVisitor((<FunctionExpression>node).typeParameters, visitor, isTypeParameter),
|
||||
visitParameterList((<FunctionExpression>node).parameters, visitor, context, nodesVisitor),
|
||||
visitNode((<FunctionExpression>node).type, visitor, isTypeNode),
|
||||
visitFunctionBody((<FunctionExpression>node).body, visitor, context));
|
||||
|
||||
case SyntaxKind.ArrowFunction:
|
||||
return updateArrowFunction(<ArrowFunction>node,
|
||||
visitNodes((<ArrowFunction>node).modifiers, visitor, isModifier),
|
||||
visitNodes((<ArrowFunction>node).typeParameters, visitor, isTypeParameter),
|
||||
visitParameterList((<ArrowFunction>node).parameters, visitor, context),
|
||||
nodesVisitor((<ArrowFunction>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<ArrowFunction>node).typeParameters, visitor, isTypeParameter),
|
||||
visitParameterList((<ArrowFunction>node).parameters, visitor, context, nodesVisitor),
|
||||
visitNode((<ArrowFunction>node).type, visitor, isTypeNode),
|
||||
visitFunctionBody((<ArrowFunction>node).body, visitor, context));
|
||||
|
||||
@@ -415,7 +415,7 @@ namespace ts {
|
||||
case SyntaxKind.TemplateExpression:
|
||||
return updateTemplateExpression(<TemplateExpression>node,
|
||||
visitNode((<TemplateExpression>node).head, visitor, isTemplateHead),
|
||||
visitNodes((<TemplateExpression>node).templateSpans, visitor, isTemplateSpan));
|
||||
nodesVisitor((<TemplateExpression>node).templateSpans, visitor, isTemplateSpan));
|
||||
|
||||
case SyntaxKind.YieldExpression:
|
||||
return updateYield(<YieldExpression>node,
|
||||
@@ -428,15 +428,15 @@ namespace ts {
|
||||
|
||||
case SyntaxKind.ClassExpression:
|
||||
return updateClassExpression(<ClassExpression>node,
|
||||
visitNodes((<ClassExpression>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<ClassExpression>node).modifiers, visitor, isModifier),
|
||||
visitNode((<ClassExpression>node).name, visitor, isIdentifier),
|
||||
visitNodes((<ClassExpression>node).typeParameters, visitor, isTypeParameter),
|
||||
visitNodes((<ClassExpression>node).heritageClauses, visitor, isHeritageClause),
|
||||
visitNodes((<ClassExpression>node).members, visitor, isClassElement));
|
||||
nodesVisitor((<ClassExpression>node).typeParameters, visitor, isTypeParameter),
|
||||
nodesVisitor((<ClassExpression>node).heritageClauses, visitor, isHeritageClause),
|
||||
nodesVisitor((<ClassExpression>node).members, visitor, isClassElement));
|
||||
|
||||
case SyntaxKind.ExpressionWithTypeArguments:
|
||||
return updateExpressionWithTypeArguments(<ExpressionWithTypeArguments>node,
|
||||
visitNodes((<ExpressionWithTypeArguments>node).typeArguments, visitor, isTypeNode),
|
||||
nodesVisitor((<ExpressionWithTypeArguments>node).typeArguments, visitor, isTypeNode),
|
||||
visitNode((<ExpressionWithTypeArguments>node).expression, visitor, isExpression));
|
||||
|
||||
case SyntaxKind.AsExpression:
|
||||
@@ -457,11 +457,11 @@ namespace ts {
|
||||
// Element
|
||||
case SyntaxKind.Block:
|
||||
return updateBlock(<Block>node,
|
||||
visitNodes((<Block>node).statements, visitor, isStatement));
|
||||
nodesVisitor((<Block>node).statements, visitor, isStatement));
|
||||
|
||||
case SyntaxKind.VariableStatement:
|
||||
return updateVariableStatement(<VariableStatement>node,
|
||||
visitNodes((<VariableStatement>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<VariableStatement>node).modifiers, visitor, isModifier),
|
||||
visitNode((<VariableStatement>node).declarationList, visitor, isVariableDeclarationList));
|
||||
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
@@ -549,61 +549,61 @@ namespace ts {
|
||||
|
||||
case SyntaxKind.VariableDeclarationList:
|
||||
return updateVariableDeclarationList(<VariableDeclarationList>node,
|
||||
visitNodes((<VariableDeclarationList>node).declarations, visitor, isVariableDeclaration));
|
||||
nodesVisitor((<VariableDeclarationList>node).declarations, visitor, isVariableDeclaration));
|
||||
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
return updateFunctionDeclaration(<FunctionDeclaration>node,
|
||||
visitNodes((<FunctionDeclaration>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<FunctionDeclaration>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<FunctionDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<FunctionDeclaration>node).modifiers, visitor, isModifier),
|
||||
(<FunctionDeclaration>node).asteriskToken,
|
||||
visitNode((<FunctionDeclaration>node).name, visitor, isIdentifier),
|
||||
visitNodes((<FunctionDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
visitParameterList((<FunctionDeclaration>node).parameters, visitor, context),
|
||||
nodesVisitor((<FunctionDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
visitParameterList((<FunctionDeclaration>node).parameters, visitor, context, nodesVisitor),
|
||||
visitNode((<FunctionDeclaration>node).type, visitor, isTypeNode),
|
||||
visitFunctionBody((<FunctionExpression>node).body, visitor, context));
|
||||
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
return updateClassDeclaration(<ClassDeclaration>node,
|
||||
visitNodes((<ClassDeclaration>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<ClassDeclaration>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<ClassDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<ClassDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<ClassDeclaration>node).name, visitor, isIdentifier),
|
||||
visitNodes((<ClassDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
visitNodes((<ClassDeclaration>node).heritageClauses, visitor, isHeritageClause),
|
||||
visitNodes((<ClassDeclaration>node).members, visitor, isClassElement));
|
||||
nodesVisitor((<ClassDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
nodesVisitor((<ClassDeclaration>node).heritageClauses, visitor, isHeritageClause),
|
||||
nodesVisitor((<ClassDeclaration>node).members, visitor, isClassElement));
|
||||
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
return updateEnumDeclaration(<EnumDeclaration>node,
|
||||
visitNodes((<EnumDeclaration>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<EnumDeclaration>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<EnumDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<EnumDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<EnumDeclaration>node).name, visitor, isIdentifier),
|
||||
visitNodes((<EnumDeclaration>node).members, visitor, isEnumMember));
|
||||
nodesVisitor((<EnumDeclaration>node).members, visitor, isEnumMember));
|
||||
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
return updateModuleDeclaration(<ModuleDeclaration>node,
|
||||
visitNodes((<ModuleDeclaration>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<ModuleDeclaration>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<ModuleDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<ModuleDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<ModuleDeclaration>node).name, visitor, isIdentifier),
|
||||
visitNode((<ModuleDeclaration>node).body, visitor, isModuleBody));
|
||||
|
||||
case SyntaxKind.ModuleBlock:
|
||||
return updateModuleBlock(<ModuleBlock>node,
|
||||
visitNodes((<ModuleBlock>node).statements, visitor, isStatement));
|
||||
nodesVisitor((<ModuleBlock>node).statements, visitor, isStatement));
|
||||
|
||||
case SyntaxKind.CaseBlock:
|
||||
return updateCaseBlock(<CaseBlock>node,
|
||||
visitNodes((<CaseBlock>node).clauses, visitor, isCaseOrDefaultClause));
|
||||
nodesVisitor((<CaseBlock>node).clauses, visitor, isCaseOrDefaultClause));
|
||||
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
return updateImportEqualsDeclaration(<ImportEqualsDeclaration>node,
|
||||
visitNodes((<ImportEqualsDeclaration>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<ImportEqualsDeclaration>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<ImportEqualsDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<ImportEqualsDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<ImportEqualsDeclaration>node).name, visitor, isIdentifier),
|
||||
visitNode((<ImportEqualsDeclaration>node).moduleReference, visitor, isModuleReference));
|
||||
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
return updateImportDeclaration(<ImportDeclaration>node,
|
||||
visitNodes((<ImportDeclaration>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<ImportDeclaration>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<ImportDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<ImportDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<ImportDeclaration>node).importClause, visitor, isImportClause),
|
||||
visitNode((<ImportDeclaration>node).moduleSpecifier, visitor, isExpression));
|
||||
|
||||
@@ -618,7 +618,7 @@ namespace ts {
|
||||
|
||||
case SyntaxKind.NamedImports:
|
||||
return updateNamedImports(<NamedImports>node,
|
||||
visitNodes((<NamedImports>node).elements, visitor, isImportSpecifier));
|
||||
nodesVisitor((<NamedImports>node).elements, visitor, isImportSpecifier));
|
||||
|
||||
case SyntaxKind.ImportSpecifier:
|
||||
return updateImportSpecifier(<ImportSpecifier>node,
|
||||
@@ -627,20 +627,20 @@ namespace ts {
|
||||
|
||||
case SyntaxKind.ExportAssignment:
|
||||
return updateExportAssignment(<ExportAssignment>node,
|
||||
visitNodes((<ExportAssignment>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<ExportAssignment>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<ExportAssignment>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<ExportAssignment>node).modifiers, visitor, isModifier),
|
||||
visitNode((<ExportAssignment>node).expression, visitor, isExpression));
|
||||
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
return updateExportDeclaration(<ExportDeclaration>node,
|
||||
visitNodes((<ExportDeclaration>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<ExportDeclaration>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<ExportDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<ExportDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<ExportDeclaration>node).exportClause, visitor, isNamedExports),
|
||||
visitNode((<ExportDeclaration>node).moduleSpecifier, visitor, isExpression));
|
||||
|
||||
case SyntaxKind.NamedExports:
|
||||
return updateNamedExports(<NamedExports>node,
|
||||
visitNodes((<NamedExports>node).elements, visitor, isExportSpecifier));
|
||||
nodesVisitor((<NamedExports>node).elements, visitor, isExportSpecifier));
|
||||
|
||||
case SyntaxKind.ExportSpecifier:
|
||||
return updateExportSpecifier(<ExportSpecifier>node,
|
||||
@@ -656,12 +656,12 @@ namespace ts {
|
||||
case SyntaxKind.JsxElement:
|
||||
return updateJsxElement(<JsxElement>node,
|
||||
visitNode((<JsxElement>node).openingElement, visitor, isJsxOpeningElement),
|
||||
visitNodes((<JsxElement>node).children, visitor, isJsxChild),
|
||||
nodesVisitor((<JsxElement>node).children, visitor, isJsxChild),
|
||||
visitNode((<JsxElement>node).closingElement, visitor, isJsxClosingElement));
|
||||
|
||||
case SyntaxKind.JsxAttributes:
|
||||
return updateJsxAttributes(<JsxAttributes>node,
|
||||
visitNodes((<JsxAttributes>node).properties, visitor, isJsxAttributeLike));
|
||||
nodesVisitor((<JsxAttributes>node).properties, visitor, isJsxAttributeLike));
|
||||
|
||||
case SyntaxKind.JsxSelfClosingElement:
|
||||
return updateJsxSelfClosingElement(<JsxSelfClosingElement>node,
|
||||
@@ -694,15 +694,15 @@ namespace ts {
|
||||
case SyntaxKind.CaseClause:
|
||||
return updateCaseClause(<CaseClause>node,
|
||||
visitNode((<CaseClause>node).expression, visitor, isExpression),
|
||||
visitNodes((<CaseClause>node).statements, visitor, isStatement));
|
||||
nodesVisitor((<CaseClause>node).statements, visitor, isStatement));
|
||||
|
||||
case SyntaxKind.DefaultClause:
|
||||
return updateDefaultClause(<DefaultClause>node,
|
||||
visitNodes((<DefaultClause>node).statements, visitor, isStatement));
|
||||
nodesVisitor((<DefaultClause>node).statements, visitor, isStatement));
|
||||
|
||||
case SyntaxKind.HeritageClause:
|
||||
return updateHeritageClause(<HeritageClause>node,
|
||||
visitNodes((<HeritageClause>node).types, visitor, isExpressionWithTypeArguments));
|
||||
nodesVisitor((<HeritageClause>node).types, visitor, isExpressionWithTypeArguments));
|
||||
|
||||
case SyntaxKind.CatchClause:
|
||||
return updateCatchClause(<CatchClause>node,
|
||||
|
||||
+50
-16
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -22,6 +22,10 @@
|
||||
namespace FourSlash {
|
||||
ts.disableIncrementalParsing = false;
|
||||
|
||||
function normalizeNewLines(s: string) {
|
||||
return s.replace(/\r\n/g, "\n");
|
||||
}
|
||||
|
||||
// Represents a parsed source file with metadata
|
||||
export interface FourSlashFile {
|
||||
// The contents of the file (with markers, etc stripped out)
|
||||
@@ -585,7 +589,7 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
private getGoToDefinition(): ts.DefinitionInfo[] {
|
||||
return this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition)
|
||||
return this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
|
||||
}
|
||||
|
||||
public verifyGoToType(arg0: any, endMarkerNames?: string | string[]) {
|
||||
@@ -923,10 +927,13 @@ namespace FourSlash {
|
||||
this.assertObjectsEqual<ReferencesJson>(fullActual, fullExpected);
|
||||
}
|
||||
|
||||
function rangeToReferenceEntry(r: Range) {
|
||||
let { isWriteAccess, isDefinition } = (r.marker && r.marker.data) || { isWriteAccess: false, isDefinition: false };
|
||||
isWriteAccess = !!isWriteAccess; isDefinition = !!isDefinition;
|
||||
return { fileName: r.fileName, textSpan: { start: r.start, length: r.end - r.start }, isWriteAccess, isDefinition }
|
||||
function rangeToReferenceEntry(r: Range): ts.ReferenceEntry {
|
||||
const { isWriteAccess, isDefinition, isInString } = (r.marker && r.marker.data) || { isWriteAccess: false, isDefinition: false, isInString: undefined };
|
||||
const result: ts.ReferenceEntry = { fileName: r.fileName, textSpan: { start: r.start, length: r.end - r.start }, isWriteAccess: !!isWriteAccess, isDefinition: !!isDefinition };
|
||||
if (isInString !== undefined) {
|
||||
result.isInString = isInString;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1851,17 +1858,41 @@ namespace FourSlash {
|
||||
|
||||
const unsatisfiedRanges: Range[] = [];
|
||||
|
||||
const delayedErrors: string[] = [];
|
||||
for (const range of ranges) {
|
||||
const length = range.end - range.start;
|
||||
const matchingImpl = ts.find(implementations, impl =>
|
||||
range.fileName === impl.fileName && range.start === impl.textSpan.start && length === impl.textSpan.length);
|
||||
if (matchingImpl) {
|
||||
if (range.marker && range.marker.data) {
|
||||
const expected = <{ displayParts?: ts.SymbolDisplayPart[], parts: string[], kind?: string }>range.marker.data;
|
||||
if (expected.displayParts) {
|
||||
if (!ts.arrayIsEqualTo(expected.displayParts, matchingImpl.displayParts, displayPartIsEqualTo)) {
|
||||
delayedErrors.push(`Mismatched display parts: expected ${JSON.stringify(expected.displayParts)}, actual ${JSON.stringify(matchingImpl.displayParts)}`);
|
||||
}
|
||||
}
|
||||
else if (expected.parts) {
|
||||
const actualParts = matchingImpl.displayParts.map(p => p.text);
|
||||
if (!ts.arrayIsEqualTo(expected.parts, actualParts)) {
|
||||
delayedErrors.push(`Mismatched non-tagged display parts: expected ${JSON.stringify(expected.parts)}, actual ${JSON.stringify(actualParts)}`);
|
||||
}
|
||||
}
|
||||
if (expected.kind !== undefined) {
|
||||
if (expected.kind !== matchingImpl.kind) {
|
||||
delayedErrors.push(`Mismatched kind: expected ${JSON.stringify(expected.kind)}, actual ${JSON.stringify(matchingImpl.kind)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matchingImpl.matched = true;
|
||||
}
|
||||
else {
|
||||
unsatisfiedRanges.push(range);
|
||||
}
|
||||
}
|
||||
if (delayedErrors.length) {
|
||||
this.raiseError(delayedErrors.join("\n"));
|
||||
}
|
||||
|
||||
const unmatchedImplementations = implementations.filter(impl => !impl.matched);
|
||||
if (unmatchedImplementations.length || unsatisfiedRanges.length) {
|
||||
@@ -1886,6 +1917,10 @@ namespace FourSlash {
|
||||
function implementationsAreEqual(a: ImplementationLocationInformation, b: ImplementationLocationInformation) {
|
||||
return a.fileName === b.fileName && TestState.textSpansEqual(a.textSpan, b.textSpan);
|
||||
}
|
||||
|
||||
function displayPartIsEqualTo(a: ts.SymbolDisplayPart, b: ts.SymbolDisplayPart): boolean {
|
||||
return a.kind === b.kind && a.text === b.text;
|
||||
}
|
||||
}
|
||||
|
||||
public getMarkers(): Marker[] {
|
||||
@@ -1958,8 +1993,7 @@ namespace FourSlash {
|
||||
|
||||
public verifyCurrentFileContent(text: string) {
|
||||
const actual = this.getFileContent(this.activeFile.fileName);
|
||||
const replaceNewlines = (str: string) => str.replace(/\r\n/g, "\n");
|
||||
if (replaceNewlines(actual) !== replaceNewlines(text)) {
|
||||
if (normalizeNewLines(actual) !== normalizeNewLines(text)) {
|
||||
throw new Error("verifyCurrentFileContent\n" +
|
||||
"\tExpected: \"" + text + "\"\n" +
|
||||
"\t Actual: \"" + actual + "\"");
|
||||
@@ -2135,8 +2169,8 @@ namespace FourSlash {
|
||||
const actualText = this.rangeText(ranges[0]);
|
||||
|
||||
const result = includeWhiteSpace
|
||||
? actualText === expectedText
|
||||
: this.removeWhitespace(actualText) === this.removeWhitespace(expectedText)
|
||||
? normalizeNewLines(actualText) === normalizeNewLines(expectedText)
|
||||
: this.removeWhitespace(actualText) === this.removeWhitespace(expectedText);
|
||||
|
||||
if (!result) {
|
||||
this.raiseError(`Actual text doesn't match expected text. Actual:\n'${actualText}'\nExpected:\n'${expectedText}'`);
|
||||
@@ -2173,7 +2207,7 @@ namespace FourSlash {
|
||||
start: diagnostic.start,
|
||||
length: diagnostic.length,
|
||||
code: diagnostic.code
|
||||
}
|
||||
};
|
||||
});
|
||||
const dedupedDiagnositcs = ts.deduplicate(diagnosticsForCodeFix, ts.equalOwnProperties);
|
||||
|
||||
@@ -2185,7 +2219,7 @@ namespace FourSlash {
|
||||
continue;
|
||||
}
|
||||
|
||||
const newActions = this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start, diagnostic.length, [diagnostic.code]);
|
||||
const newActions = this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start, diagnostic.length, [diagnostic.code], this.formatCodeSettings);
|
||||
if (newActions && newActions.length) {
|
||||
actions = actions ? actions.concat(newActions) : newActions;
|
||||
}
|
||||
@@ -2248,22 +2282,22 @@ namespace FourSlash {
|
||||
|
||||
if (expected === undefined) {
|
||||
if (actual) {
|
||||
this.raiseError(name + " failed - expected no template but got {newText: \"" + actual.newText + "\" caretOffset: " + actual.caretOffset + "}");
|
||||
this.raiseError(`${name} failed - expected no template but got {newText: "${actual.newText}", caretOffset: ${actual.caretOffset}}`);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (actual === undefined) {
|
||||
this.raiseError(name + " failed - expected the template {newText: \"" + actual.newText + "\" caretOffset: " + actual.caretOffset + "} but got nothing instead");
|
||||
this.raiseError(`${name} failed - expected the template {newText: "${expected.newText}", caretOffset: "${expected.caretOffset}"} but got nothing instead`);
|
||||
}
|
||||
|
||||
if (actual.newText !== expected.newText) {
|
||||
this.raiseError(name + " failed - expected insertion:\n" + this.clarifyNewlines(expected.newText) + "\nactual insertion:\n" + this.clarifyNewlines(actual.newText));
|
||||
this.raiseError(`${name} failed - expected insertion:\n"${this.clarifyNewlines(expected.newText)}"\nactual insertion:\n"${this.clarifyNewlines(actual.newText)}"`);
|
||||
}
|
||||
|
||||
if (actual.caretOffset !== expected.caretOffset) {
|
||||
this.raiseError(name + " failed - expected caretOffset: " + expected.caretOffset + ",\nactual caretOffset:" + actual.caretOffset);
|
||||
this.raiseError(`${name} failed - expected caretOffset: ${expected.caretOffset}\nactual caretOffset:${actual.caretOffset}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-96
@@ -34,17 +34,11 @@ var _chai: typeof chai = require("chai");
|
||||
var assert: typeof _chai.assert = _chai.assert;
|
||||
declare var __dirname: string; // Node-specific
|
||||
var global: NodeJS.Global = <any>Function("return this").call(undefined);
|
||||
declare namespace NodeJS {
|
||||
export interface Global {
|
||||
WScript: typeof WScript;
|
||||
ActiveXObject: typeof ActiveXObject;
|
||||
}
|
||||
}
|
||||
|
||||
declare var window: {};
|
||||
declare var XMLHttpRequest: {
|
||||
new(): XMLHttpRequest;
|
||||
}
|
||||
};
|
||||
interface XMLHttpRequest {
|
||||
readonly readyState: number;
|
||||
readonly responseText: string;
|
||||
@@ -60,14 +54,10 @@ namespace Utils {
|
||||
export const enum ExecutionEnvironment {
|
||||
Node,
|
||||
Browser,
|
||||
CScript
|
||||
}
|
||||
|
||||
export function getExecutionEnvironment() {
|
||||
if (typeof WScript !== "undefined" && typeof ActiveXObject === "function") {
|
||||
return ExecutionEnvironment.CScript;
|
||||
}
|
||||
else if (typeof window !== "undefined") {
|
||||
if (typeof window !== "undefined") {
|
||||
return ExecutionEnvironment.Browser;
|
||||
}
|
||||
else {
|
||||
@@ -93,7 +83,6 @@ namespace Utils {
|
||||
export function evalFile(fileContents: string, fileName: string, nodeContext?: any) {
|
||||
const environment = getExecutionEnvironment();
|
||||
switch (environment) {
|
||||
case ExecutionEnvironment.CScript:
|
||||
case ExecutionEnvironment.Browser:
|
||||
eval(fileContents);
|
||||
break;
|
||||
@@ -516,83 +505,6 @@ namespace Harness {
|
||||
export const virtualFileSystemRoot = "/";
|
||||
|
||||
namespace IOImpl {
|
||||
declare class Enumerator {
|
||||
public atEnd(): boolean;
|
||||
public moveNext(): boolean;
|
||||
public item(): any;
|
||||
constructor(o: any);
|
||||
}
|
||||
|
||||
export namespace CScript {
|
||||
let fso: any;
|
||||
if (global.ActiveXObject) {
|
||||
fso = new global.ActiveXObject("Scripting.FileSystemObject");
|
||||
}
|
||||
else {
|
||||
fso = {};
|
||||
}
|
||||
|
||||
export const args = () => ts.sys.args;
|
||||
export const getExecutingFilePath = () => ts.sys.getExecutingFilePath();
|
||||
export const exit = (exitCode: number) => ts.sys.exit(exitCode);
|
||||
export const resolvePath = (path: string) => ts.sys.resolvePath(path);
|
||||
export const getCurrentDirectory = () => ts.sys.getCurrentDirectory();
|
||||
export const newLine = () => harnessNewLine;
|
||||
export const useCaseSensitiveFileNames = () => ts.sys.useCaseSensitiveFileNames;
|
||||
|
||||
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 getEnvironmentVariable: typeof IO.getEnvironmentVariable = name => ts.sys.getEnvironmentVariable(name);
|
||||
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)) {
|
||||
fso.CreateFolder(path);
|
||||
}
|
||||
}
|
||||
|
||||
export function deleteFile(path: string) {
|
||||
if (fileExists(path)) {
|
||||
fso.DeleteFile(path, true); // true: delete read-only files
|
||||
}
|
||||
}
|
||||
|
||||
export let listFiles: typeof IO.listFiles = (path, spec?, options?) => {
|
||||
options = options || <{ recursive?: boolean; }>{};
|
||||
function filesInFolder(folder: any, root: string): string[] {
|
||||
let paths: string[] = [];
|
||||
let fc: any;
|
||||
|
||||
if (options.recursive) {
|
||||
fc = new Enumerator(folder.subfolders);
|
||||
|
||||
for (; !fc.atEnd(); fc.moveNext()) {
|
||||
paths = paths.concat(filesInFolder(fc.item(), root + "\\" + fc.item().Name));
|
||||
}
|
||||
}
|
||||
|
||||
fc = new Enumerator(folder.files);
|
||||
|
||||
for (; !fc.atEnd(); fc.moveNext()) {
|
||||
if (!spec || fc.item().Name.match(spec)) {
|
||||
paths.push(root + "\\" + fc.item().Name);
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
const folder: any = fso.GetFolder(path);
|
||||
|
||||
return filesInFolder(folder, path);
|
||||
};
|
||||
}
|
||||
|
||||
export namespace Node {
|
||||
declare const require: any;
|
||||
let fs: any, pathModule: any;
|
||||
@@ -840,16 +752,16 @@ namespace Harness {
|
||||
}
|
||||
}
|
||||
|
||||
switch (Utils.getExecutionEnvironment()) {
|
||||
case Utils.ExecutionEnvironment.CScript:
|
||||
IO = IOImpl.CScript;
|
||||
break;
|
||||
const environment = Utils.getExecutionEnvironment();
|
||||
switch (environment) {
|
||||
case Utils.ExecutionEnvironment.Node:
|
||||
IO = IOImpl.Node;
|
||||
break;
|
||||
case Utils.ExecutionEnvironment.Browser:
|
||||
IO = IOImpl.Network;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown value '${environment}' for ExecutionEnvironment.`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -873,7 +785,7 @@ namespace Harness {
|
||||
/** Aggregate various writes into a single array of lines. Useful for passing to the
|
||||
* TypeScript compiler to fill with source code or errors.
|
||||
*/
|
||||
export class WriterAggregator implements ITextWriter {
|
||||
export class WriterAggregator {
|
||||
public lines: string[] = [];
|
||||
public currentLine = <string>undefined;
|
||||
|
||||
@@ -1017,7 +929,7 @@ namespace Harness {
|
||||
}
|
||||
else {
|
||||
if (!es6TestLibFileNameSourceFileMap.get(libFileName)) {
|
||||
es6TestLibFileNameSourceFileMap.set(libFileName, createSourceFileAndAssertInvariants(libFileName, IO.readFile(libFileName), scriptTarget))
|
||||
es6TestLibFileNameSourceFileMap.set(libFileName, createSourceFileAndAssertInvariants(libFileName, IO.readFile(libFileName), scriptTarget));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -779,7 +779,7 @@ namespace Harness.LanguageService {
|
||||
start: 0
|
||||
});
|
||||
return prev;
|
||||
}
|
||||
};
|
||||
return proxy;
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
"declaration": false,
|
||||
"types": [
|
||||
"node", "mocha", "chai"
|
||||
],
|
||||
"lib": [
|
||||
"es6",
|
||||
"scripthost"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
@@ -121,6 +125,7 @@
|
||||
"./unittests/projectErrors.ts",
|
||||
"./unittests/printer.ts",
|
||||
"./unittests/transform.ts",
|
||||
"./unittests/customTransforms.ts"
|
||||
"./unittests/customTransforms.ts",
|
||||
"./unittests/textChanges.ts"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="..\harness.ts" />
|
||||
/// <reference path="..\harness.ts" />
|
||||
|
||||
namespace ts {
|
||||
interface File {
|
||||
|
||||
@@ -496,7 +496,7 @@ namespace ts.projectSystem {
|
||||
const emitOutput = host.readFile(path + ".js");
|
||||
assert.equal(emitOutput, f.content + newLine, "content of emit output should be identical with the input + newline");
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
it("should emit specified file", () => {
|
||||
const file1 = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="..\harness.ts" />
|
||||
/// <reference path="..\harness.ts" />
|
||||
/// <reference path="..\..\compiler\commandLineParser.ts" />
|
||||
|
||||
namespace ts {
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace ts {
|
||||
Harness.Baseline.runBaseline(`printerApi/${prefix}.${name}.js`, () =>
|
||||
printCallback(createPrinter({ newLine: NewLineKind.CarriageReturnLineFeed, ...options })));
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe("printFile", () => {
|
||||
@@ -45,6 +45,9 @@ namespace ts {
|
||||
|
||||
// comment9
|
||||
console.log(1 + 2);
|
||||
|
||||
// comment10
|
||||
function functionWithDefaultArgValue(argument: string = "defaultValue"): void { }
|
||||
`, ScriptTarget.ES2015);
|
||||
|
||||
printsCorrectly("default", {}, printer => printer.printFile(sourceFile));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="..\harness.ts" />
|
||||
/// <reference path="..\harness.ts" />
|
||||
/// <reference path="..\..\harness\harnessLanguageService.ts" />
|
||||
|
||||
namespace ts {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="..\..\harnessLanguageService.ts" />
|
||||
/// <reference path="..\..\harnessLanguageService.ts" />
|
||||
|
||||
interface ClassificationEntry {
|
||||
value: any;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
///<reference path='_project.ts'/>
|
||||
///<reference path='_project.ts'/>
|
||||
|
||||
describe('getFormattingEditsForRange', function() {
|
||||
//
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="..\..\harnessLanguageService.ts" />
|
||||
/// <reference path="..\..\harnessLanguageService.ts" />
|
||||
|
||||
describe("PreProcessFile:", function () {
|
||||
function test(sourceText: string, readImportFile: boolean, detectJavaScriptImports: boolean, expectedPreProcess: ts.PreProcessedFileInfo): void {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="..\harness.ts" />
|
||||
/// <reference path="..\harness.ts" />
|
||||
|
||||
const expect: typeof _chai.expect = _chai.expect;
|
||||
|
||||
|
||||
@@ -0,0 +1,794 @@
|
||||
/// <reference path="..\..\compiler\emitter.ts" />
|
||||
/// <reference path="..\..\services\textChanges.ts" />
|
||||
/// <reference path="..\harness.ts" />
|
||||
|
||||
// Some tests have trailing whitespace
|
||||
// tslint:disable trim-trailing-whitespace
|
||||
|
||||
namespace ts {
|
||||
describe("textChanges", () => {
|
||||
function findChild(name: string, n: Node) {
|
||||
return find(n);
|
||||
|
||||
function find(node: Node): Node {
|
||||
if (isDeclaration(node) && node.name && isIdentifier(node.name) && node.name.text === name) {
|
||||
return node;
|
||||
}
|
||||
else {
|
||||
return forEachChild(node, find);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const printerOptions = { newLine: NewLineKind.LineFeed };
|
||||
const newLineCharacter = getNewLineCharacter(printerOptions);
|
||||
|
||||
function getRuleProvider(action?: (opts: FormatCodeSettings) => void) {
|
||||
const options = {
|
||||
indentSize: 4,
|
||||
tabSize: 4,
|
||||
newLineCharacter,
|
||||
convertTabsToSpaces: true,
|
||||
indentStyle: ts.IndentStyle.Smart,
|
||||
insertSpaceAfterConstructor: false,
|
||||
insertSpaceAfterCommaDelimiter: true,
|
||||
insertSpaceAfterSemicolonInForStatements: true,
|
||||
insertSpaceBeforeAndAfterBinaryOperators: true,
|
||||
insertSpaceAfterKeywordsInControlFlowStatements: true,
|
||||
insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
|
||||
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
|
||||
insertSpaceBeforeFunctionParenthesis: false,
|
||||
placeOpenBraceOnNewLineForFunctions: false,
|
||||
placeOpenBraceOnNewLineForControlBlocks: false,
|
||||
};
|
||||
if (action) {
|
||||
action(options);
|
||||
}
|
||||
const rulesProvider = new formatting.RulesProvider();
|
||||
rulesProvider.ensureUpToDate(options);
|
||||
return rulesProvider;
|
||||
}
|
||||
|
||||
// validate that positions that were recovered from the printed text actually match positions that will be created if the same text is parsed.
|
||||
function verifyPositions({ text, node }: textChanges.NonFormattedText): void {
|
||||
const nodeList = flattenNodes(node);
|
||||
const sourceFile = createSourceFile("f.ts", text, ScriptTarget.ES2015);
|
||||
const parsedNodeList = flattenNodes(sourceFile.statements[0]);
|
||||
Debug.assert(nodeList.length === parsedNodeList.length);
|
||||
for (let i = 0; i < nodeList.length; i++) {
|
||||
const left = nodeList[i];
|
||||
const right = parsedNodeList[i];
|
||||
Debug.assert(left.pos === right.pos);
|
||||
Debug.assert(left.end === right.end);
|
||||
}
|
||||
|
||||
function flattenNodes(n: Node) {
|
||||
const data: (Node | NodeArray<any>)[] = [];
|
||||
walk(n);
|
||||
return data;
|
||||
|
||||
function walk(n: Node | Node[]): void {
|
||||
data.push(<any>n);
|
||||
return isArray(n) ? forEach(n, walk) : forEachChild(n, walk, walk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function runSingleFileTest(caption: string, setupFormatOptions: (opts: FormatCodeSettings) => void, text: string, validateNodes: boolean, testBlock: (sourceFile: SourceFile, changeTracker: textChanges.ChangeTracker) => void) {
|
||||
it(caption, () => {
|
||||
Harness.Baseline.runBaseline(`textChanges/${caption}.js`, () => {
|
||||
const sourceFile = createSourceFile("source.ts", text, ScriptTarget.ES2015, /*setParentNodes*/ true);
|
||||
const rulesProvider = getRuleProvider(setupFormatOptions);
|
||||
const changeTracker = new textChanges.ChangeTracker(printerOptions.newLine, rulesProvider, validateNodes ? verifyPositions : undefined);
|
||||
testBlock(sourceFile, changeTracker);
|
||||
const changes = changeTracker.getChanges();
|
||||
assert.equal(changes.length, 1);
|
||||
assert.equal(changes[0].fileName, sourceFile.fileName);
|
||||
const modified = textChanges.applyChanges(sourceFile.text, changes[0].textChanges);
|
||||
return `===ORIGINAL===${newLineCharacter}${text}${newLineCharacter}===MODIFIED===${newLineCharacter}${modified}`;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setNewLineForOpenBraceInFunctions(opts: FormatCodeSettings) {
|
||||
opts.placeOpenBraceOnNewLineForFunctions = true;
|
||||
}
|
||||
|
||||
{
|
||||
const text = `
|
||||
namespace M
|
||||
{
|
||||
namespace M2
|
||||
{
|
||||
function foo() {
|
||||
// comment 1
|
||||
const x = 1;
|
||||
|
||||
/**
|
||||
* comment 2 line 1
|
||||
* comment 2 line 2
|
||||
*/
|
||||
function f() {
|
||||
return 100;
|
||||
}
|
||||
const y = 2; // comment 3
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}`;
|
||||
runSingleFileTest("extractMethodLike", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
const statements = (<Block>(<FunctionDeclaration>findChild("foo", sourceFile)).body).statements.slice(1);
|
||||
const newFunction = createFunctionDeclaration(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
/*asteriskToken*/ undefined,
|
||||
/*name*/ "bar",
|
||||
/*typeParameters*/ undefined,
|
||||
/*parameters*/ emptyArray,
|
||||
/*type*/ createKeywordTypeNode(SyntaxKind.AnyKeyword),
|
||||
/*body */ createBlock(statements)
|
||||
);
|
||||
|
||||
changeTracker.insertNodeBefore(sourceFile, /*before*/findChild("M2", sourceFile), newFunction, { suffix: newLineCharacter });
|
||||
|
||||
// replace statements with return statement
|
||||
const newStatement = createReturn(
|
||||
createCall(
|
||||
/*expression*/ newFunction.name,
|
||||
/*typeArguments*/ undefined,
|
||||
/*argumentsArray*/ emptyArray
|
||||
));
|
||||
changeTracker.replaceNodeRange(sourceFile, statements[0], lastOrUndefined(statements), newStatement, { suffix: newLineCharacter });
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
function foo() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
function bar() {
|
||||
return 2;
|
||||
}
|
||||
`;
|
||||
runSingleFileTest("deleteRange1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteRange(sourceFile, { pos: text.indexOf("function foo"), end: text.indexOf("function bar") });
|
||||
});
|
||||
}
|
||||
function findVariableStatementContaining(name: string, sourceFile: SourceFile) {
|
||||
const varDecl = findChild(name, sourceFile);
|
||||
assert.equal(varDecl.kind, SyntaxKind.VariableDeclaration);
|
||||
const varStatement = varDecl.parent.parent;
|
||||
assert.equal(varStatement.kind, SyntaxKind.VariableStatement);
|
||||
return varStatement;
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
var x = 1; // some comment - 1
|
||||
/**
|
||||
* comment 2
|
||||
*/
|
||||
var y = 2; // comment 3
|
||||
var z = 3; // comment 4
|
||||
`;
|
||||
runSingleFileTest("deleteNode1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNode(sourceFile, findVariableStatementContaining("y", sourceFile));
|
||||
});
|
||||
runSingleFileTest("deleteNode2", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNode(sourceFile, findVariableStatementContaining("y", sourceFile), { useNonAdjustedStartPosition: true });
|
||||
});
|
||||
runSingleFileTest("deleteNode3", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNode(sourceFile, findVariableStatementContaining("y", sourceFile), { useNonAdjustedEndPosition: true });
|
||||
});
|
||||
runSingleFileTest("deleteNode4", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNode(sourceFile, findVariableStatementContaining("y", sourceFile), { useNonAdjustedStartPosition: true, useNonAdjustedEndPosition: true });
|
||||
});
|
||||
runSingleFileTest("deleteNode5", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNode(sourceFile, findVariableStatementContaining("x", sourceFile));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
// comment 1
|
||||
var x = 1; // comment 2
|
||||
// comment 3
|
||||
var y = 2; // comment 4
|
||||
var z = 3; // comment 5
|
||||
// comment 6
|
||||
var a = 4; // comment 7
|
||||
`;
|
||||
runSingleFileTest("deleteNodeRange1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile));
|
||||
});
|
||||
runSingleFileTest("deleteNodeRange2", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile),
|
||||
{ useNonAdjustedStartPosition: true });
|
||||
});
|
||||
runSingleFileTest("deleteNodeRange3", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile),
|
||||
{ useNonAdjustedEndPosition: true });
|
||||
});
|
||||
runSingleFileTest("deleteNodeRange4", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile),
|
||||
{ useNonAdjustedStartPosition: true, useNonAdjustedEndPosition: true });
|
||||
});
|
||||
}
|
||||
function createTestVariableDeclaration(name: string) {
|
||||
return createVariableDeclaration(name, /*type*/ undefined, createObjectLiteral([createPropertyAssignment("p1", createLiteral(1))], /*multiline*/ true));
|
||||
}
|
||||
function createTestClass() {
|
||||
return createClassDeclaration(
|
||||
/*decorators*/ undefined,
|
||||
[
|
||||
createToken(SyntaxKind.PublicKeyword)
|
||||
],
|
||||
"class1",
|
||||
/*typeParameters*/ undefined,
|
||||
[
|
||||
createHeritageClause(
|
||||
SyntaxKind.ImplementsKeyword,
|
||||
[
|
||||
createExpressionWithTypeArguments(/*typeArguments*/ undefined, createIdentifier("interface1"))
|
||||
]
|
||||
)
|
||||
],
|
||||
[
|
||||
createProperty(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
"property1",
|
||||
/*questionToken*/ undefined,
|
||||
createKeywordTypeNode(SyntaxKind.BooleanKeyword),
|
||||
/*initializer*/ undefined
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
// comment 1
|
||||
var x = 1; // comment 2
|
||||
// comment 3
|
||||
var y = 2; // comment 4
|
||||
var z = 3; // comment 5
|
||||
// comment 6
|
||||
var a = 4; // comment 7`;
|
||||
runSingleFileTest("replaceRange", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
changeTracker.replaceRange(sourceFile, { pos: text.indexOf("var y"), end: text.indexOf("var a") }, createTestClass(), { suffix: newLineCharacter });
|
||||
});
|
||||
runSingleFileTest("replaceRangeWithForcedIndentation", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
changeTracker.replaceRange(sourceFile, { pos: text.indexOf("var y"), end: text.indexOf("var a") }, createTestClass(), { suffix: newLineCharacter, indentation: 8, delta: 0 });
|
||||
});
|
||||
|
||||
runSingleFileTest("replaceRangeNoLineBreakBefore", setNewLineForOpenBraceInFunctions, `const x = 1, y = "2";`, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
const newNode = createTestVariableDeclaration("z1");
|
||||
changeTracker.replaceRange(sourceFile, { pos: sourceFile.text.indexOf("y"), end: sourceFile.text.indexOf(";") }, newNode);
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
namespace A {
|
||||
const x = 1, y = "2";
|
||||
}
|
||||
`;
|
||||
runSingleFileTest("replaceNode1NoLineBreakBefore", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
const newNode = createTestVariableDeclaration("z1");
|
||||
changeTracker.replaceNode(sourceFile, findChild("y", sourceFile), newNode);
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
// comment 1
|
||||
var x = 1; // comment 2
|
||||
// comment 3
|
||||
var y = 2; // comment 4
|
||||
var z = 3; // comment 5
|
||||
// comment 6
|
||||
var a = 4; // comment 7`;
|
||||
runSingleFileTest("replaceNode1", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { suffix: newLineCharacter });
|
||||
});
|
||||
runSingleFileTest("replaceNode2", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { useNonAdjustedStartPosition: true, suffix: newLineCharacter, prefix: newLineCharacter });
|
||||
});
|
||||
runSingleFileTest("replaceNode3", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { useNonAdjustedEndPosition: true, suffix: newLineCharacter });
|
||||
});
|
||||
runSingleFileTest("replaceNode4", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { useNonAdjustedStartPosition: true, useNonAdjustedEndPosition: true });
|
||||
});
|
||||
runSingleFileTest("replaceNode5", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
changeTracker.replaceNode(sourceFile, findVariableStatementContaining("x", sourceFile), createTestClass(), { useNonAdjustedStartPosition: true, useNonAdjustedEndPosition: true });
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
// comment 1
|
||||
var x = 1; // comment 2
|
||||
// comment 3
|
||||
var y = 2; // comment 4
|
||||
var z = 3; // comment 5
|
||||
// comment 6
|
||||
var a = 4; // comment 7`;
|
||||
runSingleFileTest("replaceNodeRange1", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { suffix: newLineCharacter });
|
||||
});
|
||||
runSingleFileTest("replaceNodeRange2", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { useNonAdjustedStartPosition: true, suffix: newLineCharacter, prefix: newLineCharacter });
|
||||
});
|
||||
runSingleFileTest("replaceNodeRange3", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { useNonAdjustedEndPosition: true, suffix: newLineCharacter });
|
||||
});
|
||||
runSingleFileTest("replaceNodeRange4", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { useNonAdjustedStartPosition: true, useNonAdjustedEndPosition: true });
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
// comment 1
|
||||
var x = 1; // comment 2
|
||||
// comment 3
|
||||
var y; // comment 4
|
||||
var z = 3; // comment 5
|
||||
// comment 6
|
||||
var a = 4; // comment 7`;
|
||||
runSingleFileTest("insertNodeAt1", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeAt(sourceFile, text.indexOf("var y"), createTestClass(), { suffix: newLineCharacter });
|
||||
});
|
||||
runSingleFileTest("insertNodeAt2", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeAt(sourceFile, text.indexOf("; // comment 4"), createTestVariableDeclaration("z1"));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
namespace M {
|
||||
// comment 1
|
||||
var x = 1; // comment 2
|
||||
// comment 3
|
||||
var y; // comment 4
|
||||
var z = 3; // comment 5
|
||||
// comment 6
|
||||
var a = 4; // comment 7
|
||||
}`;
|
||||
runSingleFileTest("insertNodeBefore1", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeBefore(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { suffix: newLineCharacter });
|
||||
});
|
||||
runSingleFileTest("insertNodeBefore2", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeBefore(sourceFile, findChild("M", sourceFile), createTestClass(), { suffix: newLineCharacter });
|
||||
});
|
||||
runSingleFileTest("insertNodeAfter1", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeAfter(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { suffix: newLineCharacter });
|
||||
});
|
||||
runSingleFileTest("insertNodeAfter2", setNewLineForOpenBraceInFunctions, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeAfter(sourceFile, findChild("M", sourceFile), createTestClass(), { prefix: newLineCharacter });
|
||||
});
|
||||
}
|
||||
{
|
||||
function findOpenBraceForConstructor(sourceFile: SourceFile) {
|
||||
const classDecl = <ClassDeclaration>sourceFile.statements[0];
|
||||
const constructorDecl = forEach(classDecl.members, m => m.kind === SyntaxKind.Constructor && (<ConstructorDeclaration>m).body && <ConstructorDeclaration>m);
|
||||
return constructorDecl.body.getFirstToken();
|
||||
}
|
||||
function createTestSuperCall() {
|
||||
const superCall = createCall(
|
||||
createSuper(),
|
||||
/*typeArguments*/ undefined,
|
||||
/*argumentsArray*/ emptyArray
|
||||
);
|
||||
return createStatement(superCall);
|
||||
}
|
||||
const text1 = `
|
||||
class A {
|
||||
constructor() {
|
||||
}
|
||||
}
|
||||
`;
|
||||
runSingleFileTest("insertNodeAfter3", noop, text1, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeAfter(sourceFile, findOpenBraceForConstructor(sourceFile), createTestSuperCall(), { suffix: newLineCharacter });
|
||||
});
|
||||
const text2 = `
|
||||
class A {
|
||||
constructor() {
|
||||
var x = 1;
|
||||
}
|
||||
}
|
||||
`;
|
||||
runSingleFileTest("insertNodeAfter4", noop, text2, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeAfter(sourceFile, findVariableStatementContaining("x", sourceFile), createTestSuperCall(), { suffix: newLineCharacter });
|
||||
});
|
||||
const text3 = `
|
||||
class A {
|
||||
constructor() {
|
||||
|
||||
}
|
||||
}
|
||||
`;
|
||||
runSingleFileTest("insertNodeAfter3-block with newline", noop, text3, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeAfter(sourceFile, findOpenBraceForConstructor(sourceFile), createTestSuperCall(), { suffix: newLineCharacter });
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `var a = 1, b = 2, c = 3;`;
|
||||
runSingleFileTest("deleteNodeInList1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("a", sourceFile));
|
||||
});
|
||||
runSingleFileTest("deleteNodeInList2", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("b", sourceFile));
|
||||
});
|
||||
runSingleFileTest("deleteNodeInList3", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("c", sourceFile));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `var a = 1,b = 2,c = 3;`;
|
||||
runSingleFileTest("deleteNodeInList1_1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("a", sourceFile));
|
||||
});
|
||||
runSingleFileTest("deleteNodeInList2_1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("b", sourceFile));
|
||||
});
|
||||
runSingleFileTest("deleteNodeInList3_1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("c", sourceFile));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
namespace M {
|
||||
var a = 1,
|
||||
b = 2,
|
||||
c = 3;
|
||||
}`;
|
||||
runSingleFileTest("deleteNodeInList4", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("a", sourceFile));
|
||||
});
|
||||
runSingleFileTest("deleteNodeInList5", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("b", sourceFile));
|
||||
});
|
||||
runSingleFileTest("deleteNodeInList6", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("c", sourceFile));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
namespace M {
|
||||
var a = 1, // comment 1
|
||||
// comment 2
|
||||
b = 2, // comment 3
|
||||
// comment 4
|
||||
c = 3; // comment 5
|
||||
}`;
|
||||
runSingleFileTest("deleteNodeInList4_1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("a", sourceFile));
|
||||
});
|
||||
runSingleFileTest("deleteNodeInList5_1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("b", sourceFile));
|
||||
});
|
||||
runSingleFileTest("deleteNodeInList6_1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("c", sourceFile));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
function foo(a: number, b: string, c = true) {
|
||||
return 1;
|
||||
}`;
|
||||
runSingleFileTest("deleteNodeInList7", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("a", sourceFile));
|
||||
});
|
||||
runSingleFileTest("deleteNodeInList8", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("b", sourceFile));
|
||||
});
|
||||
runSingleFileTest("deleteNodeInList9", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("c", sourceFile));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
function foo(a: number,b: string,c = true) {
|
||||
return 1;
|
||||
}`;
|
||||
runSingleFileTest("deleteNodeInList10", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("a", sourceFile));
|
||||
});
|
||||
runSingleFileTest("deleteNodeInList11", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("b", sourceFile));
|
||||
});
|
||||
runSingleFileTest("deleteNodeInList12", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("c", sourceFile));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
function foo(
|
||||
a: number,
|
||||
b: string,
|
||||
c = true) {
|
||||
return 1;
|
||||
}`;
|
||||
runSingleFileTest("deleteNodeInList13", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("a", sourceFile));
|
||||
});
|
||||
runSingleFileTest("deleteNodeInList14", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("b", sourceFile));
|
||||
});
|
||||
runSingleFileTest("deleteNodeInList15", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNodeInList(sourceFile, findChild("c", sourceFile));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
const x = 1, y = 2;`;
|
||||
runSingleFileTest("insertNodeInListAfter1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createVariableDeclaration("z", /*type*/ undefined, createLiteral(1)));
|
||||
});
|
||||
runSingleFileTest("insertNodeInListAfter2", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("y", sourceFile), createVariableDeclaration("z", /*type*/ undefined, createLiteral(1)));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
const /*x*/ x = 1, /*y*/ y = 2;`;
|
||||
runSingleFileTest("insertNodeInListAfter3", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createVariableDeclaration("z", /*type*/ undefined, createLiteral(1)));
|
||||
});
|
||||
runSingleFileTest("insertNodeInListAfter4", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("y", sourceFile), createVariableDeclaration("z", /*type*/ undefined, createLiteral(1)));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
const x = 1;`;
|
||||
runSingleFileTest("insertNodeInListAfter5", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createVariableDeclaration("z", /*type*/ undefined, createLiteral(1)));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
const x = 1,
|
||||
y = 2;`;
|
||||
runSingleFileTest("insertNodeInListAfter6", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createVariableDeclaration("z", /*type*/ undefined, createLiteral(1)));
|
||||
});
|
||||
runSingleFileTest("insertNodeInListAfter7", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("y", sourceFile), createVariableDeclaration("z", /*type*/ undefined, createLiteral(1)));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
const /*x*/ x = 1,
|
||||
/*y*/ y = 2;`;
|
||||
runSingleFileTest("insertNodeInListAfter8", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createVariableDeclaration("z", /*type*/ undefined, createLiteral(1)));
|
||||
});
|
||||
runSingleFileTest("insertNodeInListAfter9", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("y", sourceFile), createVariableDeclaration("z", /*type*/ undefined, createLiteral(1)));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
import {
|
||||
x
|
||||
} from "bar"`;
|
||||
runSingleFileTest("insertNodeInListAfter10", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createImportSpecifier(createIdentifier("b"), createIdentifier("a")));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
import {
|
||||
x // this is x
|
||||
} from "bar"`;
|
||||
runSingleFileTest("insertNodeInListAfter11", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createImportSpecifier(createIdentifier("b"), createIdentifier("a")));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
import {
|
||||
x
|
||||
} from "bar"`;
|
||||
runSingleFileTest("insertNodeInListAfter12", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createImportSpecifier(undefined, createIdentifier("a")));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
import {
|
||||
x // this is x
|
||||
} from "bar"`;
|
||||
runSingleFileTest("insertNodeInListAfter13", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createImportSpecifier(undefined, createIdentifier("a")));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
import {
|
||||
x0,
|
||||
x
|
||||
} from "bar"`;
|
||||
runSingleFileTest("insertNodeInListAfter14", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createImportSpecifier(createIdentifier("b"), createIdentifier("a")));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
import {
|
||||
x0,
|
||||
x // this is x
|
||||
} from "bar"`;
|
||||
runSingleFileTest("insertNodeInListAfter15", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createImportSpecifier(createIdentifier("b"), createIdentifier("a")));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
import {
|
||||
x0,
|
||||
x
|
||||
} from "bar"`;
|
||||
runSingleFileTest("insertNodeInListAfter16", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createImportSpecifier(undefined, createIdentifier("a")));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
import {
|
||||
x0,
|
||||
x // this is x
|
||||
} from "bar"`;
|
||||
runSingleFileTest("insertNodeInListAfter17", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createImportSpecifier(undefined, createIdentifier("a")));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
import {
|
||||
x0, x
|
||||
} from "bar"`;
|
||||
runSingleFileTest("insertNodeInListAfter18", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createImportSpecifier(undefined, createIdentifier("a")));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
class A {
|
||||
x;
|
||||
}`;
|
||||
runSingleFileTest("insertNodeAfterMultipleNodes", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
const newNodes = [];
|
||||
for (let i = 0; i < 11 /*error doesn't occur with fewer nodes*/; ++i) {
|
||||
newNodes.push(
|
||||
createProperty(undefined, undefined, i + "", undefined, undefined, undefined));
|
||||
}
|
||||
const insertAfter = findChild("x", sourceFile);
|
||||
for (const newNode of newNodes) {
|
||||
changeTracker.insertNodeAfter(sourceFile, insertAfter, newNode, { suffix: newLineCharacter });
|
||||
}
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
class A {
|
||||
x
|
||||
}
|
||||
`;
|
||||
runSingleFileTest("insertNodeAfterInClass1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), createProperty(undefined, undefined, "a", undefined, createKeywordTypeNode(SyntaxKind.BooleanKeyword), undefined), { suffix: newLineCharacter });
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
class A {
|
||||
x;
|
||||
}
|
||||
`;
|
||||
runSingleFileTest("insertNodeAfterInClass2", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), createProperty(undefined, undefined, "a", undefined, createKeywordTypeNode(SyntaxKind.BooleanKeyword), undefined), { suffix: newLineCharacter });
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
class A {
|
||||
x;
|
||||
y = 1;
|
||||
}
|
||||
`;
|
||||
runSingleFileTest("deleteNodeAfterInClass1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNode(sourceFile, findChild("x", sourceFile));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
class A {
|
||||
x
|
||||
y = 1;
|
||||
}
|
||||
`;
|
||||
runSingleFileTest("deleteNodeAfterInClass2", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
changeTracker.deleteNode(sourceFile, findChild("x", sourceFile));
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
class A {
|
||||
x = foo
|
||||
}
|
||||
`;
|
||||
runSingleFileTest("insertNodeInClassAfterNodeWithoutSeparator1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
const newNode = createProperty(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
createComputedPropertyName(createLiteral(1)),
|
||||
/*questionToken*/ undefined,
|
||||
createKeywordTypeNode(SyntaxKind.AnyKeyword),
|
||||
/*initializer*/ undefined);
|
||||
changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode, { suffix: newLineCharacter });
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
class A {
|
||||
x() {
|
||||
}
|
||||
}
|
||||
`;
|
||||
runSingleFileTest("insertNodeInClassAfterNodeWithoutSeparator2", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
const newNode = createProperty(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
createComputedPropertyName(createLiteral(1)),
|
||||
/*questionToken*/ undefined,
|
||||
createKeywordTypeNode(SyntaxKind.AnyKeyword),
|
||||
/*initializer*/ undefined);
|
||||
changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode, { suffix: newLineCharacter });
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
interface A {
|
||||
x
|
||||
}
|
||||
`;
|
||||
runSingleFileTest("insertNodeInInterfaceAfterNodeWithoutSeparator1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
const newNode = createProperty(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
createComputedPropertyName(createLiteral(1)),
|
||||
/*questionToken*/ undefined,
|
||||
createKeywordTypeNode(SyntaxKind.AnyKeyword),
|
||||
/*initializer*/ undefined);
|
||||
changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode, { suffix: newLineCharacter });
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
interface A {
|
||||
x()
|
||||
}
|
||||
`;
|
||||
runSingleFileTest("insertNodeInInterfaceAfterNodeWithoutSeparator2", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
const newNode = createProperty(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
createComputedPropertyName(createLiteral(1)),
|
||||
/*questionToken*/ undefined,
|
||||
createKeywordTypeNode(SyntaxKind.AnyKeyword),
|
||||
/*initializer*/ undefined);
|
||||
changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode, { suffix: newLineCharacter });
|
||||
});
|
||||
}
|
||||
{
|
||||
const text = `
|
||||
let x = foo
|
||||
`;
|
||||
runSingleFileTest("insertNodeInStatementListAfterNodeWithoutSeparator1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
|
||||
const newNode = createStatement(createParen(createLiteral(1)));
|
||||
changeTracker.insertNodeAfter(sourceFile, findVariableStatementContaining("x", sourceFile), newNode, { suffix: newLineCharacter });
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -65,6 +65,6 @@ namespace ts.textStorage {
|
||||
|
||||
ts1.getLineInfo(0);
|
||||
assert.isTrue(ts1.hasScriptVersionCache(), "have script version cache - 2");
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="..\harness.ts" />
|
||||
/// <reference path="..\harness.ts" />
|
||||
/// <reference path="../../server/typingsInstaller/typingsInstaller.ts" />
|
||||
|
||||
namespace ts.projectSystem {
|
||||
@@ -628,7 +628,7 @@ namespace ts.projectSystem {
|
||||
|
||||
checkProjectActualFiles(service.configuredProjects[0], []);
|
||||
checkProjectActualFiles(service.inferredProjects[0], [f1.path]);
|
||||
})
|
||||
});
|
||||
|
||||
it("create configured project without file list", () => {
|
||||
const configFile: FileOrFolder = {
|
||||
@@ -1181,7 +1181,7 @@ namespace ts.projectSystem {
|
||||
|
||||
const host = createServerHost([f1, f2, libFile]);
|
||||
const service = createProjectService(host);
|
||||
service.openExternalProject({ projectFileName: "/a/b/project", rootFiles: toExternalFiles([f1.path, f2.path]), options: {} })
|
||||
service.openExternalProject({ projectFileName: "/a/b/project", rootFiles: toExternalFiles([f1.path, f2.path]), options: {} });
|
||||
|
||||
service.openClientFile(f1.path);
|
||||
service.openClientFile(f2.path, "let x: string");
|
||||
@@ -1213,7 +1213,7 @@ namespace ts.projectSystem {
|
||||
|
||||
const host = createServerHost([f1, f2, libFile]);
|
||||
const service = createProjectService(host);
|
||||
service.openExternalProject({ projectFileName: "/a/b/project", rootFiles: [{ fileName: f1.path }, { fileName: f2.path, hasMixedContent: true }], options: {} })
|
||||
service.openExternalProject({ projectFileName: "/a/b/project", rootFiles: [{ fileName: f1.path }, { fileName: f2.path, hasMixedContent: true }], options: {} });
|
||||
|
||||
service.openClientFile(f1.path);
|
||||
service.openClientFile(f2.path, "let somelongname: string");
|
||||
@@ -2040,7 +2040,7 @@ namespace ts.projectSystem {
|
||||
|
||||
for (const f of [f2, f3]) {
|
||||
const scriptInfo = projectService.getScriptInfoForNormalizedPath(server.toNormalizedPath(f.path));
|
||||
assert.equal(scriptInfo.containingProjects.length, 0, `expect 0 containing projects for '${f.path}'`)
|
||||
assert.equal(scriptInfo.containingProjects.length, 0, `expect 0 containing projects for '${f.path}'`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2156,7 +2156,7 @@ namespace ts.projectSystem {
|
||||
projectFileName,
|
||||
rootFiles: [toExternalFile(f1.path)],
|
||||
options: {}
|
||||
})
|
||||
});
|
||||
projectService.openClientFile(f1.path, "let x = 1;\nlet y = 2;");
|
||||
|
||||
projectService.checkNumberOfProjects({ externalProjects: 1 });
|
||||
@@ -3006,6 +3006,42 @@ namespace ts.projectSystem {
|
||||
const errorResult = <protocol.Diagnostic[]>session.executeCommand(dTsFileGetErrRequest).response;
|
||||
assert.isTrue(errorResult.length === 0);
|
||||
});
|
||||
|
||||
it("should be turned on for js-only external projects with skipLibCheck=false", () => {
|
||||
const jsFile = {
|
||||
path: "/a/b/file1.js",
|
||||
content: "let x =1;"
|
||||
};
|
||||
const dTsFile = {
|
||||
path: "/a/b/file2.d.ts",
|
||||
content: `
|
||||
interface T {
|
||||
name: string;
|
||||
};
|
||||
interface T {
|
||||
name: number;
|
||||
};`
|
||||
};
|
||||
const host = createServerHost([jsFile, dTsFile]);
|
||||
const session = createSession(host);
|
||||
|
||||
const openExternalProjectRequest = makeSessionRequest<protocol.OpenExternalProjectArgs>(
|
||||
CommandNames.OpenExternalProject,
|
||||
{
|
||||
projectFileName: "project1",
|
||||
rootFiles: toExternalFiles([jsFile.path, dTsFile.path]),
|
||||
options: { skipLibCheck: false }
|
||||
}
|
||||
);
|
||||
session.executeCommand(openExternalProjectRequest);
|
||||
|
||||
const dTsFileGetErrRequest = makeSessionRequest<protocol.SemanticDiagnosticsSyncRequestArgs>(
|
||||
CommandNames.SemanticDiagnosticsSync,
|
||||
{ file: dTsFile.path }
|
||||
);
|
||||
const errorResult = <protocol.Diagnostic[]>session.executeCommand(dTsFileGetErrRequest).response;
|
||||
assert.isTrue(errorResult.length === 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("non-existing directories listed in config file input array", () => {
|
||||
@@ -3307,12 +3343,12 @@ namespace ts.projectSystem {
|
||||
isCancellationRequested: () => false,
|
||||
setRequest: requestId => {
|
||||
if (expectedRequestId === undefined) {
|
||||
assert.isTrue(false, "unexpected call")
|
||||
assert.isTrue(false, "unexpected call");
|
||||
}
|
||||
assert.equal(requestId, expectedRequestId);
|
||||
},
|
||||
resetRequest: noop
|
||||
}
|
||||
};
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, /*projectServiceEventHandler*/ undefined, cancellationToken);
|
||||
|
||||
expectedRequestId = session.getNextSeq();
|
||||
@@ -3359,13 +3395,13 @@ namespace ts.projectSystem {
|
||||
currentId = requestId;
|
||||
},
|
||||
resetRequest(requestId) {
|
||||
assert.equal(requestId, currentId, "unexpected request id in cancellation")
|
||||
assert.equal(requestId, currentId, "unexpected request id in cancellation");
|
||||
currentId = undefined;
|
||||
},
|
||||
isCancellationRequested() {
|
||||
return requestToCancel === currentId;
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
const host = createServerHost([f1, config]);
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, () => {}, cancellationToken);
|
||||
@@ -3489,6 +3525,52 @@ namespace ts.projectSystem {
|
||||
});
|
||||
});
|
||||
|
||||
describe("occurence highlight on string", () => {
|
||||
it("should be marked if only on string values", () => {
|
||||
const file1: FileOrFolder = {
|
||||
path: "/a/b/file1.ts",
|
||||
content: `let t1 = "div";\nlet t2 = "div";\nlet t3 = { "div": 123 };\nlet t4 = t3["div"];`
|
||||
};
|
||||
|
||||
const host = createServerHost([file1]);
|
||||
const session = createSession(host);
|
||||
const projectService = session.getProjectService();
|
||||
|
||||
projectService.openClientFile(file1.path);
|
||||
{
|
||||
const highlightRequest = makeSessionRequest<protocol.FileLocationRequestArgs>(
|
||||
CommandNames.Occurrences,
|
||||
{ file: file1.path, line: 1, offset: 11 }
|
||||
);
|
||||
const highlightResponse = session.executeCommand(highlightRequest).response as protocol.OccurrencesResponseItem[];
|
||||
const firstOccurence = highlightResponse[0];
|
||||
assert.isTrue(firstOccurence.isInString, "Highlights should be marked with isInString");
|
||||
}
|
||||
|
||||
{
|
||||
const highlightRequest = makeSessionRequest<protocol.FileLocationRequestArgs>(
|
||||
CommandNames.Occurrences,
|
||||
{ file: file1.path, line: 3, offset: 13 }
|
||||
);
|
||||
const highlightResponse = session.executeCommand(highlightRequest).response as protocol.OccurrencesResponseItem[];
|
||||
assert.isTrue(highlightResponse.length === 2);
|
||||
const firstOccurence = highlightResponse[0];
|
||||
assert.isUndefined(firstOccurence.isInString, "Highlights should not be marked with isInString if on property name");
|
||||
}
|
||||
|
||||
{
|
||||
const highlightRequest = makeSessionRequest<protocol.FileLocationRequestArgs>(
|
||||
CommandNames.Occurrences,
|
||||
{ file: file1.path, line: 4, offset: 14 }
|
||||
);
|
||||
const highlightResponse = session.executeCommand(highlightRequest).response as protocol.OccurrencesResponseItem[];
|
||||
assert.isTrue(highlightResponse.length === 2);
|
||||
const firstOccurence = highlightResponse[0];
|
||||
assert.isUndefined(firstOccurence.isInString, "Highlights should not be marked with isInString if on indexer");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("maxNodeModuleJsDepth for inferred projects", () => {
|
||||
it("should be set to 2 if the project has js root files", () => {
|
||||
const file1: FileOrFolder = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="../harness.ts" />
|
||||
/// <reference path="../harness.ts" />
|
||||
/// <reference path="./tsserverProjectSystem.ts" />
|
||||
/// <reference path="../../server/typingsInstaller/typingsInstaller.ts" />
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace ts.projectSystem {
|
||||
path: "/a/config.js",
|
||||
content: "export let x = 1"
|
||||
};
|
||||
const typesCache = "/cache"
|
||||
const typesCache = "/cache";
|
||||
const typesConfig = {
|
||||
path: typesCache + "/node_modules/@types/config/index.d.ts",
|
||||
content: "export let y: number;"
|
||||
@@ -74,7 +74,7 @@ namespace ts.projectSystem {
|
||||
super(host, { typesRegistry: createTypesRegistry("config"), globalTypingsCacheLocation: typesCache });
|
||||
}
|
||||
installWorker(_requestId: number, _args: string[], _cwd: string, _cb: server.typingsInstaller.RequestCompletedAction) {
|
||||
assert(false, "should not be called")
|
||||
assert(false, "should not be called");
|
||||
}
|
||||
})();
|
||||
const service = createProjectService(host, { typingsInstaller: installer });
|
||||
|
||||
Vendored
+44
-2
@@ -5,9 +5,51 @@ interface DOMTokenList {
|
||||
}
|
||||
|
||||
interface NodeList {
|
||||
[Symbol.iterator](): IterableIterator<Node>
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the list
|
||||
*/
|
||||
entries(): IterableIterator<[number, Node]>;
|
||||
/**
|
||||
* Performs the specified action for each node in an list.
|
||||
* @param callbackfn A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the list.
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
forEach(callbackfn: (value: Node, index: number, listObj: NodeList) => void, thisArg?: any): void;
|
||||
/**
|
||||
* Returns an list of keys in the list
|
||||
*/
|
||||
keys(): IterableIterator<number>;
|
||||
|
||||
/**
|
||||
* Returns an list of values in the list
|
||||
*/
|
||||
values(): IterableIterator<Node>;
|
||||
|
||||
|
||||
[Symbol.iterator](): IterableIterator<Node>;
|
||||
}
|
||||
|
||||
interface NodeListOf<TNode extends Node> {
|
||||
[Symbol.iterator](): IterableIterator<TNode>
|
||||
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the list
|
||||
*/
|
||||
entries(): IterableIterator<[number, TNode]>;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each node in an list.
|
||||
* @param callbackfn A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the list.
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
forEach(callbackfn: (value: TNode, index: number, listObj: NodeListOf<TNode>) => void, thisArg?: any): void;
|
||||
/**
|
||||
* Returns an list of keys in the list
|
||||
*/
|
||||
keys(): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an list of values in the list
|
||||
*/
|
||||
values(): IterableIterator<TNode>;
|
||||
|
||||
[Symbol.iterator](): IterableIterator<TNode>;
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -17,7 +17,7 @@ declare var Map: MapConstructor;
|
||||
|
||||
interface ReadonlyMap<K, V> {
|
||||
forEach(callbackfn: (value: V, key: K, map: ReadonlyMap<K, V>) => void, thisArg?: any): void;
|
||||
get(key: K): V|undefined;
|
||||
get(key: K): V | undefined;
|
||||
has(key: K): boolean;
|
||||
readonly size: number;
|
||||
}
|
||||
|
||||
Vendored
+18
-8
@@ -10,7 +10,9 @@ interface Array<T> {
|
||||
* @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;
|
||||
find(predicate: (this: undefined, value: T, index: number, obj: Array<T>) => boolean): T | undefined;
|
||||
find(predicate: (this: undefined, value: T, index: number, obj: Array<T>) => boolean, thisArg: undefined): T | undefined;
|
||||
find<Z>(predicate: (this: Z, value: T, index: number, obj: Array<T>) => boolean, thisArg: Z): T | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -21,7 +23,9 @@ interface Array<T> {
|
||||
* @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, index: number, obj: Array<T>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (this: undefined, value: T, index: number, obj: Array<T>) => boolean): number;
|
||||
findIndex(predicate: (this: undefined, value: T, index: number, obj: Array<T>) => boolean, thisArg: undefined): number;
|
||||
findIndex<Z>(predicate: (this: Z, value: T, index: number, obj: Array<T>) => boolean, thisArg: Z): number;
|
||||
|
||||
/**
|
||||
* Returns the this object after filling the section identified by start and end with value
|
||||
@@ -52,7 +56,9 @@ interface ArrayConstructor {
|
||||
* @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>;
|
||||
from<T, U>(arrayLike: ArrayLike<T>, mapfn: (this: undefined, v: T, k: number) => U): Array<U>;
|
||||
from<T, U>(arrayLike: ArrayLike<T>, mapfn: (this: undefined, v: T, k: number) => U, thisArg: undefined): Array<U>;
|
||||
from<Z, T, U>(arrayLike: ArrayLike<T>, mapfn: (this: Z, v: T, k: number) => U, thisArg: Z): Array<U>;
|
||||
|
||||
|
||||
/**
|
||||
@@ -262,7 +268,7 @@ interface Object {
|
||||
* Determines whether an object has a property with the specified name.
|
||||
* @param v A property name.
|
||||
*/
|
||||
hasOwnProperty(v: PropertyKey): boolean
|
||||
hasOwnProperty(v: PropertyKey): boolean;
|
||||
|
||||
/**
|
||||
* Determines whether a specified property is enumerable.
|
||||
@@ -357,7 +363,9 @@ interface ReadonlyArray<T> {
|
||||
* @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: ReadonlyArray<T>) => boolean, thisArg?: any): T | undefined;
|
||||
find(predicate: (this: undefined, value: T, index: number, obj: ReadonlyArray<T>) => boolean): T | undefined;
|
||||
find(predicate: (this: undefined, value: T, index: number, obj: ReadonlyArray<T>) => boolean, thisArg: undefined): T | undefined;
|
||||
find<Z>(predicate: (this: Z, value: T, index: number, obj: ReadonlyArray<T>) => boolean, thisArg: Z): T | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
@@ -368,7 +376,9 @@ interface ReadonlyArray<T> {
|
||||
* @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, index: number, obj: Array<T>) => boolean, thisArg?: any): number;
|
||||
findIndex(predicate: (this: undefined, value: T, index: number, obj: Array<T>) => boolean): number;
|
||||
findIndex(predicate: (this: undefined, value: T, index: number, obj: Array<T>) => boolean, thisArg: undefined): number;
|
||||
findIndex<Z>(predicate: (this: Z, value: T, index: number, obj: Array<T>) => boolean, thisArg: Z): number;
|
||||
}
|
||||
|
||||
interface RegExp {
|
||||
@@ -476,10 +486,10 @@ interface String {
|
||||
bold(): string;
|
||||
|
||||
/** Returns a <tt> HTML element */
|
||||
fixed(): string
|
||||
fixed(): string;
|
||||
|
||||
/** Returns a <font> HTML element and sets the color attribute value */
|
||||
fontcolor(color: string): string
|
||||
fontcolor(color: string): string;
|
||||
|
||||
/** Returns a <font> HTML element and sets the size attribute value */
|
||||
fontsize(size: number): string;
|
||||
|
||||
Vendored
+49
-11
@@ -54,7 +54,9 @@ interface ArrayConstructor {
|
||||
* @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>;
|
||||
from<T, U>(iterable: Iterable<T>, mapfn: (this: undefined, v: T, k: number) => U): Array<U>;
|
||||
from<T, U>(iterable: Iterable<T>, mapfn: (this: undefined, v: T, k: number) => U, thisArg: undefined): Array<U>;
|
||||
from<Z, T, U>(iterable: Iterable<T>, mapfn: (this: Z, v: T, k: number) => U, thisArg: Z): Array<U>;
|
||||
|
||||
/**
|
||||
* Creates an array from an iterable object.
|
||||
@@ -89,7 +91,7 @@ interface IArguments {
|
||||
}
|
||||
|
||||
interface Map<K, V> {
|
||||
[Symbol.iterator](): IterableIterator<[K,V]>;
|
||||
[Symbol.iterator](): IterableIterator<[K, V]>;
|
||||
entries(): IterableIterator<[K, V]>;
|
||||
keys(): IterableIterator<K>;
|
||||
values(): IterableIterator<V>;
|
||||
@@ -180,7 +182,11 @@ interface Int8ArrayConstructor {
|
||||
* @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;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number): Int8Array;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number, thisArg: undefined): Int8Array;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Int8Array;
|
||||
|
||||
from(arrayLike: Iterable<number>): Int8Array;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,7 +218,11 @@ interface Uint8ArrayConstructor {
|
||||
* @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;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number): Uint8Array;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number, thisArg: undefined): Uint8Array;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Uint8Array;
|
||||
|
||||
from(arrayLike: Iterable<number>): Uint8Array;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -247,7 +257,11 @@ interface Uint8ClampedArrayConstructor {
|
||||
* @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;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number): Uint8ClampedArray;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number, thisArg: undefined): Uint8ClampedArray;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Uint8ClampedArray;
|
||||
|
||||
from(arrayLike: Iterable<number>): Uint8ClampedArray;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -281,7 +295,11 @@ interface Int16ArrayConstructor {
|
||||
* @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;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number): Int16Array;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number, thisArg: undefined): Int16Array;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Int16Array;
|
||||
|
||||
from(arrayLike: Iterable<number>): Int16Array;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -313,7 +331,11 @@ interface Uint16ArrayConstructor {
|
||||
* @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;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number): Uint16Array;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number, thisArg: undefined): Uint16Array;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Uint16Array;
|
||||
|
||||
from(arrayLike: Iterable<number>): Uint16Array;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -345,7 +367,11 @@ interface Int32ArrayConstructor {
|
||||
* @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;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number): Int32Array;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number, thisArg: undefined): Int32Array;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Int32Array;
|
||||
|
||||
from(arrayLike: Iterable<number>): Int32Array;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -377,7 +403,11 @@ interface Uint32ArrayConstructor {
|
||||
* @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;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number): Uint32Array;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number, thisArg: undefined): Uint32Array;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Uint32Array;
|
||||
|
||||
from(arrayLike: Iterable<number>): Uint32Array;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -409,7 +439,11 @@ interface Float32ArrayConstructor {
|
||||
* @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;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number): Float32Array;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number, thisArg: undefined): Float32Array;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Float32Array;
|
||||
|
||||
from(arrayLike: Iterable<number>): Float32Array;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -441,5 +475,9 @@ interface Float64ArrayConstructor {
|
||||
* @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;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number): Float64Array;
|
||||
from(arrayLike: Iterable<number>, mapfn: (this: undefined, v: number, k: number) => number, thisArg: undefined): Float64Array;
|
||||
from<Z>(arrayLike: Iterable<number>, mapfn: (this: Z, v: number, k: number) => number, thisArg: Z): Float64Array;
|
||||
|
||||
from(arrayLike: Iterable<number>): Float64Array;
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -12,11 +12,11 @@ interface ProxyHandler<T> {
|
||||
enumerate? (target: T): PropertyKey[];
|
||||
ownKeys? (target: T): PropertyKey[];
|
||||
apply? (target: T, thisArg: any, argArray?: any): any;
|
||||
construct? (target: T, argArray: any, newTarget?: any): object
|
||||
construct? (target: T, argArray: any, newTarget?: any): object;
|
||||
}
|
||||
|
||||
interface ProxyConstructor {
|
||||
revocable<T>(target: T, handler: ProxyHandler<T>): { proxy: T; revoke: () => void; };
|
||||
new <T>(target: T, handler: ProxyHandler<T>): T
|
||||
new <T>(target: T, handler: ProxyHandler<T>): T;
|
||||
}
|
||||
declare var Proxy: ProxyConstructor;
|
||||
|
||||
Vendored
+5
-5
@@ -7,8 +7,8 @@ interface Symbol {
|
||||
}
|
||||
|
||||
interface SymbolConstructor {
|
||||
/**
|
||||
* A reference to the prototype.
|
||||
/**
|
||||
* A reference to the prototype.
|
||||
*/
|
||||
readonly prototype: Symbol;
|
||||
|
||||
@@ -16,17 +16,17 @@ interface SymbolConstructor {
|
||||
* Returns a new unique Symbol value.
|
||||
* @param description Description of the new Symbol object.
|
||||
*/
|
||||
(description?: string|number): symbol;
|
||||
(description?: string | number): symbol;
|
||||
|
||||
/**
|
||||
* Returns a Symbol object from the global symbol registry matching the given key if found.
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
Vendored
+27
-27
@@ -1,55 +1,55 @@
|
||||
/// <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.
|
||||
/**
|
||||
* 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.
|
||||
* 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
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
/**
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
@@ -165,7 +165,7 @@ interface RegExp {
|
||||
* 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
|
||||
* @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;
|
||||
@@ -241,10 +241,10 @@ interface 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.
|
||||
* 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";
|
||||
@@ -255,7 +255,7 @@ interface DataView {
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit integer values. The contents are initialized to 0. If the requested
|
||||
* 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 {
|
||||
@@ -263,7 +263,7 @@ interface Int8Array {
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* 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 {
|
||||
@@ -271,7 +271,7 @@ interface Uint8Array {
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 8-bit unsigned integer (clamped) values. The contents are initialized to 0.
|
||||
* 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 {
|
||||
@@ -279,7 +279,7 @@ interface Uint8ClampedArray {
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 16-bit signed integer values. The contents are initialized to 0. If the
|
||||
* 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 {
|
||||
@@ -287,7 +287,7 @@ interface Int16Array {
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 16-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* 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 {
|
||||
@@ -295,7 +295,7 @@ interface Uint16Array {
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit signed integer values. The contents are initialized to 0. If the
|
||||
* 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 {
|
||||
@@ -303,7 +303,7 @@ interface Int32Array {
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 32-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* 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 {
|
||||
@@ -319,7 +319,7 @@ interface Float32Array {
|
||||
}
|
||||
|
||||
/**
|
||||
* A typed array of 64-bit float values. The contents are initialized to 0. If the requested
|
||||
* 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 {
|
||||
|
||||
Vendored
+2
-2
@@ -13,8 +13,8 @@ interface SharedArrayBuffer {
|
||||
length: number;
|
||||
/**
|
||||
* Returns a section of an SharedArrayBuffer.
|
||||
*/
|
||||
slice(begin:number, end?:number): SharedArrayBuffer;
|
||||
*/
|
||||
slice(begin: number, end?: number): SharedArrayBuffer;
|
||||
readonly [Symbol.species]: SharedArrayBuffer;
|
||||
readonly [Symbol.toStringTag]: "SharedArrayBuffer";
|
||||
}
|
||||
|
||||
Vendored
+27
-27
@@ -1,27 +1,27 @@
|
||||
interface String {
|
||||
/**
|
||||
* Pads the current string with a given string (possibly repeated) so that the resulting string reaches a given length.
|
||||
* The padding is applied from the start (left) of the current string.
|
||||
*
|
||||
* @param maxLength The length of the resulting string once the current string has been padded.
|
||||
* If this parameter is smaller than the current string's length, the current string will be returned as it is.
|
||||
*
|
||||
* @param fillString The string to pad the current string with.
|
||||
* If this string is too long, it will be truncated and the left-most part will be applied.
|
||||
* The default value for this parameter is " " (U+0020).
|
||||
*/
|
||||
padStart(maxLength: number, fillString?: string): string;
|
||||
|
||||
/**
|
||||
* Pads the current string with a given string (possibly repeated) so that the resulting string reaches a given length.
|
||||
* The padding is applied from the end (right) of the current string.
|
||||
*
|
||||
* @param maxLength The length of the resulting string once the current string has been padded.
|
||||
* If this parameter is smaller than the current string's length, the current string will be returned as it is.
|
||||
*
|
||||
* @param fillString The string to pad the current string with.
|
||||
* If this string is too long, it will be truncated and the left-most part will be applied.
|
||||
* The default value for this parameter is " " (U+0020).
|
||||
*/
|
||||
padEnd(maxLength: number, fillString?: string): string;
|
||||
}
|
||||
interface String {
|
||||
/**
|
||||
* Pads the current string with a given string (possibly repeated) so that the resulting string reaches a given length.
|
||||
* The padding is applied from the start (left) of the current string.
|
||||
*
|
||||
* @param maxLength The length of the resulting string once the current string has been padded.
|
||||
* If this parameter is smaller than the current string's length, the current string will be returned as it is.
|
||||
*
|
||||
* @param fillString The string to pad the current string with.
|
||||
* If this string is too long, it will be truncated and the left-most part will be applied.
|
||||
* The default value for this parameter is " " (U+0020).
|
||||
*/
|
||||
padStart(maxLength: number, fillString?: string): string;
|
||||
|
||||
/**
|
||||
* Pads the current string with a given string (possibly repeated) so that the resulting string reaches a given length.
|
||||
* The padding is applied from the end (right) of the current string.
|
||||
*
|
||||
* @param maxLength The length of the resulting string once the current string has been padded.
|
||||
* If this parameter is smaller than the current string's length, the current string will be returned as it is.
|
||||
*
|
||||
* @param fillString The string to pad the current string with.
|
||||
* If this string is too long, it will be truncated and the left-most part will be applied.
|
||||
* The default value for this parameter is " " (U+0020).
|
||||
*/
|
||||
padEnd(maxLength: number, fillString?: string): string;
|
||||
}
|
||||
|
||||
Vendored
+302
-138
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
@@ -29,7 +29,7 @@ interface TextStreamBase {
|
||||
|
||||
/**
|
||||
* Closes a text stream.
|
||||
* It is not necessary to close standard streams; they close automatically when the process ends. If
|
||||
* It is not necessary to close standard streams; they close automatically when the process ends. If
|
||||
* you close a standard stream, be aware that any other pointers to that standard stream become invalid.
|
||||
*/
|
||||
Close(): void;
|
||||
|
||||
Vendored
+2
-2
@@ -1,6 +1,6 @@
|
||||
|
||||
/////////////////////////////
|
||||
/// WorkerGlobalScope APIs
|
||||
/// WorkerGlobalScope APIs
|
||||
/////////////////////////////
|
||||
// These are only available in a Web Worker
|
||||
// These are only available in a Web Worker
|
||||
declare function importScripts(...urls: string[]): void;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/// <reference path="..\compiler\commandLineParser.ts" />
|
||||
/// <reference path="..\compiler\commandLineParser.ts" />
|
||||
/// <reference path="..\services\services.ts" />
|
||||
/// <reference path="session.ts" />
|
||||
/// <reference types="node" />
|
||||
|
||||
namespace ts.server {
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ function createCancellationToken(args: string[]): ServerCancellationToken {
|
||||
// when client wants to signal cancellation it should create a named pipe with name=<cancellationPipeName>
|
||||
// server will synchronously check the presence of the pipe and treat its existance as indicator that current request should be canceled.
|
||||
// in case if client prefers to use more fine-grained schema than one name for all request it can add '*' to the end of cancelellationPipeName.
|
||||
// in this case pipe name will be build dynamically as <cancellationPipeName><request_seq>.
|
||||
// in this case pipe name will be build dynamically as <cancellationPipeName><request_seq>.
|
||||
if (cancellationPipeName.charAt(cancellationPipeName.length - 1) === "*") {
|
||||
const namePrefix = cancellationPipeName.slice(0, -1);
|
||||
if (namePrefix.length === 0 || namePrefix.indexOf("*") >= 0) {
|
||||
@@ -48,7 +48,7 @@ function createCancellationToken(args: string[]): ServerCancellationToken {
|
||||
return {
|
||||
isCancellationRequested: () => perRequestPipeName !== undefined && pipeExists(perRequestPipeName),
|
||||
setRequest(requestId: number) {
|
||||
currentRequestId = currentRequestId;
|
||||
currentRequestId = requestId;
|
||||
perRequestPipeName = namePrefix + requestId;
|
||||
},
|
||||
resetRequest(requestId: number) {
|
||||
@@ -67,4 +67,4 @@ function createCancellationToken(args: string[]): ServerCancellationToken {
|
||||
};
|
||||
}
|
||||
}
|
||||
export = createCancellationToken;
|
||||
export = createCancellationToken;
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
"module": "commonjs",
|
||||
"types": [
|
||||
"node"
|
||||
],
|
||||
"lib": [
|
||||
"es6"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
export class SessionClient implements LanguageService {
|
||||
private sequence: number = 0;
|
||||
private sequence = 0;
|
||||
private lineMaps: ts.Map<number[]> = ts.createMap<number[]>();
|
||||
private messages: string[] = [];
|
||||
private lastRenameEntry: RenameEntry;
|
||||
@@ -382,7 +382,9 @@ namespace ts.server {
|
||||
const end = this.lineOffsetToPosition(fileName, entry.end);
|
||||
return {
|
||||
fileName,
|
||||
textSpan: ts.createTextSpanFromBounds(start, end)
|
||||
textSpan: ts.createTextSpanFromBounds(start, end),
|
||||
kind: ScriptElementKind.unknown,
|
||||
displayParts: []
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="..\compiler\commandLineParser.ts" />
|
||||
/// <reference path="..\compiler\commandLineParser.ts" />
|
||||
/// <reference path="..\services\services.ts" />
|
||||
/// <reference path="utilities.ts" />
|
||||
/// <reference path="session.ts" />
|
||||
@@ -140,7 +140,7 @@ namespace ts.server {
|
||||
getScriptKind: _ => undefined,
|
||||
hasMixedContent: (fileName, extraFileExtensions) => {
|
||||
const mixedContentExtensions = ts.map(ts.filter(extraFileExtensions, item => item.isMixedContent), item => item.extension);
|
||||
return forEach(mixedContentExtensions, extension => fileExtensionIs(fileName, extension))
|
||||
return forEach(mixedContentExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1377,7 +1377,7 @@ namespace ts.server {
|
||||
|
||||
// close projects that were missing in the input list
|
||||
forEachKey(projectsToClose, externalProjectName => {
|
||||
this.closeExternalProject(externalProjectName, /*suppressRefresh*/ true)
|
||||
this.closeExternalProject(externalProjectName, /*suppressRefresh*/ true);
|
||||
});
|
||||
|
||||
this.refreshInferredProjects();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="..\services\services.ts" />
|
||||
/// <reference path="..\services\services.ts" />
|
||||
/// <reference path="utilities.ts"/>
|
||||
/// <reference path="scriptInfo.ts"/>
|
||||
/// <reference path="lsHost.ts"/>
|
||||
@@ -723,7 +723,7 @@ namespace ts.server {
|
||||
const fileName = resolvedTypeReferenceDirective.resolvedFileName;
|
||||
const typeFilePath = toPath(fileName, currentDirectory, getCanonicalFileName);
|
||||
referencedFiles.set(typeFilePath, true);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
const allFileNames = arrayFrom(referencedFiles.keys()) as Path[];
|
||||
@@ -745,7 +745,7 @@ namespace ts.server {
|
||||
const id = nextId;
|
||||
nextId++;
|
||||
return makeInferredProjectName(id);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
private _isJsInferredProject = false;
|
||||
|
||||
@@ -621,6 +621,11 @@ namespace ts.server.protocol {
|
||||
* True if the occurrence is a write location, false otherwise.
|
||||
*/
|
||||
isWriteAccess: boolean;
|
||||
|
||||
/**
|
||||
* True if the occurrence is in a string, undefined otherwise;
|
||||
*/
|
||||
isInString?: true;
|
||||
}
|
||||
|
||||
export interface OccurrencesResponse extends Response {
|
||||
@@ -2127,6 +2132,17 @@ namespace ts.server.protocol {
|
||||
payload: any;
|
||||
}
|
||||
|
||||
export type TypesInstallerInitializationFailedEventName = "typesInstallerInitializationFailed";
|
||||
|
||||
export interface TypesInstallerInitializationFailedEvent extends Event {
|
||||
event: TypesInstallerInitializationFailedEventName;
|
||||
body: TypesInstallerInitializationFailedEventBody;
|
||||
}
|
||||
|
||||
export interface TypesInstallerInitializationFailedEventBody {
|
||||
message: string;
|
||||
}
|
||||
|
||||
export type TypingsInstalledTelemetryEventName = "typingsInstalled";
|
||||
|
||||
export interface TypingsInstalledTelemetryEventBody extends TelemetryEventBody {
|
||||
@@ -2218,6 +2234,7 @@ namespace ts.server.protocol {
|
||||
insertSpaceAfterFunctionKeywordForAnonymousFunctions?: boolean;
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis?: boolean;
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets?: boolean;
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces?: boolean;
|
||||
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces?: boolean;
|
||||
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean;
|
||||
insertSpaceBeforeFunctionParenthesis?: boolean;
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace ts.server {
|
||||
|
||||
public reloadFromFile(tempFileName?: string) {
|
||||
if (this.svc || (tempFileName !== this.fileName)) {
|
||||
this.reload(this.getFileText(tempFileName))
|
||||
this.reload(this.getFileText(tempFileName));
|
||||
}
|
||||
else {
|
||||
this.setText(undefined);
|
||||
|
||||
+54
-31
@@ -47,14 +47,14 @@ namespace ts.server {
|
||||
if (process.env.XDG_CACHE_HOME) {
|
||||
return process.env.XDG_CACHE_HOME;
|
||||
}
|
||||
const usersDir = platformIsDarwin ? "Users" : "home"
|
||||
const usersDir = platformIsDarwin ? "Users" : "home";
|
||||
const homePath = (os.homedir && os.homedir()) ||
|
||||
process.env.HOME ||
|
||||
((process.env.LOGNAME || process.env.USER) && `/${usersDir}/${process.env.LOGNAME || process.env.USER}`) ||
|
||||
os.tmpdir();
|
||||
const cacheFolder = platformIsDarwin
|
||||
? "Library/Caches"
|
||||
: ".cache"
|
||||
: ".cache";
|
||||
return combinePaths(normalizeSlashes(homePath), cacheFolder);
|
||||
}
|
||||
|
||||
@@ -131,6 +131,14 @@ namespace ts.server {
|
||||
constructor(private readonly logFilename: string,
|
||||
private readonly traceToConsole: boolean,
|
||||
private readonly level: LogLevel) {
|
||||
if (this.logFilename) {
|
||||
try {
|
||||
this.fd = fs.openSync(this.logFilename, "w");
|
||||
}
|
||||
catch (_) {
|
||||
// swallow the error and keep logging disabled if file cannot be opened
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static padStringRight(str: string, padding: string) {
|
||||
@@ -175,11 +183,6 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
msg(s: string, type: Msg.Types = Msg.Err) {
|
||||
if (this.fd < 0) {
|
||||
if (this.logFilename) {
|
||||
this.fd = fs.openSync(this.logFilename, "w");
|
||||
}
|
||||
}
|
||||
if (this.fd >= 0 || this.traceToConsole) {
|
||||
s = s + "\n";
|
||||
const prefix = Logger.padStringRight(type + " " + this.seq.toString(), " ");
|
||||
@@ -301,11 +304,23 @@ namespace ts.server {
|
||||
});
|
||||
}
|
||||
|
||||
private handleMessage(response: SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes) {
|
||||
private handleMessage(response: SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes | InitializationFailedResponse) {
|
||||
if (this.logger.hasLevel(LogLevel.verbose)) {
|
||||
this.logger.info(`Received response: ${JSON.stringify(response)}`);
|
||||
}
|
||||
|
||||
if (response.kind === EventInitializationFailed) {
|
||||
if (!this.eventSender) {
|
||||
return;
|
||||
}
|
||||
const body: protocol.TypesInstallerInitializationFailedEventBody = {
|
||||
message: response.message
|
||||
};
|
||||
const eventName: protocol.TypesInstallerInitializationFailedEventName = "typesInstallerInitializationFailed";
|
||||
this.eventSender.event(body, eventName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.kind === EventBeginInstallTypes) {
|
||||
if (!this.eventSender) {
|
||||
return;
|
||||
@@ -410,6 +425,9 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
function parseLoggingEnvironmentString(logEnvStr: string): LogOptions {
|
||||
if (!logEnvStr) {
|
||||
return {};
|
||||
}
|
||||
const logEnv: LogOptions = { logToFile: true };
|
||||
const args = logEnvStr.split(" ");
|
||||
const len = args.length - 1;
|
||||
@@ -422,8 +440,8 @@ namespace ts.server {
|
||||
logEnv.file = stripQuotes(value);
|
||||
break;
|
||||
case "-level":
|
||||
const level: LogLevel = (<any>LogLevel)[value];
|
||||
logEnv.detailLevel = typeof level === "number" ? level : LogLevel.normal;
|
||||
const level = getLogLevel(value);
|
||||
logEnv.detailLevel = level !== undefined ? level : LogLevel.normal;
|
||||
break;
|
||||
case "-traceToConsole":
|
||||
logEnv.traceToConsole = value.toLowerCase() === "true";
|
||||
@@ -437,28 +455,32 @@ namespace ts.server {
|
||||
return logEnv;
|
||||
}
|
||||
|
||||
// TSS_LOG "{ level: "normal | verbose | terse", file?: string}"
|
||||
function createLoggerFromEnv() {
|
||||
let fileName: string = undefined;
|
||||
let detailLevel = LogLevel.normal;
|
||||
let traceToConsole = false;
|
||||
const logEnvStr = process.env["TSS_LOG"];
|
||||
if (logEnvStr) {
|
||||
const logEnv = parseLoggingEnvironmentString(logEnvStr);
|
||||
if (logEnv.logToFile) {
|
||||
if (logEnv.file) {
|
||||
fileName = logEnv.file;
|
||||
}
|
||||
else {
|
||||
fileName = __dirname + "/.log" + process.pid.toString();
|
||||
function getLogLevel(level: string) {
|
||||
if (level) {
|
||||
const l = level.toLowerCase();
|
||||
for (const name in LogLevel) {
|
||||
if (isNaN(+name) && l === name.toLowerCase()) {
|
||||
return <LogLevel><any>LogLevel[name];
|
||||
}
|
||||
}
|
||||
if (logEnv.detailLevel) {
|
||||
detailLevel = logEnv.detailLevel;
|
||||
}
|
||||
traceToConsole = logEnv.traceToConsole;
|
||||
}
|
||||
return new Logger(fileName, traceToConsole, detailLevel);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// TSS_LOG "{ level: "normal | verbose | terse", file?: string}"
|
||||
function createLogger() {
|
||||
const cmdLineLogFileName = findArgument("--logFile");
|
||||
const cmdLineVerbosity = getLogLevel(findArgument("--logVerbosity"));
|
||||
const envLogOptions = parseLoggingEnvironmentString(process.env["TSS_LOG"]);
|
||||
|
||||
const logFileName = cmdLineLogFileName
|
||||
? stripQuotes(cmdLineLogFileName)
|
||||
: envLogOptions.logToFile
|
||||
? envLogOptions.file || (__dirname + "/.log" + process.pid.toString())
|
||||
: undefined;
|
||||
|
||||
const logVerbosity = cmdLineVerbosity || envLogOptions.detailLevel;
|
||||
return new Logger(logFileName, envLogOptions.traceToConsole, logVerbosity);
|
||||
}
|
||||
// This places log file in the directory containing editorServices.js
|
||||
// TODO: check that this location is writable
|
||||
@@ -555,7 +577,6 @@ namespace ts.server {
|
||||
// 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: Buffer[] = [];
|
||||
let canWrite = true;
|
||||
@@ -607,6 +628,8 @@ namespace ts.server {
|
||||
return s.length > 2 && s.charCodeAt(0) === CharacterCodes.slash && s.charCodeAt(1) === CharacterCodes.slash;
|
||||
}
|
||||
|
||||
const logger = createLogger();
|
||||
|
||||
const sys = <ServerHost>ts.sys;
|
||||
// use watchGuard process on Windows when node version is 4 or later
|
||||
const useWatchGuard = process.platform === "win32" && getNodeMajorVersion() >= 4;
|
||||
@@ -653,7 +676,7 @@ namespace ts.server {
|
||||
// this drive is unsafe - return no-op watcher
|
||||
return { close() { } };
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Override sys.write because fs.writeSync is not reliable on Node 4
|
||||
|
||||
+15
-16
@@ -26,14 +26,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
function shouldSkipSematicCheck(project: Project) {
|
||||
if (project.getCompilerOptions().skipLibCheck !== undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((project.projectKind === ProjectKind.Inferred || project.projectKind === ProjectKind.External) && project.isJsOnlyProject()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return (project.projectKind === ProjectKind.Inferred || project.projectKind === ProjectKind.External) && project.isJsOnlyProject();
|
||||
}
|
||||
|
||||
interface FileStart {
|
||||
@@ -226,7 +219,7 @@ namespace ts.server {
|
||||
|
||||
/**
|
||||
* Represents operation that can schedule its next step to be executed later.
|
||||
* Scheduling is done via instance of NextStep. If on current step subsequent step was not scheduled - operation is assumed to be completed.
|
||||
* Scheduling is done via instance of NextStep. If on current step subsequent step was not scheduled - operation is assumed to be completed.
|
||||
*/
|
||||
class MultistepOperation {
|
||||
private requestId: number;
|
||||
@@ -239,7 +232,7 @@ namespace ts.server {
|
||||
this.next = {
|
||||
immediate: action => this.immediate(action),
|
||||
delay: (ms, action) => this.delay(ms, action)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public startNew(action: (next: NextStep) => void) {
|
||||
@@ -262,7 +255,7 @@ namespace ts.server {
|
||||
|
||||
private immediate(action: () => void) {
|
||||
const requestId = this.requestId;
|
||||
Debug.assert(requestId === this.operationHost.getCurrentRequestId(), "immediate: incorrect request id")
|
||||
Debug.assert(requestId === this.operationHost.getCurrentRequestId(), "immediate: incorrect request id");
|
||||
this.setImmediateId(this.operationHost.getServerHost().setImmediate(() => {
|
||||
this.immediateId = undefined;
|
||||
this.operationHost.executeWithRequestId(requestId, () => this.executeAction(action));
|
||||
@@ -271,7 +264,7 @@ namespace ts.server {
|
||||
|
||||
private delay(ms: number, action: () => void) {
|
||||
const requestId = this.requestId;
|
||||
Debug.assert(requestId === this.operationHost.getCurrentRequestId(), "delay: incorrect request id")
|
||||
Debug.assert(requestId === this.operationHost.getCurrentRequestId(), "delay: incorrect request id");
|
||||
this.setTimerHandle(this.operationHost.getServerHost().setTimeout(() => {
|
||||
this.timerHandle = undefined;
|
||||
this.operationHost.executeWithRequestId(requestId, () => this.executeAction(action));
|
||||
@@ -351,7 +344,7 @@ namespace ts.server {
|
||||
logError: (err, cmd) => this.logError(err, cmd),
|
||||
sendRequestCompletedEvent: requestId => this.sendRequestCompletedEvent(requestId),
|
||||
isCancellationRequested: () => cancellationToken.isCancellationRequested()
|
||||
}
|
||||
};
|
||||
this.errorCheck = new MultistepOperation(multistepOperationHost);
|
||||
this.projectService = new ProjectService(host, logger, cancellationToken, useSingleInferredProject, typingsInstaller, this.eventHander);
|
||||
this.gcTimer = new GcTimer(host, /*delay*/ 7000, logger);
|
||||
@@ -651,16 +644,21 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
return occurrences.map(occurrence => {
|
||||
const { fileName, isWriteAccess, textSpan } = occurrence;
|
||||
const { fileName, isWriteAccess, textSpan, isInString } = occurrence;
|
||||
const scriptInfo = project.getScriptInfo(fileName);
|
||||
const start = scriptInfo.positionToLineOffset(textSpan.start);
|
||||
const end = scriptInfo.positionToLineOffset(ts.textSpanEnd(textSpan));
|
||||
return {
|
||||
const result: protocol.OccurrencesResponseItem = {
|
||||
start,
|
||||
end,
|
||||
file: fileName,
|
||||
isWriteAccess,
|
||||
};
|
||||
// no need to serialize the property if it is not true
|
||||
if (isInString) {
|
||||
result.isInString = isInString;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1420,8 +1418,9 @@ namespace ts.server {
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
|
||||
const startPosition = getStartPosition();
|
||||
const endPosition = getEndPosition();
|
||||
const formatOptions = this.projectService.getFormatCodeOptions(file);
|
||||
|
||||
const codeActions = project.getLanguageService().getCodeFixesAtPosition(file, startPosition, endPosition, args.errorCodes);
|
||||
const codeActions = project.getLanguageService().getCodeFixesAtPosition(file, startPosition, endPosition, args.errorCodes, formatOptions);
|
||||
if (!codeActions) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace ts.server {
|
||||
export const ActionInvalidate: ActionInvalidate = "action::invalidate";
|
||||
export const EventBeginInstallTypes: EventBeginInstallTypes = "event::beginInstallTypes";
|
||||
export const EventEndInstallTypes: EventEndInstallTypes = "event::endInstallTypes";
|
||||
export const EventInitializationFailed: EventInitializationFailed = "event::initializationFailed";
|
||||
|
||||
export namespace Arguments {
|
||||
export const GlobalCacheLocation = "--globalTypingsCacheLocation";
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
"target": "es5",
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"declaration": true
|
||||
"declaration": true,
|
||||
"types": []
|
||||
},
|
||||
"files": [
|
||||
"editorServices.ts",
|
||||
|
||||
+7
-1
@@ -47,9 +47,15 @@ declare namespace ts.server {
|
||||
export type ActionInvalidate = "action::invalidate";
|
||||
export type EventBeginInstallTypes = "event::beginInstallTypes";
|
||||
export type EventEndInstallTypes = "event::endInstallTypes";
|
||||
export type EventInitializationFailed = "event::initializationFailed";
|
||||
|
||||
export interface TypingInstallerResponse {
|
||||
readonly kind: ActionSet | ActionInvalidate | EventBeginInstallTypes | EventEndInstallTypes;
|
||||
readonly kind: ActionSet | ActionInvalidate | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
|
||||
}
|
||||
|
||||
export interface InitializationFailedResponse extends TypingInstallerResponse {
|
||||
readonly kind: EventInitializationFailed;
|
||||
readonly message: string;
|
||||
}
|
||||
|
||||
export interface ProjectResponse extends TypingInstallerResponse {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="typingsInstaller.ts"/>
|
||||
/// <reference path="typingsInstaller.ts"/>
|
||||
/// <reference types="node" />
|
||||
|
||||
namespace ts.server.typingsInstaller {
|
||||
@@ -13,14 +13,20 @@ namespace ts.server.typingsInstaller {
|
||||
} = require("path");
|
||||
|
||||
class FileLog implements Log {
|
||||
private logEnabled = true;
|
||||
constructor(private readonly logFile?: string) {
|
||||
}
|
||||
|
||||
isEnabled() {
|
||||
return this.logFile !== undefined;
|
||||
return this.logEnabled && this.logFile !== undefined;
|
||||
}
|
||||
writeLine(text: string) {
|
||||
fs.appendFileSync(this.logFile, text + sys.newLine);
|
||||
try {
|
||||
fs.appendFileSync(this.logFile, text + sys.newLine);
|
||||
}
|
||||
catch (e) {
|
||||
this.logEnabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,15 +67,15 @@ namespace ts.server.typingsInstaller {
|
||||
return combinePaths(normalizeSlashes(globalTypingsCacheLocation), `node_modules/${TypesRegistryPackageName}/index.json`);
|
||||
}
|
||||
|
||||
type ExecSync = {
|
||||
(command: string, options: { cwd: string, stdio?: "ignore" }): any
|
||||
}
|
||||
type ExecSync = (command: string, options: { cwd: string, stdio?: "ignore" }) => any;
|
||||
|
||||
export class NodeTypingsInstaller extends TypingsInstaller {
|
||||
private readonly execSync: ExecSync;
|
||||
private readonly npmPath: string;
|
||||
readonly typesRegistry: Map<void>;
|
||||
|
||||
private delayedInitializationError: InitializationFailedResponse;
|
||||
|
||||
constructor(globalTypingsCacheLocation: string, throttleLimit: number, log: Log) {
|
||||
super(
|
||||
sys,
|
||||
@@ -95,6 +101,11 @@ namespace ts.server.typingsInstaller {
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`Error updating ${TypesRegistryPackageName} package: ${(<Error>e).message}`);
|
||||
}
|
||||
// store error info to report it later when it is known that server is already listening to events from typings installer
|
||||
this.delayedInitializationError = {
|
||||
kind: "event::initializationFailed",
|
||||
message: (<Error>e).message
|
||||
};
|
||||
}
|
||||
|
||||
this.typesRegistry = loadTypesRegistryFile(getTypesRegistryFileLocation(globalTypingsCacheLocation), this.installTypingHost, this.log);
|
||||
@@ -102,6 +113,11 @@ namespace ts.server.typingsInstaller {
|
||||
|
||||
listen() {
|
||||
process.on("message", (req: DiscoverTypings | CloseProject) => {
|
||||
if (this.delayedInitializationError) {
|
||||
// report initializationFailed error
|
||||
this.sendResponse(this.delayedInitializationError);
|
||||
this.delayedInitializationError = undefined;
|
||||
}
|
||||
switch (req.kind) {
|
||||
case "discover":
|
||||
this.install(req);
|
||||
@@ -112,7 +128,7 @@ namespace ts.server.typingsInstaller {
|
||||
});
|
||||
}
|
||||
|
||||
protected sendResponse(response: SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes) {
|
||||
protected sendResponse(response: SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes | InitializationFailedResponse) {
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`Sending response: ${JSON.stringify(response)}`);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
"outFile": "../../../built/local/typingsInstaller.js",
|
||||
"types": [
|
||||
"node"
|
||||
],
|
||||
"lib": [
|
||||
"es6",
|
||||
"scripthost"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="../../compiler/core.ts" />
|
||||
/// <reference path="../../compiler/core.ts" />
|
||||
/// <reference path="../../compiler/moduleNameResolver.ts" />
|
||||
/// <reference path="../../services/jsTyping.ts"/>
|
||||
/// <reference path="../types.ts"/>
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
{
|
||||
"extends": "../../tsconfig-base",
|
||||
"extends": "../../tsconfig-base",
|
||||
"compilerOptions": {
|
||||
"removeComments": true,
|
||||
"outFile": "../../../built/local/watchGuard.js"
|
||||
"outFile": "../../../built/local/watchGuard.js",
|
||||
"types": [
|
||||
"node"
|
||||
],
|
||||
"lib": [
|
||||
"es6"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"watchGuard.ts"
|
||||
|
||||
@@ -11,7 +11,7 @@ const fs: { watch(directoryName: string, options: any, callback: () => {}): any
|
||||
// This means that here we treat any result (success or exception) from fs.watch as success since it does not tear down the process.
|
||||
// The only case that should be considered as failure - when watchGuard process crashes.
|
||||
try {
|
||||
const watcher = fs.watch(directoryName, { recursive: true }, () => ({}))
|
||||
const watcher = fs.watch(directoryName, { recursive: true }, () => ({}));
|
||||
watcher.close();
|
||||
}
|
||||
catch (_e) {
|
||||
|
||||
@@ -370,8 +370,8 @@ namespace ts.BreakpointResolver {
|
||||
}
|
||||
|
||||
function textSpanFromVariableDeclaration(variableDeclaration: VariableDeclaration): TextSpan {
|
||||
const declarations = variableDeclaration.parent.declarations;
|
||||
if (declarations && declarations[0] === variableDeclaration) {
|
||||
if (variableDeclaration.parent.kind === SyntaxKind.VariableDeclarationList &&
|
||||
variableDeclaration.parent.declarations[0] === variableDeclaration) {
|
||||
// First declaration - include let keyword
|
||||
return textSpan(findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent), variableDeclaration);
|
||||
}
|
||||
@@ -400,8 +400,8 @@ namespace ts.BreakpointResolver {
|
||||
return textSpanFromVariableDeclaration(variableDeclaration);
|
||||
}
|
||||
|
||||
const declarations = variableDeclaration.parent.declarations;
|
||||
if (declarations && declarations[0] !== variableDeclaration) {
|
||||
if (variableDeclaration.parent.kind === SyntaxKind.VariableDeclarationList &&
|
||||
variableDeclaration.parent.declarations[0] !== variableDeclaration) {
|
||||
// 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,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* @internal */
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export interface CodeFix {
|
||||
errorCodes: number[];
|
||||
@@ -13,6 +13,7 @@ namespace ts {
|
||||
newLineCharacter: string;
|
||||
host: LanguageServiceHost;
|
||||
cancellationToken: CancellationToken;
|
||||
rulesProvider: formatting.RulesProvider;
|
||||
}
|
||||
|
||||
export namespace codefix {
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace ts.codefix {
|
||||
const classDecl = token.parent as ClassLikeDeclaration;
|
||||
const startPos = classDecl.members.pos;
|
||||
|
||||
const classType = checker.getTypeAtLocation(classDecl) as InterfaceType;
|
||||
const instantiatedExtendsType = checker.getBaseTypes(classType)[0];
|
||||
const extendsNode = getClassExtendsHeritageClauseElement(classDecl);
|
||||
const instantiatedExtendsType = checker.getTypeAtLocation(extendsNode);
|
||||
|
||||
// Note that this is ultimately derived from a map indexed by symbol names,
|
||||
// so duplicates cannot occur.
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace ts.codefix {
|
||||
}
|
||||
|
||||
const startPos: number = classDecl.members.pos;
|
||||
const classType = checker.getTypeAtLocation(classDecl);
|
||||
const classType = checker.getTypeAtLocation(classDecl) as InterfaceType;
|
||||
const implementedTypeNodes = getClassImplementsHeritageClauseElements(classDecl);
|
||||
|
||||
const hasNumericIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.Number);
|
||||
@@ -25,9 +25,9 @@ namespace ts.codefix {
|
||||
|
||||
const result: CodeAction[] = [];
|
||||
for (const implementedTypeNode of implementedTypeNodes) {
|
||||
const implementedType = checker.getTypeFromTypeNode(implementedTypeNode) as InterfaceType;
|
||||
// Note that this is ultimately derived from a map indexed by symbol names,
|
||||
// so duplicates cannot occur.
|
||||
const implementedType = checker.getTypeAtLocation(implementedTypeNode) as InterfaceType;
|
||||
const implementedTypeSymbols = checker.getPropertiesOfType(implementedType);
|
||||
const nonPrivateMembers = implementedTypeSymbols.filter(symbol => !(getModifierFlags(symbol.valueDeclaration) & ModifierFlags.Private));
|
||||
|
||||
|
||||
@@ -26,22 +26,13 @@ namespace ts.codefix {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const newPosition = getOpenBraceEnd(<ConstructorDeclaration>constructor, sourceFile);
|
||||
const changes = [{
|
||||
fileName: sourceFile.fileName, textChanges: [{
|
||||
newText: superCall.getText(sourceFile),
|
||||
span: { start: newPosition, length: 0 }
|
||||
},
|
||||
{
|
||||
newText: "",
|
||||
span: { start: superCall.getStart(sourceFile), length: superCall.getWidth(sourceFile) }
|
||||
}]
|
||||
}];
|
||||
const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
|
||||
changeTracker.insertNodeAfter(sourceFile, getOpenBrace(<ConstructorDeclaration>constructor, sourceFile), superCall, { suffix: context.newLineCharacter });
|
||||
changeTracker.deleteNode(sourceFile, superCall);
|
||||
|
||||
return [{
|
||||
description: getLocaleSpecificMessage(Diagnostics.Make_super_call_the_first_statement_in_the_constructor),
|
||||
changes
|
||||
changes: changeTracker.getChanges()
|
||||
}];
|
||||
|
||||
function findSuperCall(n: Node): ExpressionStatement {
|
||||
|
||||
@@ -10,10 +10,13 @@ namespace ts.codefix {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const newPosition = getOpenBraceEnd(<ConstructorDeclaration>token.parent, sourceFile);
|
||||
const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
|
||||
const superCall = createStatement(createCall(createSuper(), /*typeArguments*/ undefined, /*argumentsArray*/ emptyArray));
|
||||
changeTracker.insertNodeAfter(sourceFile, getOpenBrace(<ConstructorDeclaration>token.parent, sourceFile), superCall, { suffix: context.newLineCharacter });
|
||||
|
||||
return [{
|
||||
description: getLocaleSpecificMessage(Diagnostics.Add_missing_super_call),
|
||||
changes: [{ fileName: sourceFile.fileName, textChanges: [{ newText: "super();", span: { start: newPosition, length: 0 } }] }]
|
||||
changes: changeTracker.getChanges()
|
||||
}];
|
||||
}
|
||||
});
|
||||
|
||||
@@ -21,26 +21,20 @@ namespace ts.codefix {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let changeStart = extendsToken.getStart(sourceFile);
|
||||
let changeEnd = extendsToken.getEnd();
|
||||
const textChanges: TextChange[] = [{ newText: " implements", span: { start: changeStart, length: changeEnd - changeStart } }];
|
||||
const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
|
||||
changeTracker.replaceNode(sourceFile, extendsToken, createToken(SyntaxKind.ImplementsKeyword));
|
||||
|
||||
// We replace existing keywords with commas.
|
||||
for (let i = 1; i < heritageClauses.length; i++) {
|
||||
const keywordToken = heritageClauses[i].getFirstToken();
|
||||
if (keywordToken) {
|
||||
changeStart = keywordToken.getStart(sourceFile);
|
||||
changeEnd = keywordToken.getEnd();
|
||||
textChanges.push({ newText: ",", span: { start: changeStart, length: changeEnd - changeStart } });
|
||||
changeTracker.replaceNode(sourceFile, keywordToken, createToken(SyntaxKind.CommaToken));
|
||||
}
|
||||
}
|
||||
|
||||
const result = [{
|
||||
description: getLocaleSpecificMessage(Diagnostics.Change_extends_to_implements),
|
||||
changes: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textChanges: textChanges
|
||||
}]
|
||||
changes: changeTracker.getChanges()
|
||||
}];
|
||||
|
||||
return result;
|
||||
|
||||
@@ -5,11 +5,15 @@ namespace ts.codefix {
|
||||
getCodeActions: (context: CodeFixContext) => {
|
||||
const sourceFile = context.sourceFile;
|
||||
const token = getTokenAtPosition(sourceFile, context.span.start);
|
||||
const start = token.getStart(sourceFile);
|
||||
if (token.kind !== SyntaxKind.Identifier) {
|
||||
return undefined;
|
||||
}
|
||||
const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
|
||||
changeTracker.replaceNode(sourceFile, token, createPropertyAccess(createThis(), <Identifier>token));
|
||||
|
||||
return [{
|
||||
description: getLocaleSpecificMessage(Diagnostics.Add_this_to_unresolved_variable),
|
||||
changes: [{ fileName: sourceFile.fileName, textChanges: [{ newText: "this.", span: { start, length: 0 } }] }]
|
||||
changes: changeTracker.getChanges()
|
||||
}];
|
||||
}
|
||||
});
|
||||
|
||||
@@ -23,8 +23,6 @@ namespace ts.codefix {
|
||||
* @returns Empty string iff there we can't figure out a representation for `symbol` in `enclosingDeclaration`.
|
||||
*/
|
||||
function getInsertionForMemberSymbol(symbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker, newlineChar: string): string {
|
||||
// const name = symbol.getName();
|
||||
const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration);
|
||||
const declarations = symbol.getDeclarations();
|
||||
if (!(declarations && declarations.length)) {
|
||||
return "";
|
||||
@@ -34,6 +32,8 @@ namespace ts.codefix {
|
||||
const name = declaration.name ? declaration.name.getText() : undefined;
|
||||
const visibility = getVisibilityPrefixWithSpace(getModifierFlags(declaration));
|
||||
|
||||
const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration);
|
||||
|
||||
switch (declaration.kind) {
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* @internal */
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
|
||||
type ImportCodeActionKind = "CodeChange" | "InsertingIntoExistingImport" | "NewImport";
|
||||
interface ImportCodeAction extends CodeAction {
|
||||
kind: ImportCodeActionKind,
|
||||
moduleSpecifier?: string
|
||||
kind: ImportCodeActionKind;
|
||||
moduleSpecifier?: string;
|
||||
}
|
||||
|
||||
enum ModuleSpecifierComparison {
|
||||
@@ -75,7 +75,7 @@ namespace ts.codefix {
|
||||
getAllActions() {
|
||||
let result: ImportCodeAction[] = [];
|
||||
for (const key in this.symbolIdToActionMap) {
|
||||
result = concatenate(result, this.symbolIdToActionMap[key])
|
||||
result = concatenate(result, this.symbolIdToActionMap[key]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -130,7 +130,7 @@ namespace ts.codefix {
|
||||
|
||||
// this is a module id -> module import declaration map
|
||||
const cachedImportDeclarations: (ImportDeclaration | ImportEqualsDeclaration)[][] = [];
|
||||
let cachedNewImportInsertPosition: number;
|
||||
let lastImportDeclaration: Node;
|
||||
|
||||
const currentTokenMeaning = getMeaningFromLocation(token);
|
||||
if (context.errorCode === Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead.code) {
|
||||
@@ -138,14 +138,14 @@ namespace ts.codefix {
|
||||
return getCodeActionForImport(symbol, /*isDefault*/ false, /*isNamespaceImport*/ true);
|
||||
}
|
||||
|
||||
const allPotentialModules = checker.getAmbientModules();
|
||||
const candidateModules = checker.getAmbientModules();
|
||||
for (const otherSourceFile of allSourceFiles) {
|
||||
if (otherSourceFile !== sourceFile && isExternalOrCommonJsModule(otherSourceFile)) {
|
||||
allPotentialModules.push(otherSourceFile.symbol);
|
||||
candidateModules.push(otherSourceFile.symbol);
|
||||
}
|
||||
}
|
||||
|
||||
for (const moduleSymbol of allPotentialModules) {
|
||||
for (const moduleSymbol of candidateModules) {
|
||||
context.cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
// check the default export
|
||||
@@ -277,14 +277,12 @@ namespace ts.codefix {
|
||||
* If the existing import declaration already has a named import list, just
|
||||
* insert the identifier into that list.
|
||||
*/
|
||||
const textChange = getTextChangeForImportClause(namedImportDeclaration.importClause);
|
||||
const fileTextChanges = getTextChangeForImportClause(namedImportDeclaration.importClause);
|
||||
const moduleSpecifierWithoutQuotes = stripQuotes(namedImportDeclaration.moduleSpecifier.getText());
|
||||
actions.push(createCodeAction(
|
||||
Diagnostics.Add_0_to_existing_import_declaration_from_1,
|
||||
[name, moduleSpecifierWithoutQuotes],
|
||||
textChange.newText,
|
||||
textChange.span,
|
||||
sourceFile.fileName,
|
||||
fileTextChanges,
|
||||
"InsertingIntoExistingImport",
|
||||
moduleSpecifierWithoutQuotes
|
||||
));
|
||||
@@ -302,49 +300,30 @@ namespace ts.codefix {
|
||||
return declaration.moduleReference.getText();
|
||||
}
|
||||
|
||||
function getTextChangeForImportClause(importClause: ImportClause): TextChange {
|
||||
const newImportText = isDefault ? `default as ${name}` : name;
|
||||
function getTextChangeForImportClause(importClause: ImportClause): FileTextChanges[] {
|
||||
const importList = <NamedImports>importClause.namedBindings;
|
||||
const newImportSpecifier = createImportSpecifier(/*propertyName*/ undefined, createIdentifier(name));
|
||||
// case 1:
|
||||
// original text: import default from "module"
|
||||
// change to: import default, { name } from "module"
|
||||
if (!importList && importClause.name) {
|
||||
const start = importClause.name.getEnd();
|
||||
return {
|
||||
newText: `, { ${newImportText} }`,
|
||||
span: { start, length: 0 }
|
||||
};
|
||||
}
|
||||
|
||||
// case 2:
|
||||
// original text: import {} from "module"
|
||||
// change to: import { name } from "module"
|
||||
if (importList.elements.length === 0) {
|
||||
const start = importList.getStart();
|
||||
return {
|
||||
newText: `{ ${newImportText} }`,
|
||||
span: { start, length: importList.getEnd() - start }
|
||||
};
|
||||
if (!importList || importList.elements.length === 0) {
|
||||
const newImportClause = createImportClause(importClause.name, createNamedImports([newImportSpecifier]));
|
||||
return createChangeTracker().replaceNode(sourceFile, importClause, newImportClause).getChanges();
|
||||
}
|
||||
|
||||
// case 3:
|
||||
// original text: import { foo, bar } from "module"
|
||||
// change to: import { foo, bar, name } from "module"
|
||||
const insertPoint = importList.elements[importList.elements.length - 1].getEnd();
|
||||
/**
|
||||
* If the import list has one import per line, preserve that. Otherwise, insert on same line as last element
|
||||
* import {
|
||||
* foo
|
||||
* } from "./module";
|
||||
*/
|
||||
const startLine = getLineOfLocalPosition(sourceFile, importList.getStart());
|
||||
const endLine = getLineOfLocalPosition(sourceFile, importList.getEnd());
|
||||
const oneImportPerLine = endLine - startLine > importList.elements.length;
|
||||
|
||||
return {
|
||||
newText: `,${oneImportPerLine ? context.newLineCharacter : " "}${newImportText}`,
|
||||
span: { start: insertPoint, length: 0 }
|
||||
};
|
||||
return createChangeTracker().insertNodeInListAfter(
|
||||
sourceFile,
|
||||
importList.elements[importList.elements.length - 1],
|
||||
newImportSpecifier).getChanges();
|
||||
}
|
||||
|
||||
function getCodeActionForNamespaceImport(declaration: ImportDeclaration | ImportEqualsDeclaration): ImportCodeAction {
|
||||
@@ -370,48 +349,47 @@ namespace ts.codefix {
|
||||
return createCodeAction(
|
||||
Diagnostics.Change_0_to_1,
|
||||
[name, `${namespacePrefix}.${name}`],
|
||||
`${namespacePrefix}.`,
|
||||
{ start: token.getStart(), length: 0 },
|
||||
sourceFile.fileName,
|
||||
createChangeTracker().replaceNode(sourceFile, token, createPropertyAccess(createIdentifier(namespacePrefix), name)).getChanges(),
|
||||
"CodeChange"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function getCodeActionForNewImport(moduleSpecifier?: string): ImportCodeAction {
|
||||
if (!cachedNewImportInsertPosition) {
|
||||
if (!lastImportDeclaration) {
|
||||
// insert after any existing imports
|
||||
let lastModuleSpecifierEnd = -1;
|
||||
for (const moduleSpecifier of sourceFile.imports) {
|
||||
const end = moduleSpecifier.getEnd();
|
||||
if (!lastModuleSpecifierEnd || end > lastModuleSpecifierEnd) {
|
||||
lastModuleSpecifierEnd = end;
|
||||
for (let i = sourceFile.statements.length - 1; i >= 0; i--) {
|
||||
const statement = sourceFile.statements[i];
|
||||
if (statement.kind === SyntaxKind.ImportEqualsDeclaration || statement.kind === SyntaxKind.ImportDeclaration) {
|
||||
lastImportDeclaration = statement;
|
||||
break;
|
||||
}
|
||||
}
|
||||
cachedNewImportInsertPosition = lastModuleSpecifierEnd > 0 ? sourceFile.getLineEndOfPosition(lastModuleSpecifierEnd) : sourceFile.getStart();
|
||||
}
|
||||
|
||||
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
const moduleSpecifierWithoutQuotes = stripQuotes(moduleSpecifier || getModuleSpecifierForNewImport());
|
||||
const importStatementText = isDefault
|
||||
? `import ${name} from "${moduleSpecifierWithoutQuotes}"`
|
||||
const changeTracker = createChangeTracker();
|
||||
const importClause = isDefault
|
||||
? createImportClause(createIdentifier(name), /*namedBindings*/ undefined)
|
||||
: isNamespaceImport
|
||||
? `import * as ${name} from "${moduleSpecifierWithoutQuotes}"`
|
||||
: `import { ${name} } from "${moduleSpecifierWithoutQuotes}"`;
|
||||
? createImportClause(/*name*/ undefined, createNamespaceImport(createIdentifier(name)))
|
||||
: createImportClause(/*name*/ undefined, createNamedImports([createImportSpecifier(/*propertyName*/ undefined, createIdentifier(name))]));
|
||||
const importDecl = createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, importClause, createLiteral(moduleSpecifierWithoutQuotes));
|
||||
if (!lastImportDeclaration) {
|
||||
changeTracker.insertNodeAt(sourceFile, sourceFile.getStart(), importDecl, { suffix: `${context.newLineCharacter}${context.newLineCharacter}` });
|
||||
}
|
||||
else {
|
||||
changeTracker.insertNodeAfter(sourceFile, lastImportDeclaration, importDecl, { suffix: context.newLineCharacter });
|
||||
}
|
||||
|
||||
// if this file doesn't have any import statements, insert an import statement and then insert a new line
|
||||
// between the only import statement and user code. Otherwise just insert the statement because chances
|
||||
// are there are already a new line seperating code and import statements.
|
||||
const newText = cachedNewImportInsertPosition === sourceFile.getStart()
|
||||
? `${importStatementText};${context.newLineCharacter}${context.newLineCharacter}`
|
||||
: `${context.newLineCharacter}${importStatementText};`;
|
||||
|
||||
return createCodeAction(
|
||||
Diagnostics.Import_0_from_1,
|
||||
[name, `"${moduleSpecifierWithoutQuotes}"`],
|
||||
newText,
|
||||
{ start: cachedNewImportInsertPosition, length: 0 },
|
||||
sourceFile.fileName,
|
||||
changeTracker.getChanges(),
|
||||
"NewImport",
|
||||
moduleSpecifierWithoutQuotes
|
||||
);
|
||||
@@ -576,17 +554,19 @@ namespace ts.codefix {
|
||||
|
||||
}
|
||||
|
||||
function createChangeTracker() {
|
||||
return textChanges.ChangeTracker.fromCodeFixContext(context);
|
||||
}
|
||||
|
||||
function createCodeAction(
|
||||
description: DiagnosticMessage,
|
||||
diagnosticArgs: string[],
|
||||
newText: string,
|
||||
span: TextSpan,
|
||||
fileName: string,
|
||||
changes: FileTextChanges[],
|
||||
kind: ImportCodeActionKind,
|
||||
moduleSpecifier?: string): ImportCodeAction {
|
||||
return {
|
||||
description: formatMessage.apply(undefined, [undefined, description].concat(<any[]>diagnosticArgs)),
|
||||
changes: [{ fileName, textChanges: [{ newText, span }] }],
|
||||
changes,
|
||||
kind,
|
||||
moduleSpecifier
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* @internal */
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
registerCodeFix({
|
||||
errorCodes: [
|
||||
@@ -25,17 +25,17 @@ namespace ts.codefix {
|
||||
const forStatement = <ForStatement>token.parent.parent.parent;
|
||||
const forInitializer = <VariableDeclarationList>forStatement.initializer;
|
||||
if (forInitializer.declarations.length === 1) {
|
||||
return createCodeFixToRemoveNode(forInitializer);
|
||||
return deleteNode(forInitializer);
|
||||
}
|
||||
else {
|
||||
return removeSingleItem(forInitializer.declarations, token);
|
||||
return deleteNodeInList(token.parent);
|
||||
}
|
||||
|
||||
case SyntaxKind.ForOfStatement:
|
||||
const forOfStatement = <ForOfStatement>token.parent.parent.parent;
|
||||
if (forOfStatement.initializer.kind === SyntaxKind.VariableDeclarationList) {
|
||||
const forOfInitializer = <VariableDeclarationList>forOfStatement.initializer;
|
||||
return createCodeFix("{}", forOfInitializer.declarations[0].getStart(), forOfInitializer.declarations[0].getWidth());
|
||||
return replaceNode(forOfInitializer.declarations[0], createObjectLiteral());
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -47,51 +47,59 @@ namespace ts.codefix {
|
||||
case SyntaxKind.CatchClause:
|
||||
const catchClause = <CatchClause>token.parent.parent;
|
||||
const parameter = catchClause.variableDeclaration.getChildren()[0];
|
||||
return createCodeFixToRemoveNode(parameter);
|
||||
return deleteNode(parameter);
|
||||
|
||||
default:
|
||||
const variableStatement = <VariableStatement>token.parent.parent.parent;
|
||||
if (variableStatement.declarationList.declarations.length === 1) {
|
||||
return createCodeFixToRemoveNode(variableStatement);
|
||||
return deleteNode(variableStatement);
|
||||
}
|
||||
else {
|
||||
const declarations = variableStatement.declarationList.declarations;
|
||||
return removeSingleItem(declarations, token);
|
||||
return deleteNodeInList(token.parent);
|
||||
}
|
||||
}
|
||||
|
||||
case SyntaxKind.TypeParameter:
|
||||
const typeParameters = (<DeclarationWithTypeParameters>token.parent.parent).typeParameters;
|
||||
if (typeParameters.length === 1) {
|
||||
return createCodeFix("", token.parent.pos - 1, token.parent.end - token.parent.pos + 2);
|
||||
const previousToken = getTokenAtPosition(sourceFile, typeParameters.pos - 1);
|
||||
if (!previousToken || previousToken.kind !== SyntaxKind.LessThanToken) {
|
||||
return deleteRange(typeParameters);
|
||||
}
|
||||
const nextToken = getTokenAtPosition(sourceFile, typeParameters.end);
|
||||
if (!nextToken || nextToken.kind !== SyntaxKind.GreaterThanToken) {
|
||||
return deleteRange(typeParameters);
|
||||
}
|
||||
return deleteNodeRange(previousToken, nextToken);
|
||||
}
|
||||
else {
|
||||
return removeSingleItem(typeParameters, token);
|
||||
return deleteNodeInList(token.parent);
|
||||
}
|
||||
|
||||
case ts.SyntaxKind.Parameter:
|
||||
const functionDeclaration = <FunctionDeclaration>token.parent.parent;
|
||||
if (functionDeclaration.parameters.length === 1) {
|
||||
return createCodeFixToRemoveNode(token.parent);
|
||||
return deleteNode(token.parent);
|
||||
}
|
||||
else {
|
||||
return removeSingleItem(functionDeclaration.parameters, token);
|
||||
return deleteNodeInList(token.parent);
|
||||
}
|
||||
|
||||
// handle case where 'import a = A;'
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
const importEquals = findImportDeclaration(token);
|
||||
return createCodeFixToRemoveNode(importEquals);
|
||||
const importEquals = getAncestor(token, SyntaxKind.ImportEqualsDeclaration);
|
||||
return deleteNode(importEquals);
|
||||
|
||||
case SyntaxKind.ImportSpecifier:
|
||||
const namedImports = <NamedImports>token.parent.parent;
|
||||
if (namedImports.elements.length === 1) {
|
||||
// Only 1 import and it is unused. So the entire declaration should be removed.
|
||||
const importSpec = findImportDeclaration(token);
|
||||
return createCodeFixToRemoveNode(importSpec);
|
||||
const importSpec = getAncestor(token, SyntaxKind.ImportDeclaration);
|
||||
return deleteNode(importSpec);
|
||||
}
|
||||
else {
|
||||
return removeSingleItem(namedImports.elements, token);
|
||||
// delete import specifier
|
||||
return deleteNodeInList(token.parent);
|
||||
}
|
||||
|
||||
// handle case where "import d, * as ns from './file'"
|
||||
@@ -99,98 +107,79 @@ namespace ts.codefix {
|
||||
case SyntaxKind.ImportClause: // this covers both 'import |d|' and 'import |d,| *'
|
||||
const importClause = <ImportClause>token.parent;
|
||||
if (!importClause.namedBindings) { // |import d from './file'| or |import * as ns from './file'|
|
||||
const importDecl = findImportDeclaration(importClause);
|
||||
return createCodeFixToRemoveNode(importDecl);
|
||||
const importDecl = getAncestor(importClause, SyntaxKind.ImportDeclaration);
|
||||
return deleteNode(importDecl);
|
||||
}
|
||||
else {
|
||||
// import |d,| * as ns from './file'
|
||||
const start = importClause.name.getStart();
|
||||
let end = findFirstNonSpaceCharPosStarting(importClause.name.end);
|
||||
if (sourceFile.text.charCodeAt(end) === CharacterCodes.comma) {
|
||||
end = findFirstNonSpaceCharPosStarting(end + 1);
|
||||
const start = importClause.name.getStart(sourceFile);
|
||||
const nextToken = getTokenAtPosition(sourceFile, importClause.name.end);
|
||||
if (nextToken && nextToken.kind === SyntaxKind.CommaToken) {
|
||||
// shift first non-whitespace position after comma to the start position of the node
|
||||
return deleteRange({ pos: start, end: skipTrivia(sourceFile.text, nextToken.end, /*stopAfterLineBreaks*/ false, /*stopAtComments*/true) });
|
||||
}
|
||||
else {
|
||||
return deleteNode(importClause.name);
|
||||
}
|
||||
|
||||
return createCodeFix("", start, end - start);
|
||||
}
|
||||
|
||||
case SyntaxKind.NamespaceImport:
|
||||
const namespaceImport = <NamespaceImport>token.parent;
|
||||
if (namespaceImport.name == token && !(<ImportClause>namespaceImport.parent).name) {
|
||||
const importDecl = findImportDeclaration(namespaceImport);
|
||||
return createCodeFixToRemoveNode(importDecl);
|
||||
const importDecl = getAncestor(namespaceImport, SyntaxKind.ImportDeclaration);
|
||||
return deleteNode(importDecl);
|
||||
}
|
||||
else {
|
||||
const start = (<ImportClause>namespaceImport.parent).name.end;
|
||||
return createCodeFix("", start, (<ImportClause>namespaceImport.parent).namedBindings.end - start);
|
||||
const previousToken = getTokenAtPosition(sourceFile, namespaceImport.pos - 1);
|
||||
if (previousToken && previousToken.kind === SyntaxKind.CommaToken) {
|
||||
const startPosition = textChanges.getAdjustedStartPosition(sourceFile, previousToken, {}, textChanges.Position.FullStart);
|
||||
return deleteRange({ pos: startPosition, end: namespaceImport.end });
|
||||
}
|
||||
return deleteRange(namespaceImport);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.NamespaceImport:
|
||||
return createCodeFixToRemoveNode(token.parent);
|
||||
return deleteNode(token.parent);
|
||||
}
|
||||
if (isDeclarationName(token)) {
|
||||
return createCodeFixToRemoveNode(token.parent);
|
||||
return deleteNode(token.parent);
|
||||
}
|
||||
else if (isLiteralComputedPropertyDeclarationName(token)) {
|
||||
return createCodeFixToRemoveNode(token.parent.parent);
|
||||
return deleteNode(token.parent.parent);
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function findImportDeclaration(token: Node): Node {
|
||||
let importDecl = token;
|
||||
while (importDecl.kind != SyntaxKind.ImportDeclaration && importDecl.parent) {
|
||||
importDecl = importDecl.parent;
|
||||
}
|
||||
|
||||
return importDecl;
|
||||
function deleteNode(n: Node) {
|
||||
return makeChange(textChanges.ChangeTracker.fromCodeFixContext(context).deleteNode(sourceFile, n));
|
||||
}
|
||||
|
||||
function createCodeFixToRemoveNode(node: Node) {
|
||||
let end = node.getEnd();
|
||||
const endCharCode = sourceFile.text.charCodeAt(end);
|
||||
const afterEndCharCode = sourceFile.text.charCodeAt(end + 1);
|
||||
if (isLineBreak(endCharCode)) {
|
||||
end += 1;
|
||||
}
|
||||
// in the case of CR LF, you could have two consecutive new line characters for one new line.
|
||||
// this needs to be differenciated from two LF LF chars that actually mean two new lines.
|
||||
if (isLineBreak(afterEndCharCode) && endCharCode !== afterEndCharCode) {
|
||||
end += 1;
|
||||
}
|
||||
|
||||
const start = node.getStart();
|
||||
return createCodeFix("", start, end - start);
|
||||
function deleteRange(range: TextRange) {
|
||||
return makeChange(textChanges.ChangeTracker.fromCodeFixContext(context).deleteRange(sourceFile, range));
|
||||
}
|
||||
|
||||
function findFirstNonSpaceCharPosStarting(start: number) {
|
||||
while (isWhiteSpace(sourceFile.text.charCodeAt(start))) {
|
||||
start += 1;
|
||||
}
|
||||
return start;
|
||||
function deleteNodeInList(n: Node) {
|
||||
return makeChange(textChanges.ChangeTracker.fromCodeFixContext(context).deleteNodeInList(sourceFile, n));
|
||||
}
|
||||
|
||||
function createCodeFix(newText: string, start: number, length: number): CodeAction[] {
|
||||
function deleteNodeRange(start: Node, end: Node) {
|
||||
return makeChange(textChanges.ChangeTracker.fromCodeFixContext(context).deleteNodeRange(sourceFile, start, end));
|
||||
}
|
||||
|
||||
function replaceNode(n: Node, newNode: Node) {
|
||||
return makeChange(textChanges.ChangeTracker.fromCodeFixContext(context).replaceNode(sourceFile, n, newNode));
|
||||
}
|
||||
|
||||
function makeChange(changeTracker: textChanges.ChangeTracker) {
|
||||
return [{
|
||||
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Remove_declaration_for_Colon_0), { 0: token.getText() }),
|
||||
changes: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textChanges: [{ newText, span: { start, length } }]
|
||||
}]
|
||||
changes: changeTracker.getChanges()
|
||||
}];
|
||||
}
|
||||
|
||||
function removeSingleItem<T extends Node>(elements: NodeArray<T>, token: T): CodeAction[] {
|
||||
if (elements[0] === token.parent) {
|
||||
return createCodeFix("", token.parent.pos, token.parent.end - token.parent.pos + 1);
|
||||
}
|
||||
else {
|
||||
return createCodeFix("", token.parent.pos - 1, token.parent.end - token.parent.pos + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
+71
-568
@@ -1,10 +1,12 @@
|
||||
/// <reference path="./pathCompletions.ts" />
|
||||
|
||||
/* @internal */
|
||||
namespace ts.Completions {
|
||||
export type Log = (message: string) => void;
|
||||
|
||||
export function getCompletionsAtPosition(host: LanguageServiceHost, typeChecker: TypeChecker, log: Log, compilerOptions: CompilerOptions, sourceFile: SourceFile, position: number): CompletionInfo | undefined {
|
||||
if (isInReferenceComment(sourceFile, position)) {
|
||||
return getTripleSlashReferenceCompletion(sourceFile, position, compilerOptions, host);
|
||||
return PathCompletions.getTripleSlashReferenceCompletion(sourceFile, position, compilerOptions, host);
|
||||
}
|
||||
|
||||
if (isInString(sourceFile, position)) {
|
||||
@@ -16,11 +18,16 @@ namespace ts.Completions {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isJsDocTagName } = completionData;
|
||||
const { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, requestJsDocTagName, requestJsDocTag } = completionData;
|
||||
|
||||
if (isJsDocTagName) {
|
||||
if (requestJsDocTagName) {
|
||||
// If the current position is a jsDoc tag name, only tag names should be provided for completion
|
||||
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getAllJsDocCompletionEntries() };
|
||||
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getJSDocTagNameCompletions() };
|
||||
}
|
||||
|
||||
if (requestJsDocTag) {
|
||||
// If the current position is a jsDoc tag, only tags should be provided for completion
|
||||
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getJSDocTagCompletions() };
|
||||
}
|
||||
|
||||
const entries: CompletionEntry[] = [];
|
||||
@@ -54,7 +61,7 @@ namespace ts.Completions {
|
||||
}
|
||||
|
||||
// Add keywords if this is not a member completion list
|
||||
if (!isMemberCompletion && !isJsDocTagName) {
|
||||
if (!isMemberCompletion && !requestJsDocTag && !requestJsDocTagName) {
|
||||
addRange(entries, keywordCompletions);
|
||||
}
|
||||
|
||||
@@ -171,7 +178,7 @@ namespace ts.Completions {
|
||||
// i.e. import * as ns from "/*completion position*/";
|
||||
// import x = require("/*completion position*/");
|
||||
// var y = require("/*completion position*/");
|
||||
return getStringLiteralCompletionEntriesFromModuleNames(<StringLiteral>node, compilerOptions, host, typeChecker);
|
||||
return PathCompletions.getStringLiteralCompletionEntriesFromModuleNames(<StringLiteral>node, compilerOptions, host, typeChecker);
|
||||
}
|
||||
else if (isEqualityExpression(node.parent)) {
|
||||
// Get completions from the type of the other operand
|
||||
@@ -273,489 +280,6 @@ namespace ts.Completions {
|
||||
}
|
||||
}
|
||||
|
||||
function getStringLiteralCompletionEntriesFromModuleNames(node: StringLiteral, compilerOptions: CompilerOptions, host: LanguageServiceHost, typeChecker: TypeChecker): CompletionInfo {
|
||||
const literalValue = normalizeSlashes(node.text);
|
||||
|
||||
const scriptPath = node.getSourceFile().path;
|
||||
const scriptDirectory = getDirectoryPath(scriptPath);
|
||||
|
||||
const span = getDirectoryFragmentTextSpan((<StringLiteral>node).text, node.getStart() + 1);
|
||||
let entries: CompletionEntry[];
|
||||
if (isPathRelativeToScript(literalValue) || isRootedDiskPath(literalValue)) {
|
||||
const extensions = getSupportedExtensions(compilerOptions);
|
||||
if (compilerOptions.rootDirs) {
|
||||
entries = getCompletionEntriesForDirectoryFragmentWithRootDirs(
|
||||
compilerOptions.rootDirs, literalValue, scriptDirectory, extensions, /*includeExtensions*/false, span, compilerOptions, host, scriptPath);
|
||||
}
|
||||
else {
|
||||
entries = getCompletionEntriesForDirectoryFragment(
|
||||
literalValue, scriptDirectory, extensions, /*includeExtensions*/false, span, host, scriptPath);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Check for node modules
|
||||
entries = getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, span, compilerOptions, host, typeChecker);
|
||||
}
|
||||
return {
|
||||
isGlobalCompletion: false,
|
||||
isMemberCompletion: false,
|
||||
isNewIdentifierLocation: true,
|
||||
entries
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a script path and returns paths for all potential folders that could be merged with its
|
||||
* containing folder via the "rootDirs" compiler option
|
||||
*/
|
||||
function getBaseDirectoriesFromRootDirs(rootDirs: string[], basePath: string, scriptPath: string, ignoreCase: boolean): string[] {
|
||||
// Make all paths absolute/normalized if they are not already
|
||||
rootDirs = map(rootDirs, rootDirectory => normalizePath(isRootedDiskPath(rootDirectory) ? rootDirectory : combinePaths(basePath, rootDirectory)));
|
||||
|
||||
// Determine the path to the directory containing the script relative to the root directory it is contained within
|
||||
let relativeDirectory: string;
|
||||
for (const rootDirectory of rootDirs) {
|
||||
if (containsPath(rootDirectory, scriptPath, basePath, ignoreCase)) {
|
||||
relativeDirectory = scriptPath.substr(rootDirectory.length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Now find a path for each potential directory that is to be merged with the one containing the script
|
||||
return deduplicate(map(rootDirs, rootDirectory => combinePaths(rootDirectory, relativeDirectory)));
|
||||
}
|
||||
|
||||
function getCompletionEntriesForDirectoryFragmentWithRootDirs(rootDirs: string[], fragment: string, scriptPath: string, extensions: string[], includeExtensions: boolean, span: TextSpan, compilerOptions: CompilerOptions, host: LanguageServiceHost, exclude?: string): CompletionEntry[] {
|
||||
const basePath = compilerOptions.project || host.getCurrentDirectory();
|
||||
const ignoreCase = !(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames());
|
||||
const baseDirectories = getBaseDirectoriesFromRootDirs(rootDirs, basePath, scriptPath, ignoreCase);
|
||||
|
||||
const result: CompletionEntry[] = [];
|
||||
|
||||
for (const baseDirectory of baseDirectories) {
|
||||
getCompletionEntriesForDirectoryFragment(fragment, baseDirectory, extensions, includeExtensions, span, host, exclude, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a path ending at a directory, gets the completions for the path, and filters for those entries containing the basename.
|
||||
*/
|
||||
function getCompletionEntriesForDirectoryFragment(fragment: string, scriptPath: string, extensions: string[], includeExtensions: boolean, span: TextSpan, host: LanguageServiceHost, exclude?: string, result: CompletionEntry[] = []): CompletionEntry[] {
|
||||
if (fragment === undefined) {
|
||||
fragment = "";
|
||||
}
|
||||
|
||||
fragment = normalizeSlashes(fragment);
|
||||
|
||||
/**
|
||||
* Remove the basename from the path. Note that we don't use the basename to filter completions;
|
||||
* the client is responsible for refining completions.
|
||||
*/
|
||||
fragment = getDirectoryPath(fragment);
|
||||
|
||||
if (fragment === "") {
|
||||
fragment = "." + directorySeparator;
|
||||
}
|
||||
|
||||
fragment = ensureTrailingDirectorySeparator(fragment);
|
||||
|
||||
const absolutePath = normalizeAndPreserveTrailingSlash(isRootedDiskPath(fragment) ? fragment : combinePaths(scriptPath, fragment));
|
||||
const baseDirectory = getDirectoryPath(absolutePath);
|
||||
const ignoreCase = !(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames());
|
||||
|
||||
if (tryDirectoryExists(host, baseDirectory)) {
|
||||
// Enumerate the available files if possible
|
||||
const files = tryReadDirectory(host, baseDirectory, extensions, /*exclude*/undefined, /*include*/["./*"]);
|
||||
|
||||
if (files) {
|
||||
/**
|
||||
* Multiple file entries might map to the same truncated name once we remove extensions
|
||||
* (happens iff includeExtensions === false)so we use a set-like data structure. Eg:
|
||||
*
|
||||
* both foo.ts and foo.tsx become foo
|
||||
*/
|
||||
const foundFiles = createMap<boolean>();
|
||||
for (let filePath of files) {
|
||||
filePath = normalizePath(filePath);
|
||||
if (exclude && comparePaths(filePath, exclude, scriptPath, ignoreCase) === Comparison.EqualTo) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const foundFileName = includeExtensions ? getBaseFileName(filePath) : removeFileExtension(getBaseFileName(filePath));
|
||||
|
||||
if (!foundFiles.get(foundFileName)) {
|
||||
foundFiles.set(foundFileName, true);
|
||||
}
|
||||
}
|
||||
|
||||
forEachKey(foundFiles, foundFile => {
|
||||
result.push(createCompletionEntryForModule(foundFile, ScriptElementKind.scriptElement, span));
|
||||
});
|
||||
}
|
||||
|
||||
// If possible, get folder completion as well
|
||||
const directories = tryGetDirectories(host, baseDirectory);
|
||||
|
||||
if (directories) {
|
||||
for (const directory of directories) {
|
||||
const directoryName = getBaseFileName(normalizePath(directory));
|
||||
|
||||
result.push(createCompletionEntryForModule(directoryName, ScriptElementKind.directory, span));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check all of the declared modules and those in node modules. Possible sources of modules:
|
||||
* Modules that are found by the type checker
|
||||
* Modules found relative to "baseUrl" compliler options (including patterns from "paths" compiler option)
|
||||
* Modules from node_modules (i.e. those listed in package.json)
|
||||
* This includes all files that are found in node_modules/moduleName/ with acceptable file extensions
|
||||
*/
|
||||
function getCompletionEntriesForNonRelativeModules(fragment: string, scriptPath: string, span: TextSpan, compilerOptions: CompilerOptions, host: LanguageServiceHost, typeChecker: TypeChecker): CompletionEntry[] {
|
||||
const { baseUrl, paths } = compilerOptions;
|
||||
|
||||
let result: CompletionEntry[];
|
||||
|
||||
if (baseUrl) {
|
||||
const fileExtensions = getSupportedExtensions(compilerOptions);
|
||||
const projectDir = compilerOptions.project || host.getCurrentDirectory();
|
||||
const absolute = isRootedDiskPath(baseUrl) ? baseUrl : combinePaths(projectDir, baseUrl);
|
||||
result = getCompletionEntriesForDirectoryFragment(fragment, normalizePath(absolute), fileExtensions, /*includeExtensions*/false, span, host);
|
||||
|
||||
if (paths) {
|
||||
for (const path in paths) {
|
||||
if (paths.hasOwnProperty(path)) {
|
||||
if (path === "*") {
|
||||
if (paths[path]) {
|
||||
for (const pattern of paths[path]) {
|
||||
for (const match of getModulesForPathsPattern(fragment, baseUrl, pattern, fileExtensions, host)) {
|
||||
result.push(createCompletionEntryForModule(match, ScriptElementKind.externalModuleName, span));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (startsWith(path, fragment)) {
|
||||
const entry = paths[path] && paths[path].length === 1 && paths[path][0];
|
||||
if (entry) {
|
||||
result.push(createCompletionEntryForModule(path, ScriptElementKind.externalModuleName, span));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = [];
|
||||
}
|
||||
|
||||
getCompletionEntriesFromTypings(host, compilerOptions, scriptPath, span, result);
|
||||
|
||||
for (const moduleName of enumeratePotentialNonRelativeModules(fragment, scriptPath, compilerOptions, typeChecker, host)) {
|
||||
result.push(createCompletionEntryForModule(moduleName, ScriptElementKind.externalModuleName, span));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function getModulesForPathsPattern(fragment: string, baseUrl: string, pattern: string, fileExtensions: string[], host: LanguageServiceHost): string[] {
|
||||
if (host.readDirectory) {
|
||||
const parsed = hasZeroOrOneAsteriskCharacter(pattern) ? tryParsePattern(pattern) : undefined;
|
||||
if (parsed) {
|
||||
// The prefix has two effective parts: the directory path and the base component after the filepath that is not a
|
||||
// full directory component. For example: directory/path/of/prefix/base*
|
||||
const normalizedPrefix = normalizeAndPreserveTrailingSlash(parsed.prefix);
|
||||
const normalizedPrefixDirectory = getDirectoryPath(normalizedPrefix);
|
||||
const normalizedPrefixBase = getBaseFileName(normalizedPrefix);
|
||||
|
||||
const fragmentHasPath = fragment.indexOf(directorySeparator) !== -1;
|
||||
|
||||
// Try and expand the prefix to include any path from the fragment so that we can limit the readDirectory call
|
||||
const expandedPrefixDirectory = fragmentHasPath ? combinePaths(normalizedPrefixDirectory, normalizedPrefixBase + getDirectoryPath(fragment)) : normalizedPrefixDirectory;
|
||||
|
||||
const normalizedSuffix = normalizePath(parsed.suffix);
|
||||
const baseDirectory = combinePaths(baseUrl, expandedPrefixDirectory);
|
||||
const completePrefix = fragmentHasPath ? baseDirectory : ensureTrailingDirectorySeparator(baseDirectory) + normalizedPrefixBase;
|
||||
|
||||
// If we have a suffix, then we need to read the directory all the way down. We could create a glob
|
||||
// that encodes the suffix, but we would have to escape the character "?" which readDirectory
|
||||
// doesn't support. For now, this is safer but slower
|
||||
const includeGlob = normalizedSuffix ? "**/*" : "./*";
|
||||
|
||||
const matches = tryReadDirectory(host, baseDirectory, fileExtensions, undefined, [includeGlob]);
|
||||
if (matches) {
|
||||
const result: string[] = [];
|
||||
|
||||
// Trim away prefix and suffix
|
||||
for (const match of matches) {
|
||||
const normalizedMatch = normalizePath(match);
|
||||
if (!endsWith(normalizedMatch, normalizedSuffix) || !startsWith(normalizedMatch, completePrefix)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const start = completePrefix.length;
|
||||
const length = normalizedMatch.length - start - normalizedSuffix.length;
|
||||
|
||||
result.push(removeFileExtension(normalizedMatch.substr(start, length)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function enumeratePotentialNonRelativeModules(fragment: string, scriptPath: string, options: CompilerOptions, typeChecker: TypeChecker, host: LanguageServiceHost): string[] {
|
||||
// Check If this is a nested module
|
||||
const isNestedModule = fragment.indexOf(directorySeparator) !== -1;
|
||||
const moduleNameFragment = isNestedModule ? fragment.substr(0, fragment.lastIndexOf(directorySeparator)) : undefined;
|
||||
|
||||
// Get modules that the type checker picked up
|
||||
const ambientModules = map(typeChecker.getAmbientModules(), sym => stripQuotes(sym.name));
|
||||
let nonRelativeModules = filter(ambientModules, moduleName => startsWith(moduleName, fragment));
|
||||
|
||||
// Nested modules of the form "module-name/sub" need to be adjusted to only return the string
|
||||
// after the last '/' that appears in the fragment because that's where the replacement span
|
||||
// starts
|
||||
if (isNestedModule) {
|
||||
const moduleNameWithSeperator = ensureTrailingDirectorySeparator(moduleNameFragment);
|
||||
nonRelativeModules = map(nonRelativeModules, moduleName => {
|
||||
if (startsWith(fragment, moduleNameWithSeperator)) {
|
||||
return moduleName.substr(moduleNameWithSeperator.length);
|
||||
}
|
||||
return moduleName;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (!options.moduleResolution || options.moduleResolution === ModuleResolutionKind.NodeJs) {
|
||||
for (const visibleModule of enumerateNodeModulesVisibleToScript(host, scriptPath)) {
|
||||
if (!isNestedModule) {
|
||||
nonRelativeModules.push(visibleModule.moduleName);
|
||||
}
|
||||
else if (startsWith(visibleModule.moduleName, moduleNameFragment)) {
|
||||
const nestedFiles = tryReadDirectory(host, visibleModule.moduleDir, supportedTypeScriptExtensions, /*exclude*/undefined, /*include*/["./*"]);
|
||||
if (nestedFiles) {
|
||||
for (let f of nestedFiles) {
|
||||
f = normalizePath(f);
|
||||
const nestedModule = removeFileExtension(getBaseFileName(f));
|
||||
nonRelativeModules.push(nestedModule);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deduplicate(nonRelativeModules);
|
||||
}
|
||||
|
||||
function getTripleSlashReferenceCompletion(sourceFile: SourceFile, position: number, compilerOptions: CompilerOptions, host: LanguageServiceHost): CompletionInfo {
|
||||
const token = getTokenAtPosition(sourceFile, position);
|
||||
if (!token) {
|
||||
return undefined;
|
||||
}
|
||||
const commentRanges: CommentRange[] = getLeadingCommentRanges(sourceFile.text, token.pos);
|
||||
|
||||
if (!commentRanges || !commentRanges.length) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const range = forEach(commentRanges, commentRange => position >= commentRange.pos && position <= commentRange.end && commentRange);
|
||||
|
||||
if (!range) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const completionInfo: CompletionInfo = {
|
||||
/**
|
||||
* We don't want the editor to offer any other completions, such as snippets, inside a comment.
|
||||
*/
|
||||
isGlobalCompletion: false,
|
||||
isMemberCompletion: false,
|
||||
/**
|
||||
* The user may type in a path that doesn't yet exist, creating a "new identifier"
|
||||
* with respect to the collection of identifiers the server is aware of.
|
||||
*/
|
||||
isNewIdentifierLocation: true,
|
||||
|
||||
entries: []
|
||||
};
|
||||
|
||||
const text = sourceFile.text.substr(range.pos, position - range.pos);
|
||||
|
||||
const match = tripleSlashDirectiveFragmentRegex.exec(text);
|
||||
|
||||
if (match) {
|
||||
const prefix = match[1];
|
||||
const kind = match[2];
|
||||
const toComplete = match[3];
|
||||
|
||||
const scriptPath = getDirectoryPath(sourceFile.path);
|
||||
if (kind === "path") {
|
||||
// Give completions for a relative path
|
||||
const span: TextSpan = getDirectoryFragmentTextSpan(toComplete, range.pos + prefix.length);
|
||||
completionInfo.entries = getCompletionEntriesForDirectoryFragment(toComplete, scriptPath, getSupportedExtensions(compilerOptions), /*includeExtensions*/true, span, host, sourceFile.path);
|
||||
}
|
||||
else {
|
||||
// Give completions based on the typings available
|
||||
const span: TextSpan = { start: range.pos + prefix.length, length: match[0].length - prefix.length };
|
||||
completionInfo.entries = getCompletionEntriesFromTypings(host, compilerOptions, scriptPath, span);
|
||||
}
|
||||
}
|
||||
|
||||
return completionInfo;
|
||||
}
|
||||
|
||||
function getCompletionEntriesFromTypings(host: LanguageServiceHost, options: CompilerOptions, scriptPath: string, span: TextSpan, result: CompletionEntry[] = []): CompletionEntry[] {
|
||||
// Check for typings specified in compiler options
|
||||
if (options.types) {
|
||||
for (const moduleName of options.types) {
|
||||
result.push(createCompletionEntryForModule(moduleName, ScriptElementKind.externalModuleName, span));
|
||||
}
|
||||
}
|
||||
else if (host.getDirectories) {
|
||||
let typeRoots: string[];
|
||||
try {
|
||||
// Wrap in try catch because getEffectiveTypeRoots touches the filesystem
|
||||
typeRoots = getEffectiveTypeRoots(options, host);
|
||||
}
|
||||
catch (e) {}
|
||||
|
||||
if (typeRoots) {
|
||||
for (const root of typeRoots) {
|
||||
getCompletionEntriesFromDirectories(host, root, span, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (host.getDirectories) {
|
||||
// Also get all @types typings installed in visible node_modules directories
|
||||
for (const packageJson of findPackageJsons(scriptPath, host)) {
|
||||
const typesDir = combinePaths(getDirectoryPath(packageJson), "node_modules/@types");
|
||||
getCompletionEntriesFromDirectories(host, typesDir, span, result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function getCompletionEntriesFromDirectories(host: LanguageServiceHost, directory: string, span: TextSpan, result: Push<CompletionEntry>) {
|
||||
if (host.getDirectories && tryDirectoryExists(host, directory)) {
|
||||
const directories = tryGetDirectories(host, directory);
|
||||
if (directories) {
|
||||
for (let typeDirectory of directories) {
|
||||
typeDirectory = normalizePath(typeDirectory);
|
||||
result.push(createCompletionEntryForModule(getBaseFileName(typeDirectory), ScriptElementKind.externalModuleName, span));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findPackageJsons(currentDir: string, host: LanguageServiceHost): string[] {
|
||||
const paths: string[] = [];
|
||||
let currentConfigPath: string;
|
||||
while (true) {
|
||||
currentConfigPath = findConfigFile(currentDir, (f) => tryFileExists(host, f), "package.json");
|
||||
if (currentConfigPath) {
|
||||
paths.push(currentConfigPath);
|
||||
|
||||
currentDir = getDirectoryPath(currentConfigPath);
|
||||
const parent = getDirectoryPath(currentDir);
|
||||
if (currentDir === parent) {
|
||||
break;
|
||||
}
|
||||
currentDir = parent;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
function enumerateNodeModulesVisibleToScript(host: LanguageServiceHost, scriptPath: string) {
|
||||
const result: VisibleModuleInfo[] = [];
|
||||
|
||||
if (host.readFile && host.fileExists) {
|
||||
for (const packageJson of findPackageJsons(scriptPath, host)) {
|
||||
const contents = tryReadingPackageJson(packageJson);
|
||||
if (!contents) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nodeModulesDir = combinePaths(getDirectoryPath(packageJson), "node_modules");
|
||||
const foundModuleNames: string[] = [];
|
||||
|
||||
// Provide completions for all non @types dependencies
|
||||
for (const key of nodeModulesDependencyKeys) {
|
||||
addPotentialPackageNames(contents[key], foundModuleNames);
|
||||
}
|
||||
|
||||
for (const moduleName of foundModuleNames) {
|
||||
const moduleDir = combinePaths(nodeModulesDir, moduleName);
|
||||
result.push({
|
||||
moduleName,
|
||||
moduleDir
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
function tryReadingPackageJson(filePath: string) {
|
||||
try {
|
||||
const fileText = tryReadFile(host, filePath);
|
||||
return fileText ? JSON.parse(fileText) : undefined;
|
||||
}
|
||||
catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function addPotentialPackageNames(dependencies: any, result: string[]) {
|
||||
if (dependencies) {
|
||||
for (const dep in dependencies) {
|
||||
if (dependencies.hasOwnProperty(dep) && !startsWith(dep, "@types/")) {
|
||||
result.push(dep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createCompletionEntryForModule(name: string, kind: string, replacementSpan: TextSpan): CompletionEntry {
|
||||
return { name, kind, kindModifiers: ScriptElementKindModifier.none, sortText: name, replacementSpan };
|
||||
}
|
||||
|
||||
// Replace everything after the last directory seperator that appears
|
||||
function getDirectoryFragmentTextSpan(text: string, textStart: number): TextSpan {
|
||||
const index = text.lastIndexOf(directorySeparator);
|
||||
const offset = index !== -1 ? index + 1 : 0;
|
||||
return { start: textStart + offset, length: text.length - offset };
|
||||
}
|
||||
|
||||
// Returns true if the path is explicitly relative to the script (i.e. relative to . or ..)
|
||||
function isPathRelativeToScript(path: string) {
|
||||
if (path && path.length >= 2 && path.charCodeAt(0) === CharacterCodes.dot) {
|
||||
const slashIndex = path.length >= 3 && path.charCodeAt(1) === CharacterCodes.dot ? 2 : 1;
|
||||
const slashCharCode = path.charCodeAt(slashIndex);
|
||||
return slashCharCode === CharacterCodes.slash || slashCharCode === CharacterCodes.backslash;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function normalizeAndPreserveTrailingSlash(path: string) {
|
||||
return hasTrailingDirectorySeparator(path) ? ensureTrailingDirectorySeparator(normalizePath(path)) : normalizePath(path);
|
||||
}
|
||||
|
||||
export function getCompletionEntryDetails(typeChecker: TypeChecker, log: (message: string) => void, compilerOptions: CompilerOptions, sourceFile: SourceFile, position: number, entryName: string): CompletionEntryDetails {
|
||||
// Compute all the completion symbols again.
|
||||
const completionData = getCompletionData(typeChecker, log, sourceFile, position);
|
||||
@@ -814,7 +338,10 @@ namespace ts.Completions {
|
||||
function getCompletionData(typeChecker: TypeChecker, log: (message: string) => void, sourceFile: SourceFile, position: number) {
|
||||
const isJavaScriptFile = isSourceFileJavaScript(sourceFile);
|
||||
|
||||
let isJsDocTagName = false;
|
||||
// JsDoc tag-name is just the name of the JSDoc tagname (exclude "@")
|
||||
let requestJsDocTagName = false;
|
||||
// JsDoc tag includes both "@" and tag-name
|
||||
let requestJsDocTag = false;
|
||||
|
||||
let start = timestamp();
|
||||
const currentToken = getTokenAtPosition(sourceFile, position);
|
||||
@@ -826,10 +353,32 @@ namespace ts.Completions {
|
||||
log("getCompletionData: Is inside comment: " + (timestamp() - start));
|
||||
|
||||
if (insideComment) {
|
||||
// The current position is next to the '@' sign, when no tag name being provided yet.
|
||||
// Provide a full list of tag names
|
||||
if (hasDocComment(sourceFile, position) && sourceFile.text.charCodeAt(position - 1) === CharacterCodes.at) {
|
||||
isJsDocTagName = true;
|
||||
if (hasDocComment(sourceFile, position)) {
|
||||
// The current position is next to the '@' sign, when no tag name being provided yet.
|
||||
// Provide a full list of tag names
|
||||
if (sourceFile.text.charCodeAt(position - 1) === CharacterCodes.at) {
|
||||
requestJsDocTagName = true;
|
||||
}
|
||||
else {
|
||||
// When completion is requested without "@", we will have check to make sure that
|
||||
// there are no comments prefix the request position. We will only allow "*" and space.
|
||||
// e.g
|
||||
// /** |c| /*
|
||||
//
|
||||
// /**
|
||||
// |c|
|
||||
// */
|
||||
//
|
||||
// /**
|
||||
// * |c|
|
||||
// */
|
||||
//
|
||||
// /**
|
||||
// * |c|
|
||||
// */
|
||||
const lineStart = getLineStartPositionForPosition(position, sourceFile);
|
||||
requestJsDocTag = !(sourceFile.text.substring(lineStart, position).match(/[^\*|\s|(/\*\*)]/));
|
||||
}
|
||||
}
|
||||
|
||||
// Completion should work inside certain JsDoc tags. For example:
|
||||
@@ -839,7 +388,7 @@ namespace ts.Completions {
|
||||
const tag = getJsDocTagAtPosition(sourceFile, position);
|
||||
if (tag) {
|
||||
if (tag.tagName.pos <= position && position <= tag.tagName.end) {
|
||||
isJsDocTagName = true;
|
||||
requestJsDocTagName = true;
|
||||
}
|
||||
|
||||
switch (tag.kind) {
|
||||
@@ -854,8 +403,8 @@ namespace ts.Completions {
|
||||
}
|
||||
}
|
||||
|
||||
if (isJsDocTagName) {
|
||||
return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, isJsDocTagName };
|
||||
if (requestJsDocTagName || requestJsDocTag) {
|
||||
return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, requestJsDocTagName, requestJsDocTag };
|
||||
}
|
||||
|
||||
if (!insideJsDocTagExpression) {
|
||||
@@ -898,8 +447,8 @@ namespace ts.Completions {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const { parent, kind } = contextToken;
|
||||
if (kind === SyntaxKind.DotToken) {
|
||||
let parent = contextToken.parent;
|
||||
if (contextToken.kind === SyntaxKind.DotToken) {
|
||||
if (parent.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
node = (<PropertyAccessExpression>contextToken.parent).expression;
|
||||
isRightOfDot = true;
|
||||
@@ -915,16 +464,24 @@ namespace ts.Completions {
|
||||
}
|
||||
}
|
||||
else if (sourceFile.languageVariant === LanguageVariant.JSX) {
|
||||
switch (contextToken.parent.kind) {
|
||||
// <UI.Test /* completion position */ />
|
||||
// If the tagname is a property access expression, we will then walk up to the top most of property access expression.
|
||||
// Then, try to get a JSX container and its associated attributes type.
|
||||
if (parent && parent.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
contextToken = parent;
|
||||
parent = parent.parent;
|
||||
}
|
||||
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.JsxClosingElement:
|
||||
if (kind === SyntaxKind.SlashToken) {
|
||||
if (contextToken.kind === SyntaxKind.SlashToken) {
|
||||
isStartingCloseTag = true;
|
||||
location = contextToken;
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.BinaryExpression:
|
||||
if (!((contextToken.parent as BinaryExpression).left.flags & NodeFlags.ThisNodeHasError)) {
|
||||
if (!((parent as BinaryExpression).left.flags & NodeFlags.ThisNodeHasError)) {
|
||||
// It has a left-hand side, so we're not in an opening JSX tag.
|
||||
break;
|
||||
}
|
||||
@@ -933,7 +490,7 @@ namespace ts.Completions {
|
||||
case SyntaxKind.JsxSelfClosingElement:
|
||||
case SyntaxKind.JsxElement:
|
||||
case SyntaxKind.JsxOpeningElement:
|
||||
if (kind === SyntaxKind.LessThanToken) {
|
||||
if (contextToken.kind === SyntaxKind.LessThanToken) {
|
||||
isRightOfOpenTag = true;
|
||||
location = contextToken;
|
||||
}
|
||||
@@ -983,7 +540,7 @@ namespace ts.Completions {
|
||||
|
||||
log("getCompletionData: Semantic work: " + (timestamp() - semanticStart));
|
||||
|
||||
return { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), isJsDocTagName };
|
||||
return { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), requestJsDocTagName, requestJsDocTag };
|
||||
|
||||
function getTypeScriptMemberSymbols(): void {
|
||||
// Right of dot member completion list
|
||||
@@ -1401,6 +958,7 @@ namespace ts.Completions {
|
||||
case SyntaxKind.LessThanSlashToken:
|
||||
case SyntaxKind.SlashToken:
|
||||
case SyntaxKind.Identifier:
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.JsxAttributes:
|
||||
case SyntaxKind.JsxAttribute:
|
||||
case SyntaxKind.JsxSpreadAttribute:
|
||||
@@ -1457,20 +1015,18 @@ namespace ts.Completions {
|
||||
}
|
||||
|
||||
function isFunction(kind: SyntaxKind): boolean {
|
||||
if (!isFunctionLikeKind(kind)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (kind) {
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.FunctionType:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1748,59 +1304,6 @@ namespace ts.Completions {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a triple slash reference directive with an incomplete string literal for its path. Used
|
||||
* to determine if the caret is currently within the string literal and capture the literal fragment
|
||||
* for completions.
|
||||
* For example, this matches
|
||||
*
|
||||
* /// <reference path="fragment
|
||||
*
|
||||
* but not
|
||||
*
|
||||
* /// <reference path="fragment"
|
||||
*/
|
||||
const tripleSlashDirectiveFragmentRegex = /^(\/\/\/\s*<reference\s+(path|types)\s*=\s*(?:'|"))([^\3"]*)$/;
|
||||
|
||||
interface VisibleModuleInfo {
|
||||
moduleName: string;
|
||||
moduleDir: string;
|
||||
}
|
||||
|
||||
const nodeModulesDependencyKeys = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
|
||||
|
||||
function tryGetDirectories(host: LanguageServiceHost, directoryName: string): string[] {
|
||||
return tryIOAndConsumeErrors(host, host.getDirectories, directoryName);
|
||||
}
|
||||
|
||||
function tryReadDirectory(host: LanguageServiceHost, path: string, extensions?: string[], exclude?: string[], include?: string[]): string[] {
|
||||
return tryIOAndConsumeErrors(host, host.readDirectory, path, extensions, exclude, include);
|
||||
}
|
||||
|
||||
function tryReadFile(host: LanguageServiceHost, path: string): string {
|
||||
return tryIOAndConsumeErrors(host, host.readFile, path);
|
||||
}
|
||||
|
||||
function tryFileExists(host: LanguageServiceHost, path: string): boolean {
|
||||
return tryIOAndConsumeErrors(host, host.fileExists, path);
|
||||
}
|
||||
|
||||
function tryDirectoryExists(host: LanguageServiceHost, path: string): boolean {
|
||||
try {
|
||||
return directoryProbablyExists(path, host);
|
||||
}
|
||||
catch (e) {}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function tryIOAndConsumeErrors<T>(host: LanguageServiceHost, toApply: (...a: any[]) => T, ...args: any[]) {
|
||||
try {
|
||||
return toApply && toApply.apply(host, args);
|
||||
}
|
||||
catch (e) {}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function isEqualityExpression(node: Node): node is BinaryExpression {
|
||||
return isBinaryExpression(node) && isEqualityOperatorKind(node.operatorToken.kind);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user