mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into excess-property-checks-for-discriminated-unions
This commit is contained in:
+2
-1
@@ -57,4 +57,5 @@ internal/
|
||||
!tests/cases/projects/NodeModulesSearch/**/*
|
||||
!tests/baselines/reference/project/nodeModules*/**/*
|
||||
.idea
|
||||
yarn.lock
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
|
||||
+2
-1
@@ -16,4 +16,5 @@ Jakefile.js
|
||||
.gitattributes
|
||||
.settings/
|
||||
.travis.yml
|
||||
.vscode/
|
||||
.vscode/
|
||||
test.config
|
||||
+1
-3
@@ -16,9 +16,7 @@ matrix:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- release-2.1
|
||||
- release-2.2
|
||||
- release-2.3
|
||||
- release-2.5
|
||||
|
||||
install:
|
||||
- npm uninstall typescript --no-save
|
||||
|
||||
Vendored
+7
@@ -18,6 +18,13 @@
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"taskName": "tests",
|
||||
"showOutput": "silent",
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+96
-65
@@ -28,7 +28,6 @@ import minimist = require("minimist");
|
||||
import browserify = require("browserify");
|
||||
import through2 = require("through2");
|
||||
import merge2 = require("merge2");
|
||||
import intoStream = require("into-stream");
|
||||
import * as os from "os";
|
||||
import fold = require("travis-fold");
|
||||
const gulp = helpMaker(originalGulp);
|
||||
@@ -39,25 +38,25 @@ Error.stackTraceLimit = 1000;
|
||||
|
||||
const cmdLineOptions = minimist(process.argv.slice(2), {
|
||||
boolean: ["debug", "inspect", "light", "colors", "lint", "soft"],
|
||||
string: ["browser", "tests", "host", "reporter", "stackTraceLimit"],
|
||||
string: ["browser", "tests", "host", "reporter", "stackTraceLimit", "timeout"],
|
||||
alias: {
|
||||
b: "browser",
|
||||
d: "debug",
|
||||
t: "tests",
|
||||
test: "tests",
|
||||
d: "debug", "debug-brk": "debug",
|
||||
i: "inspect", "inspect-brk": "inspect",
|
||||
t: "tests", test: "tests",
|
||||
r: "reporter",
|
||||
color: "colors",
|
||||
f: "files",
|
||||
file: "files",
|
||||
c: "colors", color: "colors",
|
||||
f: "files", file: "files",
|
||||
w: "workers",
|
||||
},
|
||||
default: {
|
||||
soft: false,
|
||||
colors: process.env.colors || process.env.color || true,
|
||||
debug: process.env.debug || process.env.d,
|
||||
inspect: process.env.inspect,
|
||||
debug: process.env.debug || process.env["debug-brk"] || process.env.d,
|
||||
inspect: process.env.inspect || process.env["inspect-brk"] || process.env.i,
|
||||
host: process.env.TYPESCRIPT_HOST || process.env.host || "node",
|
||||
browser: process.env.browser || process.env.b || "IE",
|
||||
timeout: process.env.timeout || 40000,
|
||||
tests: process.env.test || process.env.tests || process.env.t,
|
||||
light: process.env.light || false,
|
||||
reporter: process.env.reporter || process.env.r,
|
||||
@@ -256,14 +255,8 @@ function needsUpdate(source: string | string[], dest: string | string[]): boolea
|
||||
return true;
|
||||
}
|
||||
|
||||
// Doing tsconfig inheritance manually. https://github.com/ivogabe/gulp-typescript/issues/459
|
||||
const tsconfigBase = JSON.parse(fs.readFileSync("src/tsconfig-base.json", "utf-8")).compilerOptions;
|
||||
|
||||
function getCompilerSettings(base: tsc.Settings, useBuiltCompiler?: boolean): tsc.Settings {
|
||||
const copy: tsc.Settings = {};
|
||||
for (const key in tsconfigBase) {
|
||||
copy[key] = tsconfigBase[key];
|
||||
}
|
||||
for (const key in base) {
|
||||
copy[key] = base[key];
|
||||
}
|
||||
@@ -300,7 +293,7 @@ gulp.task("configure-nightly", "Runs scripts/configureNightly.ts to prepare a bu
|
||||
exec(host, [configureNightlyJs, packageJson, versionFile], done, done);
|
||||
});
|
||||
gulp.task("publish-nightly", "Runs `npm publish --tag next` to create a new nightly build on npm", ["LKG"], () => {
|
||||
return runSequence("clean", "useDebugMode", "runtests", (done) => {
|
||||
return runSequence("clean", "useDebugMode", "runtests-parallel", (done) => {
|
||||
exec("npm", ["publish", "--tag", "next"], done, done);
|
||||
});
|
||||
});
|
||||
@@ -470,10 +463,11 @@ gulp.task(serverFile, /*help*/ false, [servicesFile, typingsInstallerJs, cancell
|
||||
.pipe(gulp.dest("src/server"));
|
||||
});
|
||||
|
||||
const typesMapJson = path.join(builtLocalDirectory, "typesMap.json");
|
||||
const tsserverLibraryFile = path.join(builtLocalDirectory, "tsserverlibrary.js");
|
||||
const tsserverLibraryDefinitionFile = path.join(builtLocalDirectory, "tsserverlibrary.d.ts");
|
||||
|
||||
gulp.task(tsserverLibraryFile, /*help*/ false, [servicesFile], (done) => {
|
||||
gulp.task(tsserverLibraryFile, /*help*/ false, [servicesFile, typesMapJson], (done) => {
|
||||
const serverLibraryProject = tsc.createProject("src/server/tsconfig.library.json", getCompilerSettings({}, /*useBuiltCompiler*/ true));
|
||||
const {js, dts}: { js: NodeJS.ReadableStream, dts: NodeJS.ReadableStream } = serverLibraryProject.src()
|
||||
.pipe(sourcemaps.init())
|
||||
@@ -492,6 +486,15 @@ gulp.task(tsserverLibraryFile, /*help*/ false, [servicesFile], (done) => {
|
||||
]);
|
||||
});
|
||||
|
||||
gulp.task(typesMapJson, /*help*/ false, [], () => {
|
||||
return gulp.src("src/server/typesMap.json")
|
||||
.pipe(insert.transform((contents, file) => {
|
||||
JSON.parse(contents);
|
||||
return contents;
|
||||
}))
|
||||
.pipe(gulp.dest(builtLocalDirectory));
|
||||
});
|
||||
|
||||
gulp.task("lssl", "Builds language service server library", [tsserverLibraryFile]);
|
||||
gulp.task("local", "Builds the full compiler and services", [builtLocalCompiler, servicesFile, serverFile, builtGeneratedDiagnosticMessagesJSON, tsserverLibraryFile]);
|
||||
gulp.task("tsc", "Builds only the compiler", [builtLocalCompiler]);
|
||||
@@ -561,7 +564,7 @@ gulp.task(run, /*help*/ false, [servicesFile], () => {
|
||||
.pipe(newer(run))
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(testProject())
|
||||
.pipe(sourcemaps.write(".", { includeContent: false, sourceRoot: "../../" }))
|
||||
.pipe(sourcemaps.write(".", { includeContent: false, sourceRoot: "." }))
|
||||
.pipe(gulp.dest("src/harness"));
|
||||
});
|
||||
|
||||
@@ -594,11 +597,11 @@ function restoreSavedNodeEnv() {
|
||||
process.env.NODE_ENV = savedNodeEnv;
|
||||
}
|
||||
|
||||
let testTimeout = 40000;
|
||||
function runConsoleTests(defaultReporter: string, runInParallel: boolean, done: (e?: any) => void) {
|
||||
const lintFlag = cmdLineOptions["lint"];
|
||||
cleanTestDirs((err) => {
|
||||
if (err) { console.error(err); failWithStatus(err, 1); }
|
||||
let testTimeout = cmdLineOptions["timeout"];
|
||||
const debug = cmdLineOptions["debug"];
|
||||
const inspect = cmdLineOptions["inspect"];
|
||||
const tests = cmdLineOptions["tests"];
|
||||
@@ -637,12 +640,6 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done:
|
||||
// default timeout is 2sec which really should be enough, but maybe we just need a small amount longer
|
||||
if (!runInParallel) {
|
||||
const args = [];
|
||||
if (inspect) {
|
||||
args.push("--inspect");
|
||||
}
|
||||
if (inspect || debug) {
|
||||
args.push("--debug-brk");
|
||||
}
|
||||
args.push("-R", reporter);
|
||||
if (tests) {
|
||||
args.push("-g", `"${tests}"`);
|
||||
@@ -653,7 +650,15 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done:
|
||||
else {
|
||||
args.push("--no-colors");
|
||||
}
|
||||
args.push("-t", testTimeout);
|
||||
if (inspect) {
|
||||
args.unshift("--inspect-brk");
|
||||
}
|
||||
else if (debug) {
|
||||
args.unshift("--debug-brk");
|
||||
}
|
||||
else {
|
||||
args.push("-t", testTimeout);
|
||||
}
|
||||
args.push(run);
|
||||
setNodeEnvToDevelopment();
|
||||
exec(mocha, args, lintThenFinish, function(e, status) {
|
||||
@@ -673,7 +678,7 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done:
|
||||
}
|
||||
args.push(run);
|
||||
setNodeEnvToDevelopment();
|
||||
runTestsInParallel(taskConfigsFolder, run, { testTimeout: testTimeout, noColors: colors === " --no-colors " }, function(err) {
|
||||
runTestsInParallel(taskConfigsFolder, run, { testTimeout, noColors: colors === " --no-colors " }, function(err) {
|
||||
// last worker clean everything and runs linter in case if there were no errors
|
||||
del(taskConfigsFolder).then(() => {
|
||||
if (!err) {
|
||||
@@ -741,50 +746,75 @@ gulp.task(nodeServerOutFile, /*help*/ false, [servicesFile], () => {
|
||||
|
||||
import convertMap = require("convert-source-map");
|
||||
import sorcery = require("sorcery");
|
||||
declare module "convert-source-map" {
|
||||
export function fromSource(source: string, largeSource?: boolean): SourceMapConverter;
|
||||
}
|
||||
import Vinyl = require("vinyl");
|
||||
|
||||
const bundlePath = path.resolve("built/local/bundle.js");
|
||||
|
||||
gulp.task("browserify", "Runs browserify on run.js to produce a file suitable for running tests in the browser", [servicesFile], (done) => {
|
||||
const testProject = tsc.createProject("src/harness/tsconfig.json", getCompilerSettings({ outFile: "../../built/local/bundle.js" }, /*useBuiltCompiler*/ true));
|
||||
return testProject.src()
|
||||
.pipe(newer("built/local/bundle.js"))
|
||||
const testProject = tsc.createProject("src/harness/tsconfig.json", getCompilerSettings({ outFile: bundlePath, inlineSourceMap: true }, /*useBuiltCompiler*/ true));
|
||||
let originalMap: any;
|
||||
let prebundledContent: string;
|
||||
browserify(testProject.src()
|
||||
.pipe(newer(bundlePath))
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(testProject())
|
||||
.pipe(through2.obj((file, enc, next) => {
|
||||
const originalMap = file.sourceMap;
|
||||
const prebundledContent = file.contents.toString();
|
||||
if (originalMap) {
|
||||
throw new Error("Should only recieve one file!");
|
||||
}
|
||||
console.log(`Saving sourcemaps for ${file.path}`);
|
||||
originalMap = file.sourceMap;
|
||||
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(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
|
||||
// browserify names input files this when they are streamed in, so this is what it puts in the sourcemap
|
||||
originalMap.file = "built/local/_stream_0.js";
|
||||
|
||||
browserify(intoStream(file.contents), { debug: true })
|
||||
.bundle((err, res) => {
|
||||
// assumes file.contents is a Buffer
|
||||
const maps = JSON.parse(convertMap.fromSource(res.toString(), /*largeSource*/ true).toJSON());
|
||||
delete maps.sourceRoot;
|
||||
maps.sources = maps.sources.map(s => path.resolve(s === "_stream_0.js" ? "built/local/_stream_0.js" : s));
|
||||
// Strip browserify's inline comments away (could probably just let sorcery do this, but then we couldn't fix the paths)
|
||||
file.contents = new Buffer(convertMap.removeComments(res.toString()));
|
||||
const chain = sorcery.loadSync("built/local/bundle.js", {
|
||||
content: {
|
||||
"built/local/_stream_0.js": prebundledContent,
|
||||
"built/local/bundle.js": file.contents.toString()
|
||||
},
|
||||
sourcemaps: {
|
||||
"built/local/_stream_0.js": originalMap,
|
||||
"built/local/bundle.js": maps,
|
||||
"node_modules/source-map-support/source-map-support.js": undefined,
|
||||
}
|
||||
});
|
||||
const finalMap = chain.apply();
|
||||
file.sourceMap = finalMap;
|
||||
next(/*err*/ undefined, file);
|
||||
});
|
||||
next(/*err*/ undefined, file.contents);
|
||||
}))
|
||||
.pipe(sourcemaps.write(".", { includeContent: false }))
|
||||
.pipe(gulp.dest("src/harness"));
|
||||
.on("error", err => {
|
||||
return done(err);
|
||||
}), { debug: true, basedir: __dirname }) // Attach error handler to inner stream
|
||||
.bundle((err, contents) => {
|
||||
if (err) {
|
||||
if (err.message.match(/Cannot find module '.*_stream_0.js'/)) {
|
||||
return done(); // Browserify errors when we pass in no files when `newer` filters the input, we should count that as a success, though
|
||||
}
|
||||
return done(err);
|
||||
}
|
||||
const stringContent = contents.toString();
|
||||
const file = new Vinyl({ contents, path: bundlePath });
|
||||
console.log(`Fixing sourcemaps for ${file.path}`);
|
||||
// assumes contents is a Buffer, since that's what browserify yields
|
||||
const maps = convertMap.fromSource(stringContent, /*largeSource*/ true).toObject();
|
||||
delete maps.sourceRoot;
|
||||
maps.sources = maps.sources.map(s => path.resolve(s === "_stream_0.js" ? "built/local/_stream_0.js" : s));
|
||||
// Strip browserify's inline comments away (could probably just let sorcery do this, but then we couldn't fix the paths)
|
||||
file.contents = new Buffer(convertMap.removeComments(stringContent));
|
||||
const chain = sorcery.loadSync(bundlePath, {
|
||||
content: {
|
||||
"built/local/_stream_0.js": prebundledContent,
|
||||
[bundlePath]: stringContent
|
||||
},
|
||||
sourcemaps: {
|
||||
"built/local/_stream_0.js": originalMap,
|
||||
[bundlePath]: maps,
|
||||
"node_modules/source-map-support/source-map-support.js": undefined,
|
||||
}
|
||||
});
|
||||
const finalMap = chain.apply();
|
||||
file.sourceMap = finalMap;
|
||||
|
||||
const stream = through2.obj((file, enc, callback) => {
|
||||
return callback(/*err*/ undefined, file);
|
||||
});
|
||||
stream.pipe(sourcemaps.write(".", { includeContent: false }))
|
||||
.pipe(gulp.dest("."))
|
||||
.on("end", done)
|
||||
.on("error", done);
|
||||
stream.write(file);
|
||||
stream.end();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -838,6 +868,7 @@ gulp.task("runtests-browser", "Runs the tests using the built run.js file like '
|
||||
});
|
||||
|
||||
gulp.task("generate-code-coverage", "Generates code coverage data via istanbul", ["tests"], (done) => {
|
||||
const testTimeout = cmdLineOptions["timeout"];
|
||||
exec("istanbul", ["cover", "node_modules/mocha/bin/_mocha", "--", "-R", "min", "-t", testTimeout.toString(), run], done, done);
|
||||
});
|
||||
|
||||
@@ -947,7 +978,7 @@ const instrumenterPath = path.join(harnessDirectory, "instrumenter.ts");
|
||||
const instrumenterJsPath = path.join(builtLocalDirectory, "instrumenter.js");
|
||||
gulp.task(instrumenterJsPath, /*help*/ false, [servicesFile], () => {
|
||||
const settings: tsc.Settings = getCompilerSettings({
|
||||
outFile: instrumenterJsPath,
|
||||
module: "commonjs",
|
||||
target: "es5",
|
||||
lib: [
|
||||
"es6",
|
||||
@@ -959,8 +990,8 @@ gulp.task(instrumenterJsPath, /*help*/ false, [servicesFile], () => {
|
||||
.pipe(newer(instrumenterJsPath))
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(tsc(settings))
|
||||
.pipe(sourcemaps.write("."))
|
||||
.pipe(gulp.dest("."));
|
||||
.pipe(sourcemaps.write(builtLocalDirectory))
|
||||
.pipe(gulp.dest(builtLocalDirectory));
|
||||
});
|
||||
|
||||
gulp.task("tsc-instrumented", "Builds an instrumented tsc.js", ["local", loggedIOJsPath, instrumenterJsPath, servicesFile], (done) => {
|
||||
|
||||
+53
-43
@@ -25,6 +25,8 @@ var LKGDirectory = "lib/";
|
||||
var copyright = "CopyrightNotice.txt";
|
||||
var thirdParty = "ThirdPartyNoticeText.txt";
|
||||
|
||||
var defaultTestTimeout = 40000;
|
||||
|
||||
// add node_modules to path so we don't need global modules, prefer the modules by adding them first
|
||||
var nodeModulesPathPrefix = path.resolve("./node_modules/.bin/") + path.delimiter;
|
||||
if (process.env.path !== undefined) {
|
||||
@@ -74,6 +76,10 @@ function measure(marker) {
|
||||
console.log("travis_time:end:" + marker.id + ":start=" + toNs(marker.stamp) + ",finish=" + toNs(total) + ",duration=" + toNs(diff) + "\r");
|
||||
}
|
||||
|
||||
function removeConstModifierFromEnumDeclarations(text) {
|
||||
return text.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, '$1$2enum $3 {$4');
|
||||
}
|
||||
|
||||
var compilerSources = filesFromConfig("./src/compiler/tsconfig.json");
|
||||
var servicesSources = filesFromConfig("./src/services/tsconfig.json");
|
||||
var cancellationTokenSources = filesFromConfig(path.join(serverDirectory, "cancellationToken/tsconfig.json"));
|
||||
@@ -82,6 +88,8 @@ var watchGuardSources = filesFromConfig(path.join(serverDirectory, "watchGuard/t
|
||||
var serverSources = filesFromConfig(path.join(serverDirectory, "tsconfig.json"))
|
||||
var languageServiceLibrarySources = filesFromConfig(path.join(serverDirectory, "tsconfig.library.json"));
|
||||
|
||||
var typesMapOutputPath = path.join(builtLocalDirectory, 'typesMap.json');
|
||||
|
||||
var harnessCoreSources = [
|
||||
"harness.ts",
|
||||
"virtualFileSystem.ts",
|
||||
@@ -127,11 +135,14 @@ var harnessSources = harnessCoreSources.concat([
|
||||
"projectErrors.ts",
|
||||
"matchFiles.ts",
|
||||
"initializeTSConfig.ts",
|
||||
"extractMethods.ts",
|
||||
"printer.ts",
|
||||
"textChanges.ts",
|
||||
"telemetry.ts",
|
||||
"transform.ts",
|
||||
"customTransforms.ts",
|
||||
"programMissingFiles.ts",
|
||||
"symbolWalker.ts",
|
||||
].map(function (f) {
|
||||
return path.join(unittestsDirectory, f);
|
||||
})).concat([
|
||||
@@ -280,7 +291,7 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts
|
||||
var startCompileTime = mark();
|
||||
opts = opts || {};
|
||||
var compilerPath = useBuiltCompiler ? builtLocalCompiler : LKGCompiler;
|
||||
var options = "--noImplicitAny --noImplicitThis --noEmitOnError --types "
|
||||
var options = "--noImplicitAny --noImplicitThis --alwaysStrict --noEmitOnError --types "
|
||||
if (opts.types) {
|
||||
options += opts.types.join(",");
|
||||
}
|
||||
@@ -415,6 +426,7 @@ var buildProtocolTs = path.join(scriptsDirectory, "buildProtocol.ts");
|
||||
var buildProtocolJs = path.join(scriptsDirectory, "buildProtocol.js");
|
||||
var buildProtocolDts = path.join(builtLocalDirectory, "protocol.d.ts");
|
||||
var typescriptServicesDts = path.join(builtLocalDirectory, "typescriptServices.d.ts");
|
||||
var typesMapJson = path.join(builtLocalDirectory, "typesMap.json");
|
||||
|
||||
file(buildProtocolTs);
|
||||
|
||||
@@ -498,7 +510,7 @@ task("configure-nightly", [configureNightlyJs], function () {
|
||||
}, { async: true });
|
||||
|
||||
desc("Configure, build, test, and publish the nightly release.");
|
||||
task("publish-nightly", ["configure-nightly", "LKG", "clean", "setDebugMode", "runtests"], function () {
|
||||
task("publish-nightly", ["configure-nightly", "LKG", "clean", "setDebugMode", "runtests-parallel"], function () {
|
||||
var cmd = "npm publish --tag next";
|
||||
console.log(cmd);
|
||||
exec(cmd);
|
||||
@@ -526,7 +538,6 @@ var tscFile = path.join(builtLocalDirectory, compilerFilename);
|
||||
compileFile(tscFile, compilerSources, [builtLocalDirectory, copyright].concat(compilerSources), [copyright], /*useBuiltCompiler:*/ false);
|
||||
|
||||
var servicesFile = path.join(builtLocalDirectory, "typescriptServices.js");
|
||||
var servicesFileInBrowserTest = path.join(builtLocalDirectory, "typescriptServicesInBrowserTest.js");
|
||||
var standaloneDefinitionsFile = path.join(builtLocalDirectory, "typescriptServices.d.ts");
|
||||
var nodePackageFile = path.join(builtLocalDirectory, "typescript.js");
|
||||
var nodeDefinitionsFile = path.join(builtLocalDirectory, "typescript.d.ts");
|
||||
@@ -551,7 +562,7 @@ compileFile(servicesFile, servicesSources, [builtLocalDirectory, copyright].conc
|
||||
// Stanalone/web definition file using global 'ts' namespace
|
||||
jake.cpR(standaloneDefinitionsFile, nodeDefinitionsFile, { silent: true });
|
||||
var definitionFileContents = fs.readFileSync(nodeDefinitionsFile).toString();
|
||||
definitionFileContents = definitionFileContents.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, '$1$2enum $3 {$4');
|
||||
definitionFileContents = removeConstModifierFromEnumDeclarations(definitionFileContents)
|
||||
fs.writeFileSync(standaloneDefinitionsFile, definitionFileContents);
|
||||
|
||||
// Official node package definition file, pointed to by 'typings' in package.json
|
||||
@@ -565,22 +576,6 @@ compileFile(servicesFile, servicesSources, [builtLocalDirectory, copyright].conc
|
||||
fs.writeFileSync(nodeStandaloneDefinitionsFile, nodeStandaloneDefinitionsFileContents);
|
||||
});
|
||||
|
||||
compileFile(
|
||||
servicesFileInBrowserTest,
|
||||
servicesSources,
|
||||
[builtLocalDirectory, copyright].concat(servicesSources),
|
||||
/*prefixes*/[copyright],
|
||||
/*useBuiltCompiler*/ true,
|
||||
{
|
||||
noOutFile: false,
|
||||
generateDeclarations: true,
|
||||
preserveConstEnums: true,
|
||||
keepComments: true,
|
||||
noResolve: false,
|
||||
stripInternal: true,
|
||||
inlineSourceMap: true
|
||||
});
|
||||
|
||||
file(typescriptServicesDts, [servicesFile]);
|
||||
|
||||
var cancellationTokenFile = path.join(builtLocalDirectory, "cancellationToken.js");
|
||||
@@ -596,6 +591,16 @@ var serverFile = path.join(builtLocalDirectory, "tsserver.js");
|
||||
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");
|
||||
file(typesMapOutputPath, function() {
|
||||
var content = fs.readFileSync(path.join(serverDirectory, 'typesMap.json'));
|
||||
// Validate that it's valid JSON
|
||||
try {
|
||||
JSON.parse(content);
|
||||
} catch (e) {
|
||||
console.log("Parse error in typesMap.json: " + e);
|
||||
}
|
||||
fs.writeFileSync(typesMapOutputPath, content);
|
||||
});
|
||||
compileFile(
|
||||
tsserverLibraryFile,
|
||||
languageServiceLibrarySources,
|
||||
@@ -611,13 +616,14 @@ compileFile(
|
||||
fs.readFileSync(tsserverLibraryDefinitionFile).toString() +
|
||||
"\r\nexport = ts;" +
|
||||
"\r\nexport as namespace ts;";
|
||||
tsserverLibraryDefinitionFileContents = removeConstModifierFromEnumDeclarations(tsserverLibraryDefinitionFileContents);
|
||||
|
||||
fs.writeFileSync(tsserverLibraryDefinitionFile, tsserverLibraryDefinitionFileContents);
|
||||
});
|
||||
|
||||
// Local target to build the language service server library
|
||||
desc("Builds language service server library");
|
||||
task("lssl", [tsserverLibraryFile, tsserverLibraryDefinitionFile]);
|
||||
task("lssl", [tsserverLibraryFile, tsserverLibraryDefinitionFile, typesMapOutputPath]);
|
||||
|
||||
desc("Emit the start of the build fold");
|
||||
task("build-fold-start", [], function () {
|
||||
@@ -646,7 +652,6 @@ task("release", function () {
|
||||
// Set the default task to "local"
|
||||
task("default", ["local"]);
|
||||
|
||||
|
||||
// Cleans the built directory
|
||||
desc("Cleans the compiler output, declare files, and tests");
|
||||
task("clean", function () {
|
||||
@@ -717,7 +722,7 @@ compileFile(
|
||||
/*prereqs*/[builtLocalDirectory, tscFile].concat(libraryTargets).concat(servicesSources).concat(harnessSources),
|
||||
/*prefixes*/[],
|
||||
/*useBuiltCompiler:*/ true,
|
||||
/*opts*/ { inlineSourceMap: true, types: ["node", "mocha", "chai"], lib: "es6" });
|
||||
/*opts*/ { types: ["node", "mocha", "chai"], lib: "es6" });
|
||||
|
||||
var internalTests = "internal/";
|
||||
|
||||
@@ -800,8 +805,8 @@ function runConsoleTests(defaultReporter, runInParallel) {
|
||||
cleanTestDirs();
|
||||
}
|
||||
|
||||
var debug = process.env.debug || process.env.d;
|
||||
var inspect = process.env.inspect;
|
||||
var debug = process.env.debug || process.env["debug-brk"] || process.env.d;
|
||||
var inspect = process.env.inspect || process.env["inspect-brk"] || process.env.i;
|
||||
var testTimeout = process.env.timeout || defaultTestTimeout;
|
||||
var tests = process.env.test || process.env.tests || process.env.t;
|
||||
var light = process.env.light || false;
|
||||
@@ -832,7 +837,8 @@ function runConsoleTests(defaultReporter, runInParallel) {
|
||||
testTimeout = 800000;
|
||||
}
|
||||
|
||||
var colors = process.env.colors || process.env.color || true;
|
||||
var colorsFlag = process.env.color || process.env.colors;
|
||||
var colors = colorsFlag !== "false" && colorsFlag !== "0";
|
||||
var reporter = process.env.reporter || process.env.r || defaultReporter;
|
||||
var bail = process.env.bail || process.env.b;
|
||||
var lintFlag = process.env.lint !== 'false';
|
||||
@@ -842,12 +848,6 @@ function runConsoleTests(defaultReporter, runInParallel) {
|
||||
if (!runInParallel) {
|
||||
var startTime = mark();
|
||||
var args = [];
|
||||
if (inspect) {
|
||||
args.push("--inspect");
|
||||
}
|
||||
if (inspect || debug) {
|
||||
args.push("--debug-brk");
|
||||
}
|
||||
args.push("-R", reporter);
|
||||
if (tests) {
|
||||
args.push("-g", `"${tests}"`);
|
||||
@@ -861,7 +861,15 @@ function runConsoleTests(defaultReporter, runInParallel) {
|
||||
if (bail) {
|
||||
args.push("--bail");
|
||||
}
|
||||
args.push("-t", testTimeout);
|
||||
if (inspect) {
|
||||
args.unshift("--inspect-brk");
|
||||
}
|
||||
else if (debug) {
|
||||
args.unshift("--debug-brk");
|
||||
}
|
||||
else {
|
||||
args.push("-t", testTimeout);
|
||||
}
|
||||
args.push(run);
|
||||
|
||||
var cmd = "mocha " + args.join(" ");
|
||||
@@ -926,7 +934,6 @@ function runConsoleTests(defaultReporter, runInParallel) {
|
||||
}
|
||||
}
|
||||
|
||||
var defaultTestTimeout = 22000;
|
||||
desc("Runs all the tests in parallel using the built run.js file. Optional arguments are: t[ests]=category1|category2|... d[ebug]=true.");
|
||||
task("runtests-parallel", ["build-rules", "tests", builtLocalDirectory], function () {
|
||||
runConsoleTests('min', /*runInParallel*/ true);
|
||||
@@ -939,6 +946,7 @@ task("runtests", ["build-rules", "tests", builtLocalDirectory], function() {
|
||||
|
||||
desc("Generates code coverage data via instanbul");
|
||||
task("generate-code-coverage", ["tests", builtLocalDirectory], function () {
|
||||
var testTimeout = process.env.timeout || defaultTestTimeout;
|
||||
var cmd = 'istanbul cover node_modules/mocha/bin/_mocha -- -R min -t ' + testTimeout + ' ' + run;
|
||||
console.log(cmd);
|
||||
exec(cmd);
|
||||
@@ -950,13 +958,14 @@ var nodeServerInFile = "tests/webTestServer.ts";
|
||||
compileFile(nodeServerOutFile, [nodeServerInFile], [builtLocalDirectory, tscFile], [], /*useBuiltCompiler:*/ true, { noOutFile: true, lib: "es6" });
|
||||
|
||||
desc("Runs browserify on run.js to produce a file suitable for running tests in the browser");
|
||||
task("browserify", ["tests", builtLocalDirectory, nodeServerOutFile], function() {
|
||||
var cmd = 'browserify built/local/run.js -t ./scripts/browserify-optional -d -o built/local/bundle.js';
|
||||
task("browserify", [], function() {
|
||||
// Shell out to `gulp`, since we do the work to handle sourcemaps correctly w/o inline maps there
|
||||
var cmd = 'gulp browserify --silent';
|
||||
exec(cmd);
|
||||
}, { async: true });
|
||||
|
||||
desc("Runs the tests using the built run.js file like 'jake runtests'. Syntax is jake runtests-browser. Additional optional parameters tests=[regex], browser=[chrome|IE]");
|
||||
task("runtests-browser", ["tests", "browserify", builtLocalDirectory, servicesFileInBrowserTest], function () {
|
||||
task("runtests-browser", ["browserify", nodeServerOutFile], function () {
|
||||
cleanTestDirs();
|
||||
host = "node";
|
||||
browser = process.env.browser || process.env.b || (os.platform() === "linux" ? "chrome" : "IE");
|
||||
@@ -1090,7 +1099,7 @@ file(loggedIOJsPath, [builtLocalDirectory, loggedIOpath], function () {
|
||||
|
||||
var instrumenterPath = harnessDirectory + 'instrumenter.ts';
|
||||
var instrumenterJsPath = builtLocalDirectory + 'instrumenter.js';
|
||||
compileFile(instrumenterJsPath, [instrumenterPath], [tscFile, instrumenterPath].concat(libraryTargets), [], /*useBuiltCompiler*/ true, { lib: "es6", types: ["node"] });
|
||||
compileFile(instrumenterJsPath, [instrumenterPath], [tscFile, instrumenterPath].concat(libraryTargets), [], /*useBuiltCompiler*/ true, { lib: "es6", types: ["node"], noOutFile: true, outDir: builtLocalDirectory });
|
||||
|
||||
desc("Builds an instrumented tsc.js");
|
||||
task('tsc-instrumented', [loggedIOJsPath, instrumenterJsPath, tscFile], function () {
|
||||
@@ -1111,14 +1120,15 @@ task("update-sublime", ["local", serverFile], function () {
|
||||
|
||||
var tslintRuleDir = "scripts/tslint";
|
||||
var tslintRules = [
|
||||
"nextLineRule",
|
||||
"booleanTriviaRule",
|
||||
"typeOperatorSpacingRule",
|
||||
"noInOperatorRule",
|
||||
"debugAssertRule",
|
||||
"nextLineRule",
|
||||
"noBomRule",
|
||||
"noIncrementDecrementRule",
|
||||
"objectLiteralSurroundingSpaceRule",
|
||||
"noInOperatorRule",
|
||||
"noTypeAssertionWhitespaceRule",
|
||||
"noBomRule"
|
||||
"objectLiteralSurroundingSpaceRule",
|
||||
"typeOperatorSpacingRule",
|
||||
];
|
||||
var tslintRulesFiles = tslintRules.map(function (p) {
|
||||
return path.join(tslintRuleDir, p + ".ts");
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
[](https://gitter.im/Microsoft/TypeScript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
[TypeScript](http://www.typescriptlang.org/) is a language for application-scale JavaScript. TypeScript adds optional types, classes, and modules to JavaScript. TypeScript supports tools for large-scale JavaScript applications for any browser, for any host, on any OS. TypeScript compiles to readable, standards-based JavaScript. Try it out at the [playground](http://www.typescriptlang.org/Playground), and stay up to date via [our blog](https://blogs.msdn.microsoft.com/typescript) and [Twitter account](https://twitter.com/typescriptlang).
|
||||
[TypeScript](https://www.typescriptlang.org/) is a language for application-scale JavaScript. TypeScript adds optional types, classes, and modules to JavaScript. TypeScript supports tools for large-scale JavaScript applications for any browser, for any host, on any OS. TypeScript compiles to readable, standards-based JavaScript. Try it out at the [playground](https://www.typescriptlang.org/play/), and stay up to date via [our blog](https://blogs.msdn.microsoft.com/typescript) and [Twitter account](https://twitter.com/typescriptlang).
|
||||
|
||||
## Installing
|
||||
|
||||
@@ -27,8 +27,8 @@ npm install -g typescript@next
|
||||
There are many ways to [contribute](https://github.com/Microsoft/TypeScript/blob/master/CONTRIBUTING.md) to TypeScript.
|
||||
* [Submit bugs](https://github.com/Microsoft/TypeScript/issues) and help us verify fixes as they are checked in.
|
||||
* Review the [source code changes](https://github.com/Microsoft/TypeScript/pulls).
|
||||
* Engage with other TypeScript users and developers on [StackOverflow](http://stackoverflow.com/questions/tagged/typescript).
|
||||
* Join the [#typescript](http://twitter.com/#!/search/realtime/%23typescript) discussion on Twitter.
|
||||
* Engage with other TypeScript users and developers on [StackOverflow](https://stackoverflow.com/questions/tagged/typescript).
|
||||
* Join the [#typescript](https://twitter.com/#!/search/realtime/%23typescript) discussion on Twitter.
|
||||
* [Contribute bug fixes](https://github.com/Microsoft/TypeScript/blob/master/CONTRIBUTING.md).
|
||||
* Read the language specification ([docx](https://github.com/Microsoft/TypeScript/blob/master/doc/TypeScript%20Language%20Specification.docx?raw=true),
|
||||
[pdf](https://github.com/Microsoft/TypeScript/blob/master/doc/TypeScript%20Language%20Specification.pdf?raw=true), [md](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md)).
|
||||
@@ -39,14 +39,14 @@ with any additional questions or comments.
|
||||
|
||||
## Documentation
|
||||
|
||||
* [Quick tutorial](http://www.typescriptlang.org/docs/tutorial.html)
|
||||
* [Programming handbook](http://www.typescriptlang.org/docs/handbook/basic-types.html)
|
||||
* [Quick tutorial](https://www.typescriptlang.org/docs/tutorial.html)
|
||||
* [Programming handbook](https://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/)
|
||||
* [Homepage](https://www.typescriptlang.org/)
|
||||
|
||||
## Building
|
||||
|
||||
In order to build the TypeScript compiler, ensure that you have [Git](http://git-scm.com/downloads) and [Node.js](http://nodejs.org/) installed.
|
||||
In order to build the TypeScript compiler, ensure that you have [Git](https://git-scm.com/downloads) and [Node.js](https://nodejs.org/) installed.
|
||||
|
||||
Clone a copy of the repo:
|
||||
|
||||
|
||||
+2
-2
@@ -2,13 +2,13 @@
|
||||
<!-- 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.2.1 / nightly (2.2.0-dev.201xxxxx)
|
||||
**TypeScript Version:** 2.4.0 / nightly (2.5.0-dev.201xxxxx)
|
||||
|
||||
**Code**
|
||||
|
||||
```ts
|
||||
// A *self-contained* demonstration of the problem follows...
|
||||
|
||||
// Test this by running `tsc` on the command-line, rather than through another build tool such as Gulp, Webpack, etc.
|
||||
```
|
||||
|
||||
**Expected behavior:**
|
||||
|
||||
@@ -69,5 +69,3 @@ function createCancellationToken(args) {
|
||||
}
|
||||
}
|
||||
module.exports = createCancellationToken;
|
||||
|
||||
//# sourceMappingURL=cancellationToken.js.map
|
||||
|
||||
Vendored
+4346
-4803
File diff suppressed because it is too large
Load Diff
Vendored
+4200
-4452
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
@@ -21,8 +21,8 @@ and limitations under the License.
|
||||
/// <reference path="lib.es2015.core.d.ts" />
|
||||
/// <reference path="lib.es2015.collection.d.ts" />
|
||||
/// <reference path="lib.es2015.generator.d.ts" />
|
||||
/// <reference path="lib.es2015.iterable.d.ts" />
|
||||
/// <reference path="lib.es2015.promise.d.ts" />
|
||||
/// <reference path="lib.es2015.iterable.d.ts" />
|
||||
/// <reference path="lib.es2015.proxy.d.ts" />
|
||||
/// <reference path="lib.es2015.reflect.d.ts" />
|
||||
/// <reference path="lib.es2015.symbol.d.ts" />
|
||||
|
||||
Vendored
+4200
-6276
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
@@ -22,4 +22,4 @@ and limitations under the License.
|
||||
/// <reference path="lib.es2017.object.d.ts" />
|
||||
/// <reference path="lib.es2017.sharedmemory.d.ts" />
|
||||
/// <reference path="lib.es2017.string.d.ts" />
|
||||
/// <reference path="lib.es2017.intl.d.ts" />
|
||||
/// <reference path="lib.es2017.intl.d.ts" />
|
||||
|
||||
Vendored
+4200
-6275
File diff suppressed because it is too large
Load Diff
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
/*! *****************************************************************************
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
this file except in compliance with the License. You may obtain a copy of the
|
||||
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||
|
||||
See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
|
||||
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
|
||||
|
||||
type DateTimeFormatPartTypes = "day" | "dayPeriod" | "era" | "hour" | "literal" | "minute" | "month" | "second" | "timeZoneName" | "weekday" | "year";
|
||||
|
||||
interface DateTimeFormatPart {
|
||||
type: DateTimeFormatPartTypes;
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface DateTimeFormat {
|
||||
formatToParts(date?: Date | number): DateTimeFormatPart[];
|
||||
}
|
||||
Vendored
+146
-351
File diff suppressed because it is too large
Load Diff
Vendored
+4346
-4803
File diff suppressed because it is too large
Load Diff
Vendored
+4200
-6276
File diff suppressed because it is too large
Load Diff
Vendored
+145
-134
@@ -20,7 +20,7 @@ and limitations under the License.
|
||||
|
||||
|
||||
/////////////////////////////
|
||||
/// IE Worker APIs
|
||||
/// Worker APIs
|
||||
/////////////////////////////
|
||||
|
||||
interface Algorithm {
|
||||
@@ -28,16 +28,16 @@ interface Algorithm {
|
||||
}
|
||||
|
||||
interface CacheQueryOptions {
|
||||
ignoreSearch?: boolean;
|
||||
ignoreMethod?: boolean;
|
||||
ignoreVary?: boolean;
|
||||
cacheName?: string;
|
||||
ignoreMethod?: boolean;
|
||||
ignoreSearch?: boolean;
|
||||
ignoreVary?: boolean;
|
||||
}
|
||||
|
||||
interface CloseEventInit extends EventInit {
|
||||
wasClean?: boolean;
|
||||
code?: number;
|
||||
reason?: string;
|
||||
wasClean?: boolean;
|
||||
}
|
||||
|
||||
interface EventInit {
|
||||
@@ -69,16 +69,16 @@ interface MessageEventInit extends EventInit {
|
||||
channel?: string;
|
||||
data?: any;
|
||||
origin?: string;
|
||||
source?: any;
|
||||
ports?: MessagePort[];
|
||||
source?: any;
|
||||
}
|
||||
|
||||
interface NotificationOptions {
|
||||
dir?: NotificationDirection;
|
||||
lang?: string;
|
||||
body?: string;
|
||||
tag?: string;
|
||||
dir?: NotificationDirection;
|
||||
icon?: string;
|
||||
lang?: string;
|
||||
tag?: string;
|
||||
}
|
||||
|
||||
interface ObjectURLOptions {
|
||||
@@ -86,29 +86,29 @@ interface ObjectURLOptions {
|
||||
}
|
||||
|
||||
interface PushSubscriptionOptionsInit {
|
||||
userVisibleOnly?: boolean;
|
||||
applicationServerKey?: any;
|
||||
userVisibleOnly?: boolean;
|
||||
}
|
||||
|
||||
interface RequestInit {
|
||||
method?: string;
|
||||
headers?: any;
|
||||
body?: any;
|
||||
referrer?: string;
|
||||
referrerPolicy?: ReferrerPolicy;
|
||||
mode?: RequestMode;
|
||||
credentials?: RequestCredentials;
|
||||
cache?: RequestCache;
|
||||
redirect?: RequestRedirect;
|
||||
credentials?: RequestCredentials;
|
||||
headers?: any;
|
||||
integrity?: string;
|
||||
keepalive?: boolean;
|
||||
method?: string;
|
||||
mode?: RequestMode;
|
||||
redirect?: RequestRedirect;
|
||||
referrer?: string;
|
||||
referrerPolicy?: ReferrerPolicy;
|
||||
window?: any;
|
||||
}
|
||||
|
||||
interface ResponseInit {
|
||||
headers?: any;
|
||||
status?: number;
|
||||
statusText?: string;
|
||||
headers?: any;
|
||||
}
|
||||
|
||||
interface ClientQueryOptions {
|
||||
@@ -176,7 +176,7 @@ interface AudioBuffer {
|
||||
declare var AudioBuffer: {
|
||||
prototype: AudioBuffer;
|
||||
new(): AudioBuffer;
|
||||
}
|
||||
};
|
||||
|
||||
interface Blob {
|
||||
readonly size: number;
|
||||
@@ -189,7 +189,7 @@ interface Blob {
|
||||
declare var Blob: {
|
||||
prototype: Blob;
|
||||
new (blobParts?: any[], options?: BlobPropertyBag): Blob;
|
||||
}
|
||||
};
|
||||
|
||||
interface Cache {
|
||||
add(request: RequestInfo): Promise<void>;
|
||||
@@ -204,7 +204,7 @@ interface Cache {
|
||||
declare var Cache: {
|
||||
prototype: Cache;
|
||||
new(): Cache;
|
||||
}
|
||||
};
|
||||
|
||||
interface CacheStorage {
|
||||
delete(cacheName: string): Promise<boolean>;
|
||||
@@ -217,7 +217,7 @@ interface CacheStorage {
|
||||
declare var CacheStorage: {
|
||||
prototype: CacheStorage;
|
||||
new(): CacheStorage;
|
||||
}
|
||||
};
|
||||
|
||||
interface CloseEvent extends Event {
|
||||
readonly code: number;
|
||||
@@ -229,7 +229,7 @@ interface CloseEvent extends Event {
|
||||
declare var CloseEvent: {
|
||||
prototype: CloseEvent;
|
||||
new(typeArg: string, eventInitDict?: CloseEventInit): CloseEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface Console {
|
||||
assert(test?: boolean, message?: string, ...optionalParams: any[]): void;
|
||||
@@ -240,8 +240,8 @@ interface Console {
|
||||
dirxml(value: any): void;
|
||||
error(message?: any, ...optionalParams: any[]): void;
|
||||
exception(message?: string, ...optionalParams: any[]): void;
|
||||
group(groupTitle?: string): void;
|
||||
groupCollapsed(groupTitle?: string): void;
|
||||
group(groupTitle?: string, ...optionalParams: any[]): void;
|
||||
groupCollapsed(groupTitle?: string, ...optionalParams: any[]): void;
|
||||
groupEnd(): void;
|
||||
info(message?: any, ...optionalParams: any[]): void;
|
||||
log(message?: any, ...optionalParams: any[]): void;
|
||||
@@ -259,7 +259,7 @@ interface Console {
|
||||
declare var Console: {
|
||||
prototype: Console;
|
||||
new(): Console;
|
||||
}
|
||||
};
|
||||
|
||||
interface Coordinates {
|
||||
readonly accuracy: number;
|
||||
@@ -274,7 +274,7 @@ interface Coordinates {
|
||||
declare var Coordinates: {
|
||||
prototype: Coordinates;
|
||||
new(): Coordinates;
|
||||
}
|
||||
};
|
||||
|
||||
interface CryptoKey {
|
||||
readonly algorithm: KeyAlgorithm;
|
||||
@@ -286,7 +286,7 @@ interface CryptoKey {
|
||||
declare var CryptoKey: {
|
||||
prototype: CryptoKey;
|
||||
new(): CryptoKey;
|
||||
}
|
||||
};
|
||||
|
||||
interface DOMError {
|
||||
readonly name: string;
|
||||
@@ -296,7 +296,7 @@ interface DOMError {
|
||||
declare var DOMError: {
|
||||
prototype: DOMError;
|
||||
new(): DOMError;
|
||||
}
|
||||
};
|
||||
|
||||
interface DOMException {
|
||||
readonly code: number;
|
||||
@@ -316,10 +316,10 @@ interface DOMException {
|
||||
readonly INVALID_STATE_ERR: number;
|
||||
readonly NAMESPACE_ERR: number;
|
||||
readonly NETWORK_ERR: number;
|
||||
readonly NOT_FOUND_ERR: number;
|
||||
readonly NOT_SUPPORTED_ERR: number;
|
||||
readonly NO_DATA_ALLOWED_ERR: number;
|
||||
readonly NO_MODIFICATION_ALLOWED_ERR: number;
|
||||
readonly NOT_FOUND_ERR: number;
|
||||
readonly NOT_SUPPORTED_ERR: number;
|
||||
readonly PARSE_ERR: number;
|
||||
readonly QUOTA_EXCEEDED_ERR: number;
|
||||
readonly SECURITY_ERR: number;
|
||||
@@ -348,10 +348,10 @@ declare var DOMException: {
|
||||
readonly INVALID_STATE_ERR: number;
|
||||
readonly NAMESPACE_ERR: number;
|
||||
readonly NETWORK_ERR: number;
|
||||
readonly NOT_FOUND_ERR: number;
|
||||
readonly NOT_SUPPORTED_ERR: number;
|
||||
readonly NO_DATA_ALLOWED_ERR: number;
|
||||
readonly NO_MODIFICATION_ALLOWED_ERR: number;
|
||||
readonly NOT_FOUND_ERR: number;
|
||||
readonly NOT_SUPPORTED_ERR: number;
|
||||
readonly PARSE_ERR: number;
|
||||
readonly QUOTA_EXCEEDED_ERR: number;
|
||||
readonly SECURITY_ERR: number;
|
||||
@@ -362,7 +362,7 @@ declare var DOMException: {
|
||||
readonly URL_MISMATCH_ERR: number;
|
||||
readonly VALIDATION_ERR: number;
|
||||
readonly WRONG_DOCUMENT_ERR: number;
|
||||
}
|
||||
};
|
||||
|
||||
interface DOMStringList {
|
||||
readonly length: number;
|
||||
@@ -374,7 +374,7 @@ interface DOMStringList {
|
||||
declare var DOMStringList: {
|
||||
prototype: DOMStringList;
|
||||
new(): DOMStringList;
|
||||
}
|
||||
};
|
||||
|
||||
interface ErrorEvent extends Event {
|
||||
readonly colno: number;
|
||||
@@ -388,12 +388,12 @@ interface ErrorEvent extends Event {
|
||||
declare var ErrorEvent: {
|
||||
prototype: ErrorEvent;
|
||||
new(type: string, errorEventInitDict?: ErrorEventInit): ErrorEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface Event {
|
||||
readonly bubbles: boolean;
|
||||
cancelBubble: boolean;
|
||||
readonly cancelable: boolean;
|
||||
cancelBubble: boolean;
|
||||
readonly currentTarget: EventTarget;
|
||||
readonly defaultPrevented: boolean;
|
||||
readonly eventPhase: number;
|
||||
@@ -420,7 +420,7 @@ declare var Event: {
|
||||
readonly AT_TARGET: number;
|
||||
readonly BUBBLING_PHASE: number;
|
||||
readonly CAPTURING_PHASE: number;
|
||||
}
|
||||
};
|
||||
|
||||
interface EventTarget {
|
||||
addEventListener(type: string, listener?: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
@@ -431,7 +431,7 @@ interface EventTarget {
|
||||
declare var EventTarget: {
|
||||
prototype: EventTarget;
|
||||
new(): EventTarget;
|
||||
}
|
||||
};
|
||||
|
||||
interface File extends Blob {
|
||||
readonly lastModifiedDate: any;
|
||||
@@ -442,7 +442,7 @@ interface File extends Blob {
|
||||
declare var File: {
|
||||
prototype: File;
|
||||
new (parts: (ArrayBuffer | ArrayBufferView | Blob | string)[], filename: string, properties?: FilePropertyBag): File;
|
||||
}
|
||||
};
|
||||
|
||||
interface FileList {
|
||||
readonly length: number;
|
||||
@@ -453,7 +453,7 @@ interface FileList {
|
||||
declare var FileList: {
|
||||
prototype: FileList;
|
||||
new(): FileList;
|
||||
}
|
||||
};
|
||||
|
||||
interface FileReader extends EventTarget, MSBaseReader {
|
||||
readonly error: DOMError;
|
||||
@@ -468,8 +468,17 @@ interface FileReader extends EventTarget, MSBaseReader {
|
||||
declare var FileReader: {
|
||||
prototype: FileReader;
|
||||
new(): FileReader;
|
||||
};
|
||||
|
||||
interface FormData {
|
||||
append(name: string, value: string | Blob, fileName?: string): void;
|
||||
}
|
||||
|
||||
declare var FormData: {
|
||||
prototype: FormData;
|
||||
new(): FormData;
|
||||
};
|
||||
|
||||
interface Headers {
|
||||
append(name: string, value: string): void;
|
||||
delete(name: string): void;
|
||||
@@ -482,7 +491,7 @@ interface Headers {
|
||||
declare var Headers: {
|
||||
prototype: Headers;
|
||||
new(init?: any): Headers;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBCursor {
|
||||
readonly direction: IDBCursorDirection;
|
||||
@@ -506,7 +515,7 @@ declare var IDBCursor: {
|
||||
readonly NEXT_NO_DUPLICATE: string;
|
||||
readonly PREV: string;
|
||||
readonly PREV_NO_DUPLICATE: string;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBCursorWithValue extends IDBCursor {
|
||||
readonly value: any;
|
||||
@@ -515,7 +524,7 @@ interface IDBCursorWithValue extends IDBCursor {
|
||||
declare var IDBCursorWithValue: {
|
||||
prototype: IDBCursorWithValue;
|
||||
new(): IDBCursorWithValue;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBDatabaseEventMap {
|
||||
"abort": Event;
|
||||
@@ -532,7 +541,7 @@ interface IDBDatabase extends EventTarget {
|
||||
close(): void;
|
||||
createObjectStore(name: string, optionalParameters?: IDBObjectStoreParameters): IDBObjectStore;
|
||||
deleteObjectStore(name: string): void;
|
||||
transaction(storeNames: string | string[], mode?: string): IDBTransaction;
|
||||
transaction(storeNames: string | string[], mode?: IDBTransactionMode): IDBTransaction;
|
||||
addEventListener(type: "versionchange", listener: (ev: IDBVersionChangeEvent) => any, useCapture?: boolean): void;
|
||||
addEventListener<K extends keyof IDBDatabaseEventMap>(type: K, listener: (this: IDBDatabase, ev: IDBDatabaseEventMap[K]) => any, useCapture?: boolean): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
|
||||
@@ -541,7 +550,7 @@ interface IDBDatabase extends EventTarget {
|
||||
declare var IDBDatabase: {
|
||||
prototype: IDBDatabase;
|
||||
new(): IDBDatabase;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBFactory {
|
||||
cmp(first: any, second: any): number;
|
||||
@@ -552,7 +561,7 @@ interface IDBFactory {
|
||||
declare var IDBFactory: {
|
||||
prototype: IDBFactory;
|
||||
new(): IDBFactory;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBIndex {
|
||||
keyPath: string | string[];
|
||||
@@ -563,14 +572,14 @@ interface IDBIndex {
|
||||
count(key?: IDBKeyRange | IDBValidKey): IDBRequest;
|
||||
get(key: IDBKeyRange | IDBValidKey): IDBRequest;
|
||||
getKey(key: IDBKeyRange | IDBValidKey): IDBRequest;
|
||||
openCursor(range?: IDBKeyRange | IDBValidKey, direction?: string): IDBRequest;
|
||||
openKeyCursor(range?: IDBKeyRange | IDBValidKey, direction?: string): IDBRequest;
|
||||
openCursor(range?: IDBKeyRange | IDBValidKey, direction?: IDBCursorDirection): IDBRequest;
|
||||
openKeyCursor(range?: IDBKeyRange | IDBValidKey, direction?: IDBCursorDirection): IDBRequest;
|
||||
}
|
||||
|
||||
declare var IDBIndex: {
|
||||
prototype: IDBIndex;
|
||||
new(): IDBIndex;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBKeyRange {
|
||||
readonly lower: any;
|
||||
@@ -586,7 +595,7 @@ declare var IDBKeyRange: {
|
||||
lowerBound(lower: any, open?: boolean): IDBKeyRange;
|
||||
only(value: any): IDBKeyRange;
|
||||
upperBound(upper: any, open?: boolean): IDBKeyRange;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBObjectStore {
|
||||
readonly indexNames: DOMStringList;
|
||||
@@ -602,14 +611,14 @@ interface IDBObjectStore {
|
||||
deleteIndex(indexName: string): void;
|
||||
get(key: any): IDBRequest;
|
||||
index(name: string): IDBIndex;
|
||||
openCursor(range?: IDBKeyRange | IDBValidKey, direction?: string): IDBRequest;
|
||||
openCursor(range?: IDBKeyRange | IDBValidKey, direction?: IDBCursorDirection): IDBRequest;
|
||||
put(value: any, key?: IDBKeyRange | IDBValidKey): IDBRequest;
|
||||
}
|
||||
|
||||
declare var IDBObjectStore: {
|
||||
prototype: IDBObjectStore;
|
||||
new(): IDBObjectStore;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBOpenDBRequestEventMap extends IDBRequestEventMap {
|
||||
"blocked": Event;
|
||||
@@ -626,7 +635,7 @@ interface IDBOpenDBRequest extends IDBRequest {
|
||||
declare var IDBOpenDBRequest: {
|
||||
prototype: IDBOpenDBRequest;
|
||||
new(): IDBOpenDBRequest;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBRequestEventMap {
|
||||
"error": Event;
|
||||
@@ -634,7 +643,7 @@ interface IDBRequestEventMap {
|
||||
}
|
||||
|
||||
interface IDBRequest extends EventTarget {
|
||||
readonly error: DOMError;
|
||||
readonly error: DOMException;
|
||||
onerror: (this: IDBRequest, ev: Event) => any;
|
||||
onsuccess: (this: IDBRequest, ev: Event) => any;
|
||||
readonly readyState: IDBRequestReadyState;
|
||||
@@ -648,7 +657,7 @@ interface IDBRequest extends EventTarget {
|
||||
declare var IDBRequest: {
|
||||
prototype: IDBRequest;
|
||||
new(): IDBRequest;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBTransactionEventMap {
|
||||
"abort": Event;
|
||||
@@ -658,7 +667,7 @@ interface IDBTransactionEventMap {
|
||||
|
||||
interface IDBTransaction extends EventTarget {
|
||||
readonly db: IDBDatabase;
|
||||
readonly error: DOMError;
|
||||
readonly error: DOMException;
|
||||
readonly mode: IDBTransactionMode;
|
||||
onabort: (this: IDBTransaction, ev: Event) => any;
|
||||
oncomplete: (this: IDBTransaction, ev: Event) => any;
|
||||
@@ -678,7 +687,7 @@ declare var IDBTransaction: {
|
||||
readonly READ_ONLY: string;
|
||||
readonly READ_WRITE: string;
|
||||
readonly VERSION_CHANGE: string;
|
||||
}
|
||||
};
|
||||
|
||||
interface IDBVersionChangeEvent extends Event {
|
||||
readonly newVersion: number | null;
|
||||
@@ -688,7 +697,7 @@ interface IDBVersionChangeEvent extends Event {
|
||||
declare var IDBVersionChangeEvent: {
|
||||
prototype: IDBVersionChangeEvent;
|
||||
new(): IDBVersionChangeEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface ImageData {
|
||||
data: Uint8ClampedArray;
|
||||
@@ -700,7 +709,7 @@ declare var ImageData: {
|
||||
prototype: ImageData;
|
||||
new(width: number, height: number): ImageData;
|
||||
new(array: Uint8ClampedArray, width: number, height: number): ImageData;
|
||||
}
|
||||
};
|
||||
|
||||
interface MessageChannel {
|
||||
readonly port1: MessagePort;
|
||||
@@ -710,7 +719,7 @@ interface MessageChannel {
|
||||
declare var MessageChannel: {
|
||||
prototype: MessageChannel;
|
||||
new(): MessageChannel;
|
||||
}
|
||||
};
|
||||
|
||||
interface MessageEvent extends Event {
|
||||
readonly data: any;
|
||||
@@ -723,7 +732,7 @@ interface MessageEvent extends Event {
|
||||
declare var MessageEvent: {
|
||||
prototype: MessageEvent;
|
||||
new(type: string, eventInitDict?: MessageEventInit): MessageEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface MessagePortEventMap {
|
||||
"message": MessageEvent;
|
||||
@@ -741,7 +750,7 @@ interface MessagePort extends EventTarget {
|
||||
declare var MessagePort: {
|
||||
prototype: MessagePort;
|
||||
new(): MessagePort;
|
||||
}
|
||||
};
|
||||
|
||||
interface NotificationEventMap {
|
||||
"click": Event;
|
||||
@@ -771,7 +780,7 @@ declare var Notification: {
|
||||
prototype: Notification;
|
||||
new(title: string, options?: NotificationOptions): Notification;
|
||||
requestPermission(callback?: NotificationPermissionCallback): Promise<NotificationPermission>;
|
||||
}
|
||||
};
|
||||
|
||||
interface Performance {
|
||||
readonly navigation: PerformanceNavigation;
|
||||
@@ -794,7 +803,7 @@ interface Performance {
|
||||
declare var Performance: {
|
||||
prototype: Performance;
|
||||
new(): Performance;
|
||||
}
|
||||
};
|
||||
|
||||
interface PerformanceNavigation {
|
||||
readonly redirectCount: number;
|
||||
@@ -813,18 +822,18 @@ declare var PerformanceNavigation: {
|
||||
readonly TYPE_NAVIGATE: number;
|
||||
readonly TYPE_RELOAD: number;
|
||||
readonly TYPE_RESERVED: number;
|
||||
}
|
||||
};
|
||||
|
||||
interface PerformanceTiming {
|
||||
readonly connectEnd: number;
|
||||
readonly connectStart: number;
|
||||
readonly domainLookupEnd: number;
|
||||
readonly domainLookupStart: number;
|
||||
readonly domComplete: number;
|
||||
readonly domContentLoadedEventEnd: number;
|
||||
readonly domContentLoadedEventStart: number;
|
||||
readonly domInteractive: number;
|
||||
readonly domLoading: number;
|
||||
readonly domainLookupEnd: number;
|
||||
readonly domainLookupStart: number;
|
||||
readonly fetchStart: number;
|
||||
readonly loadEventEnd: number;
|
||||
readonly loadEventStart: number;
|
||||
@@ -844,7 +853,7 @@ interface PerformanceTiming {
|
||||
declare var PerformanceTiming: {
|
||||
prototype: PerformanceTiming;
|
||||
new(): PerformanceTiming;
|
||||
}
|
||||
};
|
||||
|
||||
interface Position {
|
||||
readonly coords: Coordinates;
|
||||
@@ -854,7 +863,7 @@ interface Position {
|
||||
declare var Position: {
|
||||
prototype: Position;
|
||||
new(): Position;
|
||||
}
|
||||
};
|
||||
|
||||
interface PositionError {
|
||||
readonly code: number;
|
||||
@@ -871,7 +880,7 @@ declare var PositionError: {
|
||||
readonly PERMISSION_DENIED: number;
|
||||
readonly POSITION_UNAVAILABLE: number;
|
||||
readonly TIMEOUT: number;
|
||||
}
|
||||
};
|
||||
|
||||
interface ProgressEvent extends Event {
|
||||
readonly lengthComputable: boolean;
|
||||
@@ -883,7 +892,7 @@ interface ProgressEvent extends Event {
|
||||
declare var ProgressEvent: {
|
||||
prototype: ProgressEvent;
|
||||
new(type: string, eventInitDict?: ProgressEventInit): ProgressEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface PushManager {
|
||||
getSubscription(): Promise<PushSubscription>;
|
||||
@@ -894,7 +903,7 @@ interface PushManager {
|
||||
declare var PushManager: {
|
||||
prototype: PushManager;
|
||||
new(): PushManager;
|
||||
}
|
||||
};
|
||||
|
||||
interface PushSubscription {
|
||||
readonly endpoint: USVString;
|
||||
@@ -907,7 +916,7 @@ interface PushSubscription {
|
||||
declare var PushSubscription: {
|
||||
prototype: PushSubscription;
|
||||
new(): PushSubscription;
|
||||
}
|
||||
};
|
||||
|
||||
interface PushSubscriptionOptions {
|
||||
readonly applicationServerKey: ArrayBuffer | null;
|
||||
@@ -917,7 +926,7 @@ interface PushSubscriptionOptions {
|
||||
declare var PushSubscriptionOptions: {
|
||||
prototype: PushSubscriptionOptions;
|
||||
new(): PushSubscriptionOptions;
|
||||
}
|
||||
};
|
||||
|
||||
interface ReadableStream {
|
||||
readonly locked: boolean;
|
||||
@@ -928,7 +937,7 @@ interface ReadableStream {
|
||||
declare var ReadableStream: {
|
||||
prototype: ReadableStream;
|
||||
new(): ReadableStream;
|
||||
}
|
||||
};
|
||||
|
||||
interface ReadableStreamReader {
|
||||
cancel(): Promise<void>;
|
||||
@@ -939,7 +948,7 @@ interface ReadableStreamReader {
|
||||
declare var ReadableStreamReader: {
|
||||
prototype: ReadableStreamReader;
|
||||
new(): ReadableStreamReader;
|
||||
}
|
||||
};
|
||||
|
||||
interface Request extends Object, Body {
|
||||
readonly cache: RequestCache;
|
||||
@@ -961,7 +970,7 @@ interface Request extends Object, Body {
|
||||
declare var Request: {
|
||||
prototype: Request;
|
||||
new(input: Request | string, init?: RequestInit): Request;
|
||||
}
|
||||
};
|
||||
|
||||
interface Response extends Object, Body {
|
||||
readonly body: ReadableStream | null;
|
||||
@@ -977,7 +986,9 @@ interface Response extends Object, Body {
|
||||
declare var Response: {
|
||||
prototype: Response;
|
||||
new(body?: any, init?: ResponseInit): Response;
|
||||
}
|
||||
error: () => Response;
|
||||
redirect: (url: string, status?: number) => Response;
|
||||
};
|
||||
|
||||
interface ServiceWorkerEventMap extends AbstractWorkerEventMap {
|
||||
"statechange": Event;
|
||||
@@ -995,7 +1006,7 @@ interface ServiceWorker extends EventTarget, AbstractWorker {
|
||||
declare var ServiceWorker: {
|
||||
prototype: ServiceWorker;
|
||||
new(): ServiceWorker;
|
||||
}
|
||||
};
|
||||
|
||||
interface ServiceWorkerRegistrationEventMap {
|
||||
"updatefound": Event;
|
||||
@@ -1020,7 +1031,7 @@ interface ServiceWorkerRegistration extends EventTarget {
|
||||
declare var ServiceWorkerRegistration: {
|
||||
prototype: ServiceWorkerRegistration;
|
||||
new(): ServiceWorkerRegistration;
|
||||
}
|
||||
};
|
||||
|
||||
interface SyncManager {
|
||||
getTags(): any;
|
||||
@@ -1030,7 +1041,7 @@ interface SyncManager {
|
||||
declare var SyncManager: {
|
||||
prototype: SyncManager;
|
||||
new(): SyncManager;
|
||||
}
|
||||
};
|
||||
|
||||
interface URL {
|
||||
hash: string;
|
||||
@@ -1053,7 +1064,7 @@ declare var URL: {
|
||||
new(url: string, base?: string): URL;
|
||||
createObjectURL(object: any, options?: ObjectURLOptions): string;
|
||||
revokeObjectURL(url: string): void;
|
||||
}
|
||||
};
|
||||
|
||||
interface WebSocketEventMap {
|
||||
"close": CloseEvent;
|
||||
@@ -1090,7 +1101,7 @@ declare var WebSocket: {
|
||||
readonly CLOSING: number;
|
||||
readonly CONNECTING: number;
|
||||
readonly OPEN: number;
|
||||
}
|
||||
};
|
||||
|
||||
interface WorkerEventMap extends AbstractWorkerEventMap {
|
||||
"message": MessageEvent;
|
||||
@@ -1107,7 +1118,7 @@ interface Worker extends EventTarget, AbstractWorker {
|
||||
declare var Worker: {
|
||||
prototype: Worker;
|
||||
new(stringUrl: string): Worker;
|
||||
}
|
||||
};
|
||||
|
||||
interface XMLHttpRequestEventMap extends XMLHttpRequestEventTargetEventMap {
|
||||
"readystatechange": Event;
|
||||
@@ -1153,7 +1164,7 @@ declare var XMLHttpRequest: {
|
||||
readonly LOADING: number;
|
||||
readonly OPENED: number;
|
||||
readonly UNSENT: number;
|
||||
}
|
||||
};
|
||||
|
||||
interface XMLHttpRequestUpload extends EventTarget, XMLHttpRequestEventTarget {
|
||||
addEventListener<K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, useCapture?: boolean): void;
|
||||
@@ -1163,7 +1174,7 @@ interface XMLHttpRequestUpload extends EventTarget, XMLHttpRequestEventTarget {
|
||||
declare var XMLHttpRequestUpload: {
|
||||
prototype: XMLHttpRequestUpload;
|
||||
new(): XMLHttpRequestUpload;
|
||||
}
|
||||
};
|
||||
|
||||
interface AbstractWorkerEventMap {
|
||||
"error": ErrorEvent;
|
||||
@@ -1278,7 +1289,7 @@ interface Client {
|
||||
declare var Client: {
|
||||
prototype: Client;
|
||||
new(): Client;
|
||||
}
|
||||
};
|
||||
|
||||
interface Clients {
|
||||
claim(): Promise<void>;
|
||||
@@ -1290,7 +1301,7 @@ interface Clients {
|
||||
declare var Clients: {
|
||||
prototype: Clients;
|
||||
new(): Clients;
|
||||
}
|
||||
};
|
||||
|
||||
interface DedicatedWorkerGlobalScopeEventMap extends WorkerGlobalScopeEventMap {
|
||||
"message": MessageEvent;
|
||||
@@ -1307,7 +1318,7 @@ interface DedicatedWorkerGlobalScope extends WorkerGlobalScope {
|
||||
declare var DedicatedWorkerGlobalScope: {
|
||||
prototype: DedicatedWorkerGlobalScope;
|
||||
new(): DedicatedWorkerGlobalScope;
|
||||
}
|
||||
};
|
||||
|
||||
interface ExtendableEvent extends Event {
|
||||
waitUntil(f: Promise<any>): void;
|
||||
@@ -1316,7 +1327,7 @@ interface ExtendableEvent extends Event {
|
||||
declare var ExtendableEvent: {
|
||||
prototype: ExtendableEvent;
|
||||
new(type: string, eventInitDict?: ExtendableEventInit): ExtendableEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface ExtendableMessageEvent extends ExtendableEvent {
|
||||
readonly data: any;
|
||||
@@ -1329,7 +1340,7 @@ interface ExtendableMessageEvent extends ExtendableEvent {
|
||||
declare var ExtendableMessageEvent: {
|
||||
prototype: ExtendableMessageEvent;
|
||||
new(type: string, eventInitDict?: ExtendableMessageEventInit): ExtendableMessageEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface FetchEvent extends ExtendableEvent {
|
||||
readonly clientId: string | null;
|
||||
@@ -1341,7 +1352,7 @@ interface FetchEvent extends ExtendableEvent {
|
||||
declare var FetchEvent: {
|
||||
prototype: FetchEvent;
|
||||
new(type: string, eventInitDict: FetchEventInit): FetchEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface FileReaderSync {
|
||||
readAsArrayBuffer(blob: Blob): any;
|
||||
@@ -1353,7 +1364,7 @@ interface FileReaderSync {
|
||||
declare var FileReaderSync: {
|
||||
prototype: FileReaderSync;
|
||||
new(): FileReaderSync;
|
||||
}
|
||||
};
|
||||
|
||||
interface NotificationEvent extends ExtendableEvent {
|
||||
readonly action: string;
|
||||
@@ -1363,7 +1374,7 @@ interface NotificationEvent extends ExtendableEvent {
|
||||
declare var NotificationEvent: {
|
||||
prototype: NotificationEvent;
|
||||
new(type: string, eventInitDict: NotificationEventInit): NotificationEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface PushEvent extends ExtendableEvent {
|
||||
readonly data: PushMessageData | null;
|
||||
@@ -1372,7 +1383,7 @@ interface PushEvent extends ExtendableEvent {
|
||||
declare var PushEvent: {
|
||||
prototype: PushEvent;
|
||||
new(type: string, eventInitDict?: PushEventInit): PushEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface PushMessageData {
|
||||
arrayBuffer(): ArrayBuffer;
|
||||
@@ -1384,7 +1395,7 @@ interface PushMessageData {
|
||||
declare var PushMessageData: {
|
||||
prototype: PushMessageData;
|
||||
new(): PushMessageData;
|
||||
}
|
||||
};
|
||||
|
||||
interface ServiceWorkerGlobalScopeEventMap extends WorkerGlobalScopeEventMap {
|
||||
"activate": ExtendableEvent;
|
||||
@@ -1418,7 +1429,7 @@ interface ServiceWorkerGlobalScope extends WorkerGlobalScope {
|
||||
declare var ServiceWorkerGlobalScope: {
|
||||
prototype: ServiceWorkerGlobalScope;
|
||||
new(): ServiceWorkerGlobalScope;
|
||||
}
|
||||
};
|
||||
|
||||
interface SyncEvent extends ExtendableEvent {
|
||||
readonly lastChance: boolean;
|
||||
@@ -1428,7 +1439,7 @@ interface SyncEvent extends ExtendableEvent {
|
||||
declare var SyncEvent: {
|
||||
prototype: SyncEvent;
|
||||
new(type: string, init: SyncEventInit): SyncEvent;
|
||||
}
|
||||
};
|
||||
|
||||
interface WindowClient extends Client {
|
||||
readonly focused: boolean;
|
||||
@@ -1440,7 +1451,7 @@ interface WindowClient extends Client {
|
||||
declare var WindowClient: {
|
||||
prototype: WindowClient;
|
||||
new(): WindowClient;
|
||||
}
|
||||
};
|
||||
|
||||
interface WorkerGlobalScopeEventMap {
|
||||
"error": ErrorEvent;
|
||||
@@ -1463,7 +1474,7 @@ interface WorkerGlobalScope extends EventTarget, WorkerUtils, WindowConsole, Glo
|
||||
declare var WorkerGlobalScope: {
|
||||
prototype: WorkerGlobalScope;
|
||||
new(): WorkerGlobalScope;
|
||||
}
|
||||
};
|
||||
|
||||
interface WorkerLocation {
|
||||
readonly hash: string;
|
||||
@@ -1481,7 +1492,7 @@ interface WorkerLocation {
|
||||
declare var WorkerLocation: {
|
||||
prototype: WorkerLocation;
|
||||
new(): WorkerLocation;
|
||||
}
|
||||
};
|
||||
|
||||
interface WorkerNavigator extends Object, NavigatorID, NavigatorOnLine, NavigatorBeacon, NavigatorConcurrentHardware {
|
||||
readonly hardwareConcurrency: number;
|
||||
@@ -1490,7 +1501,7 @@ interface WorkerNavigator extends Object, NavigatorID, NavigatorOnLine, Navigato
|
||||
declare var WorkerNavigator: {
|
||||
prototype: WorkerNavigator;
|
||||
new(): WorkerNavigator;
|
||||
}
|
||||
};
|
||||
|
||||
interface WorkerUtils extends Object, WindowBase64 {
|
||||
readonly indexedDB: IDBFactory;
|
||||
@@ -1533,38 +1544,38 @@ interface ImageBitmap {
|
||||
|
||||
interface URLSearchParams {
|
||||
/**
|
||||
* Appends a specified key/value pair as a new search parameter.
|
||||
*/
|
||||
* Appends a specified key/value pair as a new search parameter.
|
||||
*/
|
||||
append(name: string, value: string): void;
|
||||
/**
|
||||
* Deletes the given search parameter, and its associated value, from the list of all search parameters.
|
||||
*/
|
||||
* Deletes the given search parameter, and its associated value, from the list of all search parameters.
|
||||
*/
|
||||
delete(name: string): void;
|
||||
/**
|
||||
* Returns the first value associated to the given search parameter.
|
||||
*/
|
||||
* Returns the first value associated to the given search parameter.
|
||||
*/
|
||||
get(name: string): string | null;
|
||||
/**
|
||||
* Returns all the values association with a given search parameter.
|
||||
*/
|
||||
* Returns all the values association with a given search parameter.
|
||||
*/
|
||||
getAll(name: string): string[];
|
||||
/**
|
||||
* Returns a Boolean indicating if such a search parameter exists.
|
||||
*/
|
||||
* Returns a Boolean indicating if such a search parameter exists.
|
||||
*/
|
||||
has(name: string): boolean;
|
||||
/**
|
||||
* Sets the value associated to a given search parameter to the given value. If there were several values, delete the others.
|
||||
*/
|
||||
* Sets the value associated to a given search parameter to the given value. If there were several values, delete the others.
|
||||
*/
|
||||
set(name: string, value: string): void;
|
||||
}
|
||||
|
||||
declare var URLSearchParams: {
|
||||
prototype: URLSearchParams;
|
||||
/**
|
||||
* Constructor returning a URLSearchParams object.
|
||||
*/
|
||||
* Constructor returning a URLSearchParams object.
|
||||
*/
|
||||
new (init?: string | URLSearchParams): URLSearchParams;
|
||||
}
|
||||
};
|
||||
|
||||
interface BlobPropertyBag {
|
||||
type?: string;
|
||||
@@ -1771,8 +1782,23 @@ interface AddEventListenerOptions extends EventListenerOptions {
|
||||
|
||||
declare type EventListenerOrEventListenerObject = EventListener | EventListenerObject;
|
||||
|
||||
interface DecodeErrorCallback {
|
||||
(error: DOMException): void;
|
||||
}
|
||||
interface DecodeSuccessCallback {
|
||||
(decodedData: AudioBuffer): void;
|
||||
}
|
||||
interface ErrorEventHandler {
|
||||
(message: string, filename?: string, lineno?: number, colno?: number, error?:Error): void;
|
||||
(message: string, filename?: string, lineno?: number, colno?: number, error?: Error): void;
|
||||
}
|
||||
interface ForEachCallback {
|
||||
(keyId: any, status: MediaKeyStatus): void;
|
||||
}
|
||||
interface FunctionStringCallback {
|
||||
(data: string): void;
|
||||
}
|
||||
interface NotificationPermissionCallback {
|
||||
(permission: NotificationPermission): void;
|
||||
}
|
||||
interface PositionCallback {
|
||||
(position: Position): void;
|
||||
@@ -1780,21 +1806,6 @@ interface PositionCallback {
|
||||
interface PositionErrorCallback {
|
||||
(error: PositionError): void;
|
||||
}
|
||||
interface DecodeSuccessCallback {
|
||||
(decodedData: AudioBuffer): void;
|
||||
}
|
||||
interface DecodeErrorCallback {
|
||||
(error: DOMException): void;
|
||||
}
|
||||
interface FunctionStringCallback {
|
||||
(data: string): void;
|
||||
}
|
||||
interface ForEachCallback {
|
||||
(keyId: any, status: MediaKeyStatus): void;
|
||||
}
|
||||
interface NotificationPermissionCallback {
|
||||
(permission: NotificationPermission): void;
|
||||
}
|
||||
declare var onmessage: (this: DedicatedWorkerGlobalScope, ev: MessageEvent) => any;
|
||||
declare function close(): void;
|
||||
declare function postMessage(message: any, transfer?: any[]): void;
|
||||
|
||||
Vendored
+180
-95
@@ -2,51 +2,53 @@
|
||||
* Declaration module describing the TypeScript Server protocol
|
||||
*/
|
||||
declare namespace ts.server.protocol {
|
||||
namespace CommandTypes {
|
||||
type Brace = "brace";
|
||||
type BraceCompletion = "braceCompletion";
|
||||
type Change = "change";
|
||||
type Close = "close";
|
||||
type Completions = "completions";
|
||||
type CompletionDetails = "completionEntryDetails";
|
||||
type CompileOnSaveAffectedFileList = "compileOnSaveAffectedFileList";
|
||||
type CompileOnSaveEmitFile = "compileOnSaveEmitFile";
|
||||
type Configure = "configure";
|
||||
type Definition = "definition";
|
||||
type Implementation = "implementation";
|
||||
type Exit = "exit";
|
||||
type Format = "format";
|
||||
type Formatonkey = "formatonkey";
|
||||
type Geterr = "geterr";
|
||||
type GeterrForProject = "geterrForProject";
|
||||
type SemanticDiagnosticsSync = "semanticDiagnosticsSync";
|
||||
type SyntacticDiagnosticsSync = "syntacticDiagnosticsSync";
|
||||
type NavBar = "navbar";
|
||||
type Navto = "navto";
|
||||
type NavTree = "navtree";
|
||||
type NavTreeFull = "navtree-full";
|
||||
type Occurrences = "occurrences";
|
||||
type DocumentHighlights = "documentHighlights";
|
||||
type Open = "open";
|
||||
type Quickinfo = "quickinfo";
|
||||
type References = "references";
|
||||
type Reload = "reload";
|
||||
type Rename = "rename";
|
||||
type Saveto = "saveto";
|
||||
type SignatureHelp = "signatureHelp";
|
||||
type TypeDefinition = "typeDefinition";
|
||||
type ProjectInfo = "projectInfo";
|
||||
type ReloadProjects = "reloadProjects";
|
||||
type Unknown = "unknown";
|
||||
type OpenExternalProject = "openExternalProject";
|
||||
type OpenExternalProjects = "openExternalProjects";
|
||||
type CloseExternalProject = "closeExternalProject";
|
||||
type TodoComments = "todoComments";
|
||||
type Indentation = "indentation";
|
||||
type DocCommentTemplate = "docCommentTemplate";
|
||||
type CompilerOptionsForInferredProjects = "compilerOptionsForInferredProjects";
|
||||
type GetCodeFixes = "getCodeFixes";
|
||||
type GetSupportedCodeFixes = "getSupportedCodeFixes";
|
||||
const enum CommandTypes {
|
||||
Brace = "brace",
|
||||
BraceCompletion = "braceCompletion",
|
||||
Change = "change",
|
||||
Close = "close",
|
||||
Completions = "completions",
|
||||
CompletionDetails = "completionEntryDetails",
|
||||
CompileOnSaveAffectedFileList = "compileOnSaveAffectedFileList",
|
||||
CompileOnSaveEmitFile = "compileOnSaveEmitFile",
|
||||
Configure = "configure",
|
||||
Definition = "definition",
|
||||
Implementation = "implementation",
|
||||
Exit = "exit",
|
||||
Format = "format",
|
||||
Formatonkey = "formatonkey",
|
||||
Geterr = "geterr",
|
||||
GeterrForProject = "geterrForProject",
|
||||
SemanticDiagnosticsSync = "semanticDiagnosticsSync",
|
||||
SyntacticDiagnosticsSync = "syntacticDiagnosticsSync",
|
||||
NavBar = "navbar",
|
||||
Navto = "navto",
|
||||
NavTree = "navtree",
|
||||
NavTreeFull = "navtree-full",
|
||||
Occurrences = "occurrences",
|
||||
DocumentHighlights = "documentHighlights",
|
||||
Open = "open",
|
||||
Quickinfo = "quickinfo",
|
||||
References = "references",
|
||||
Reload = "reload",
|
||||
Rename = "rename",
|
||||
Saveto = "saveto",
|
||||
SignatureHelp = "signatureHelp",
|
||||
TypeDefinition = "typeDefinition",
|
||||
ProjectInfo = "projectInfo",
|
||||
ReloadProjects = "reloadProjects",
|
||||
Unknown = "unknown",
|
||||
OpenExternalProject = "openExternalProject",
|
||||
OpenExternalProjects = "openExternalProjects",
|
||||
CloseExternalProject = "closeExternalProject",
|
||||
TodoComments = "todoComments",
|
||||
Indentation = "indentation",
|
||||
DocCommentTemplate = "docCommentTemplate",
|
||||
CompilerOptionsForInferredProjects = "compilerOptionsForInferredProjects",
|
||||
GetCodeFixes = "getCodeFixes",
|
||||
GetSupportedCodeFixes = "getSupportedCodeFixes",
|
||||
GetApplicableRefactors = "getApplicableRefactors",
|
||||
GetEditsForRefactor = "getEditsForRefactor",
|
||||
}
|
||||
/**
|
||||
* A TypeScript Server message
|
||||
@@ -287,6 +289,85 @@ declare namespace ts.server.protocol {
|
||||
*/
|
||||
offset: number;
|
||||
}
|
||||
type FileLocationOrRangeRequestArgs = FileLocationRequestArgs | FileRangeRequestArgs;
|
||||
/**
|
||||
* Request refactorings at a given position or selection area.
|
||||
*/
|
||||
interface GetApplicableRefactorsRequest extends Request {
|
||||
command: CommandTypes.GetApplicableRefactors;
|
||||
arguments: GetApplicableRefactorsRequestArgs;
|
||||
}
|
||||
type GetApplicableRefactorsRequestArgs = FileLocationOrRangeRequestArgs;
|
||||
/**
|
||||
* Response is a list of available refactorings.
|
||||
* Each refactoring exposes one or more "Actions"; a user selects one action to invoke a refactoring
|
||||
*/
|
||||
interface GetApplicableRefactorsResponse extends Response {
|
||||
body?: ApplicableRefactorInfo[];
|
||||
}
|
||||
/**
|
||||
* A set of one or more available refactoring actions, grouped under a parent refactoring.
|
||||
*/
|
||||
interface ApplicableRefactorInfo {
|
||||
/**
|
||||
* The programmatic name of the refactoring
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* A description of this refactoring category to show to the user.
|
||||
* If the refactoring gets inlined (see below), this text will not be visible.
|
||||
*/
|
||||
description: string;
|
||||
/**
|
||||
* Inlineable refactorings can have their actions hoisted out to the top level
|
||||
* of a context menu. Non-inlineanable refactorings should always be shown inside
|
||||
* their parent grouping.
|
||||
*
|
||||
* If not specified, this value is assumed to be 'true'
|
||||
*/
|
||||
inlineable?: boolean;
|
||||
actions: RefactorActionInfo[];
|
||||
}
|
||||
/**
|
||||
* Represents a single refactoring action - for example, the "Extract Method..." refactor might
|
||||
* offer several actions, each corresponding to a surround class or closure to extract into.
|
||||
*/
|
||||
type RefactorActionInfo = {
|
||||
/**
|
||||
* The programmatic name of the refactoring action
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* A description of this refactoring action to show to the user.
|
||||
* If the parent refactoring is inlined away, this will be the only text shown,
|
||||
* so this description should make sense by itself if the parent is inlineable=true
|
||||
*/
|
||||
description: string;
|
||||
};
|
||||
interface GetEditsForRefactorRequest extends Request {
|
||||
command: CommandTypes.GetEditsForRefactor;
|
||||
arguments: GetEditsForRefactorRequestArgs;
|
||||
}
|
||||
/**
|
||||
* Request the edits that a particular refactoring action produces.
|
||||
* Callers must specify the name of the refactor and the name of the action.
|
||||
*/
|
||||
type GetEditsForRefactorRequestArgs = FileLocationOrRangeRequestArgs & {
|
||||
refactor: string;
|
||||
action: string;
|
||||
};
|
||||
interface GetEditsForRefactorResponse extends Response {
|
||||
body?: RefactorEditInfo;
|
||||
}
|
||||
type RefactorEditInfo = {
|
||||
edits: FileCodeEdits[];
|
||||
/**
|
||||
* An optional location where the editor should start a rename operation once
|
||||
* the refactoring edits have been applied
|
||||
*/
|
||||
renameLocation?: Location;
|
||||
renameFilename?: string;
|
||||
};
|
||||
/**
|
||||
* Request for the available codefixes at a specific position.
|
||||
*/
|
||||
@@ -294,10 +375,7 @@ declare namespace ts.server.protocol {
|
||||
command: CommandTypes.GetCodeFixes;
|
||||
arguments: CodeFixRequestArgs;
|
||||
}
|
||||
/**
|
||||
* Instances of this interface specify errorcodes on a specific location in a sourcefile.
|
||||
*/
|
||||
interface CodeFixRequestArgs extends FileRequestArgs {
|
||||
interface FileRangeRequestArgs extends FileRequestArgs {
|
||||
/**
|
||||
* The line number for the request (1-based).
|
||||
*/
|
||||
@@ -314,6 +392,11 @@ declare namespace ts.server.protocol {
|
||||
* The character offset (on the line) for the request (1-based).
|
||||
*/
|
||||
endOffset: number;
|
||||
}
|
||||
/**
|
||||
* Instances of this interface specify errorcodes on a specific location in a sourcefile.
|
||||
*/
|
||||
interface CodeFixRequestArgs extends FileRangeRequestArgs {
|
||||
/**
|
||||
* Errorcodes we want to get the fixes for.
|
||||
*/
|
||||
@@ -394,7 +477,7 @@ declare namespace ts.server.protocol {
|
||||
command: CommandTypes.Implementation;
|
||||
}
|
||||
/**
|
||||
* Location in source code expressed as (one-based) line and character offset.
|
||||
* Location in source code expressed as (one-based) line and (one-based) column offset.
|
||||
*/
|
||||
interface Location {
|
||||
line: number;
|
||||
@@ -488,10 +571,9 @@ declare namespace ts.server.protocol {
|
||||
}
|
||||
/**
|
||||
* Span augmented with extra information that denotes the kind of the highlighting to be used for span.
|
||||
* Kind is taken from HighlightSpanKind type.
|
||||
*/
|
||||
interface HighlightSpan extends TextSpan {
|
||||
kind: string;
|
||||
kind: HighlightSpanKind;
|
||||
}
|
||||
/**
|
||||
* Represents a set of highligh spans for a give name
|
||||
@@ -609,7 +691,7 @@ declare namespace ts.server.protocol {
|
||||
/**
|
||||
* The items's kind (such as 'className' or 'parameterName' or plain 'text').
|
||||
*/
|
||||
kind: string;
|
||||
kind: ScriptElementKind;
|
||||
/**
|
||||
* Optional modifiers for the kind (such as 'public').
|
||||
*/
|
||||
@@ -957,7 +1039,7 @@ declare namespace ts.server.protocol {
|
||||
/**
|
||||
* The symbol's kind (such as 'className' or 'parameterName' or plain 'text').
|
||||
*/
|
||||
kind: string;
|
||||
kind: ScriptElementKind;
|
||||
/**
|
||||
* Optional modifiers for the kind (such as 'public').
|
||||
*/
|
||||
@@ -1143,7 +1225,7 @@ declare namespace ts.server.protocol {
|
||||
/**
|
||||
* The symbol's kind (such as 'className' or 'parameterName').
|
||||
*/
|
||||
kind: string;
|
||||
kind: ScriptElementKind;
|
||||
/**
|
||||
* Optional modifiers for the kind (such as 'public').
|
||||
*/
|
||||
@@ -1170,7 +1252,7 @@ declare namespace ts.server.protocol {
|
||||
/**
|
||||
* The symbol's kind (such as 'className' or 'parameterName').
|
||||
*/
|
||||
kind: string;
|
||||
kind: ScriptElementKind;
|
||||
/**
|
||||
* Optional modifiers for the kind (such as 'public').
|
||||
*/
|
||||
@@ -1417,6 +1499,12 @@ declare namespace ts.server.protocol {
|
||||
*/
|
||||
source?: string;
|
||||
}
|
||||
interface DiagnosticWithFileName extends Diagnostic {
|
||||
/**
|
||||
* Name of the file the diagnostic is in
|
||||
*/
|
||||
fileName: string;
|
||||
}
|
||||
interface DiagnosticEventBody {
|
||||
/**
|
||||
* The file for which diagnostic information is reported.
|
||||
@@ -1446,7 +1534,7 @@ declare namespace ts.server.protocol {
|
||||
/**
|
||||
* An arry of diagnostic information items for the found config file.
|
||||
*/
|
||||
diagnostics: Diagnostic[];
|
||||
diagnostics: DiagnosticWithFileName[];
|
||||
}
|
||||
/**
|
||||
* Event message for "configFileDiag" event type.
|
||||
@@ -1563,7 +1651,7 @@ declare namespace ts.server.protocol {
|
||||
/**
|
||||
* The symbol's kind (such as 'className' or 'parameterName').
|
||||
*/
|
||||
kind: string;
|
||||
kind: ScriptElementKind;
|
||||
/**
|
||||
* exact, substring, or prefix.
|
||||
*/
|
||||
@@ -1596,7 +1684,7 @@ declare namespace ts.server.protocol {
|
||||
/**
|
||||
* Kind of symbol's container symbol (if any).
|
||||
*/
|
||||
containerKind?: string;
|
||||
containerKind?: ScriptElementKind;
|
||||
}
|
||||
/**
|
||||
* Navto response message. Body is an array of navto items. Each
|
||||
@@ -1660,7 +1748,7 @@ declare namespace ts.server.protocol {
|
||||
/**
|
||||
* The symbol's kind (such as 'className' or 'parameterName').
|
||||
*/
|
||||
kind: string;
|
||||
kind: ScriptElementKind;
|
||||
/**
|
||||
* Optional modifiers for the kind (such as 'public').
|
||||
*/
|
||||
@@ -1681,7 +1769,7 @@ declare namespace ts.server.protocol {
|
||||
/** protocol.NavigationTree is identical to ts.NavigationTree, except using protocol.TextSpan instead of ts.TextSpan */
|
||||
interface NavigationTree {
|
||||
text: string;
|
||||
kind: string;
|
||||
kind: ScriptElementKind;
|
||||
kindModifiers: string;
|
||||
spans: TextSpan[];
|
||||
childItems?: NavigationTree[];
|
||||
@@ -1756,12 +1844,11 @@ declare namespace ts.server.protocol {
|
||||
interface NavTreeResponse extends Response {
|
||||
body?: NavigationTree;
|
||||
}
|
||||
namespace IndentStyle {
|
||||
type None = "None";
|
||||
type Block = "Block";
|
||||
type Smart = "Smart";
|
||||
const enum IndentStyle {
|
||||
None = "None",
|
||||
Block = "Block",
|
||||
Smart = "Smart",
|
||||
}
|
||||
type IndentStyle = IndentStyle.None | IndentStyle.Block | IndentStyle.Smart;
|
||||
interface EditorSettings {
|
||||
baseIndentSize?: number;
|
||||
indentSize?: number;
|
||||
@@ -1782,6 +1869,7 @@ declare namespace ts.server.protocol {
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces?: boolean;
|
||||
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces?: boolean;
|
||||
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean;
|
||||
insertSpaceAfterTypeAssertion?: boolean;
|
||||
insertSpaceBeforeFunctionParenthesis?: boolean;
|
||||
placeOpenBraceOnNewLineForFunctions?: boolean;
|
||||
placeOpenBraceOnNewLineForControlBlocks?: boolean;
|
||||
@@ -1854,40 +1942,35 @@ declare namespace ts.server.protocol {
|
||||
typeRoots?: string[];
|
||||
[option: string]: CompilerOptionsValue | undefined;
|
||||
}
|
||||
namespace JsxEmit {
|
||||
type None = "None";
|
||||
type Preserve = "Preserve";
|
||||
type ReactNative = "ReactNative";
|
||||
type React = "React";
|
||||
const enum JsxEmit {
|
||||
None = "None",
|
||||
Preserve = "Preserve",
|
||||
ReactNative = "ReactNative",
|
||||
React = "React",
|
||||
}
|
||||
type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React | JsxEmit.ReactNative;
|
||||
namespace ModuleKind {
|
||||
type None = "None";
|
||||
type CommonJS = "CommonJS";
|
||||
type AMD = "AMD";
|
||||
type UMD = "UMD";
|
||||
type System = "System";
|
||||
type ES6 = "ES6";
|
||||
type ES2015 = "ES2015";
|
||||
const enum ModuleKind {
|
||||
None = "None",
|
||||
CommonJS = "CommonJS",
|
||||
AMD = "AMD",
|
||||
UMD = "UMD",
|
||||
System = "System",
|
||||
ES6 = "ES6",
|
||||
ES2015 = "ES2015",
|
||||
}
|
||||
type ModuleKind = ModuleKind.None | ModuleKind.CommonJS | ModuleKind.AMD | ModuleKind.UMD | ModuleKind.System | ModuleKind.ES6 | ModuleKind.ES2015;
|
||||
namespace ModuleResolutionKind {
|
||||
type Classic = "Classic";
|
||||
type Node = "Node";
|
||||
const enum ModuleResolutionKind {
|
||||
Classic = "Classic",
|
||||
Node = "Node",
|
||||
}
|
||||
type ModuleResolutionKind = ModuleResolutionKind.Classic | ModuleResolutionKind.Node;
|
||||
namespace NewLineKind {
|
||||
type Crlf = "Crlf";
|
||||
type Lf = "Lf";
|
||||
const enum NewLineKind {
|
||||
Crlf = "Crlf",
|
||||
Lf = "Lf",
|
||||
}
|
||||
type NewLineKind = NewLineKind.Crlf | NewLineKind.Lf;
|
||||
namespace ScriptTarget {
|
||||
type ES3 = "ES3";
|
||||
type ES5 = "ES5";
|
||||
type ES6 = "ES6";
|
||||
type ES2015 = "ES2015";
|
||||
const enum ScriptTarget {
|
||||
ES3 = "ES3",
|
||||
ES5 = "ES5",
|
||||
ES6 = "ES6",
|
||||
ES2015 = "ES2015",
|
||||
}
|
||||
type ScriptTarget = ScriptTarget.ES3 | ScriptTarget.ES5 | ScriptTarget.ES6 | ScriptTarget.ES2015;
|
||||
}
|
||||
declare namespace ts.server.protocol {
|
||||
|
||||
@@ -1943,6 +2026,8 @@ declare namespace ts.server.protocol {
|
||||
}
|
||||
declare namespace ts {
|
||||
// these types are empty stubs for types from services and should not be used directly
|
||||
export type HighlightSpanKind = never;
|
||||
export type ScriptElementKind = never;
|
||||
export type ScriptKind = never;
|
||||
export type IndentStyle = never;
|
||||
export type JsxEmit = never;
|
||||
|
||||
+32264
-31871
File diff suppressed because it is too large
Load Diff
+34381
-32033
File diff suppressed because it is too large
Load Diff
Vendored
+939
-685
File diff suppressed because it is too large
Load Diff
+37069
-34736
File diff suppressed because it is too large
Load Diff
Vendored
+803
-446
File diff suppressed because it is too large
Load Diff
+40242
-37611
File diff suppressed because it is too large
Load Diff
Vendored
+803
-446
File diff suppressed because it is too large
Load Diff
+40242
-37611
File diff suppressed because it is too large
Load Diff
+11502
-2323
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,7 @@ See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
|
||||
"use strict";
|
||||
if (process.argv.length < 3) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
+1
-1
@@ -17,6 +17,6 @@ nodeVersions.each { nodeVer ->
|
||||
}
|
||||
|
||||
Utilities.standardJobSetup(newJob, project, true, "*/${branch}")
|
||||
Utilities.setMachineAffinity(newJob, 'Ubuntu', '20161020')
|
||||
Utilities.setMachineAffinity(newJob, 'Ubuntu14.04', '20161020')
|
||||
Utilities.addGithubPRTriggerForBranch(newJob, branch, "TypeScript Test Run ${newJobName}")
|
||||
}
|
||||
|
||||
+6
-5
@@ -2,7 +2,7 @@
|
||||
"name": "typescript",
|
||||
"author": "Microsoft Corp.",
|
||||
"homepage": "http://typescriptlang.org/",
|
||||
"version": "2.4.0",
|
||||
"version": "2.6.0",
|
||||
"license": "Apache-2.0",
|
||||
"description": "TypeScript is a language for application scale JavaScript development",
|
||||
"keywords": [
|
||||
@@ -34,7 +34,7 @@
|
||||
"@types/convert-source-map": "latest",
|
||||
"@types/del": "latest",
|
||||
"@types/glob": "latest",
|
||||
"@types/gulp": "latest",
|
||||
"@types/gulp": "3.X",
|
||||
"@types/gulp-concat": "latest",
|
||||
"@types/gulp-help": "latest",
|
||||
"@types/gulp-newer": "latest",
|
||||
@@ -52,7 +52,7 @@
|
||||
"chai": "latest",
|
||||
"convert-source-map": "latest",
|
||||
"del": "latest",
|
||||
"gulp": "latest",
|
||||
"gulp": "3.X",
|
||||
"gulp-clone": "latest",
|
||||
"gulp-concat": "latest",
|
||||
"gulp-help": "latest",
|
||||
@@ -60,7 +60,6 @@
|
||||
"gulp-newer": "latest",
|
||||
"gulp-sourcemaps": "latest",
|
||||
"gulp-typescript": "latest",
|
||||
"into-stream": "latest",
|
||||
"istanbul": "latest",
|
||||
"jake": "latest",
|
||||
"merge2": "latest",
|
||||
@@ -91,9 +90,11 @@
|
||||
"setup-hooks": "node scripts/link-hooks.js"
|
||||
},
|
||||
"browser": {
|
||||
"buffer": false,
|
||||
"fs": false,
|
||||
"os": false,
|
||||
"path": false
|
||||
},
|
||||
"dependencies": {
|
||||
"browser-resolve": "^1.11.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,15 @@ function endsWith(s: string, suffix: string) {
|
||||
return s.lastIndexOf(suffix, s.length - suffix.length) !== -1;
|
||||
}
|
||||
|
||||
function isStringEnum(declaration: ts.EnumDeclaration) {
|
||||
return declaration.members.length && declaration.members.every(m => m.initializer && m.initializer.kind === ts.SyntaxKind.StringLiteral);
|
||||
}
|
||||
|
||||
class DeclarationsWalker {
|
||||
private visitedTypes: ts.Type[] = [];
|
||||
private text = "";
|
||||
private removedTypes: ts.Type[] = [];
|
||||
|
||||
|
||||
private constructor(private typeChecker: ts.TypeChecker, private protocolFile: ts.SourceFile) {
|
||||
}
|
||||
|
||||
@@ -19,7 +23,7 @@ class DeclarationsWalker {
|
||||
let text = "declare namespace ts.server.protocol {\n";
|
||||
var walker = new DeclarationsWalker(typeChecker, protocolFile);
|
||||
walker.visitTypeNodes(protocolFile);
|
||||
text = walker.text
|
||||
text = walker.text
|
||||
? `declare namespace ts.server.protocol {\n${walker.text}}`
|
||||
: "";
|
||||
if (walker.removedTypes) {
|
||||
@@ -52,7 +56,7 @@ class DeclarationsWalker {
|
||||
if (sourceFile === this.protocolFile || path.basename(sourceFile.fileName) === "lib.d.ts") {
|
||||
return;
|
||||
}
|
||||
if (decl.kind === ts.SyntaxKind.EnumDeclaration) {
|
||||
if (decl.kind === ts.SyntaxKind.EnumDeclaration && !isStringEnum(decl as ts.EnumDeclaration)) {
|
||||
this.removedTypes.push(type);
|
||||
return;
|
||||
}
|
||||
@@ -91,7 +95,7 @@ class DeclarationsWalker {
|
||||
for (const type of heritageClauses[0].types) {
|
||||
this.processTypeOfNode(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -110,7 +114,7 @@ class DeclarationsWalker {
|
||||
this.processType(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeProtocolFile(outputFile: string, protocolTs: string, typeScriptServicesDts: string) {
|
||||
|
||||
+34
-24
@@ -19,47 +19,57 @@ function main(): void {
|
||||
|
||||
// Acquire the version from the package.json file and modify it appropriately.
|
||||
const packageJsonFilePath = ts.normalizePath(sys.args[0]);
|
||||
const packageJsonContents = sys.readFile(packageJsonFilePath);
|
||||
const packageJsonValue: PackageJson = JSON.parse(packageJsonContents);
|
||||
const packageJsonValue: PackageJson = JSON.parse(sys.readFile(packageJsonFilePath));
|
||||
|
||||
const nightlyVersion = getNightlyVersionString(packageJsonValue.version);
|
||||
|
||||
// Modify the package.json structure
|
||||
packageJsonValue.version = nightlyVersion;
|
||||
const { majorMinor, patch } = parsePackageJsonVersion(packageJsonValue.version);
|
||||
const nightlyPatch = getNightlyPatch(patch);
|
||||
|
||||
// Acquire and modify the source file that exposes the version string.
|
||||
const tsFilePath = ts.normalizePath(sys.args[1]);
|
||||
const tsFileContents = sys.readFile(tsFilePath);
|
||||
const versionAssignmentRegExp = /export\s+const\s+version\s+=\s+".*";/;
|
||||
const modifiedTsFileContents = tsFileContents.replace(versionAssignmentRegExp, `export const version = "${nightlyVersion}";`);
|
||||
const tsFileContents = ts.sys.readFile(tsFilePath);
|
||||
const modifiedTsFileContents = updateTsFile(tsFilePath, tsFileContents, majorMinor, patch, nightlyPatch);
|
||||
|
||||
// Ensure we are actually changing something - the user probably wants to know that the update failed.
|
||||
if (tsFileContents === modifiedTsFileContents) {
|
||||
let err = `\n '${tsFilePath}' was not updated while configuring for a nightly publish.\n `;
|
||||
|
||||
if (tsFileContents.match(versionAssignmentRegExp)) {
|
||||
err += `Ensure that you have not already run this script; otherwise, erase your changes using 'git checkout -- "${tsFilePath}"'.`;
|
||||
}
|
||||
else {
|
||||
err += `The file seems to no longer have a string matching '${versionAssignmentRegExp}'.`;
|
||||
}
|
||||
|
||||
err += `Ensure that you have not already run this script; otherwise, erase your changes using 'git checkout -- "${tsFilePath}"'.`;
|
||||
throw err + "\n";
|
||||
}
|
||||
|
||||
// Finally write the changes to disk.
|
||||
// Modify the package.json structure
|
||||
packageJsonValue.version = `${majorMinor}.${nightlyPatch}`;
|
||||
sys.writeFile(packageJsonFilePath, JSON.stringify(packageJsonValue, /*replacer:*/ undefined, /*space:*/ 4))
|
||||
sys.writeFile(tsFilePath, modifiedTsFileContents);
|
||||
}
|
||||
|
||||
function getNightlyVersionString(versionString: string): string {
|
||||
// If the version string already contains "-nightly",
|
||||
// then get the base string and update based on that.
|
||||
const dashNightlyPos = versionString.indexOf("-dev");
|
||||
if (dashNightlyPos >= 0) {
|
||||
versionString = versionString.slice(0, dashNightlyPos);
|
||||
function updateTsFile(tsFilePath: string, tsFileContents: string, majorMinor: string, patch: string, nightlyPatch: string): string {
|
||||
const majorMinorRgx = /export const versionMajorMinor = "(\d+\.\d+)"/;
|
||||
const majorMinorMatch = majorMinorRgx.exec(tsFileContents);
|
||||
ts.Debug.assert(majorMinorMatch !== null, "", () => `The file seems to no longer have a string matching '${majorMinorRgx}'.`);
|
||||
const parsedMajorMinor = majorMinorMatch[1];
|
||||
ts.Debug.assert(parsedMajorMinor === majorMinor, "versionMajorMinor does not match.", () => `${tsFilePath}: '${parsedMajorMinor}'; package.json: '${majorMinor}'`);
|
||||
|
||||
const versionRgx = /export const version = `\$\{versionMajorMinor\}\.(\d)`;/;
|
||||
const patchMatch = versionRgx.exec(tsFileContents);
|
||||
ts.Debug.assert(patchMatch !== null, "The file seems to no longer have a string matching", () => versionRgx.toString());
|
||||
const parsedPatch = patchMatch[1];
|
||||
if (parsedPatch !== patch) {
|
||||
throw new Error(`patch does not match. ${tsFilePath}: '${parsedPatch}; package.json: '${patch}'`);
|
||||
}
|
||||
|
||||
return tsFileContents.replace(versionRgx, `export const version = \`\${versionMajorMinor}.${nightlyPatch}\`;`);
|
||||
}
|
||||
|
||||
function parsePackageJsonVersion(versionString: string): { majorMinor: string, patch: string } {
|
||||
const versionRgx = /(\d+\.\d+)\.(\d+)($|\-)/;
|
||||
const match = versionString.match(versionRgx);
|
||||
ts.Debug.assert(match !== null, "package.json 'version' should match", () => versionRgx.toString());
|
||||
return { majorMinor: match[1], patch: match[2] };
|
||||
}
|
||||
|
||||
/** e.g. 0-dev.20170707 */
|
||||
function getNightlyPatch(plainPatch: string): string {
|
||||
// We're going to append a representation of the current time at the end of the current version.
|
||||
// String.prototype.toISOString() returns a 24-character string formatted as 'YYYY-MM-DDTHH:mm:ss.sssZ',
|
||||
// but we'd prefer to just remove separators and limit ourselves to YYYYMMDD.
|
||||
@@ -67,7 +77,7 @@ function getNightlyVersionString(versionString: string): string {
|
||||
const now = new Date();
|
||||
const timeStr = now.toISOString().replace(/:|T|\.|-/g, "").slice(0, 8);
|
||||
|
||||
return `${versionString}-dev.${timeStr}`;
|
||||
return `${plainPatch}-dev.${timeStr}`;
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -72,6 +72,7 @@ function runTests(taskConfigsFolder, run, options, cb) {
|
||||
current: undefined,
|
||||
start: undefined,
|
||||
end: undefined,
|
||||
catastrophicError: "",
|
||||
failures: []
|
||||
};
|
||||
partitions[index] = partition;
|
||||
@@ -86,9 +87,20 @@ function runTests(taskConfigsFolder, run, options, cb) {
|
||||
input: p.stdout,
|
||||
terminal: false
|
||||
});
|
||||
|
||||
var rlError = readline.createInterface({
|
||||
input: p.stderr,
|
||||
terminal: false
|
||||
});
|
||||
|
||||
rl.on("line", onmessage);
|
||||
rlError.on("line", onErrorMessage);
|
||||
p.on("exit", onexit)
|
||||
|
||||
function onErrorMessage(line) {
|
||||
partition.catastrophicError += line + os.EOL;
|
||||
}
|
||||
|
||||
function onmessage(line) {
|
||||
if (partition.start === undefined) {
|
||||
partition.start = Date.now();
|
||||
@@ -153,15 +165,17 @@ function runTests(taskConfigsFolder, run, options, cb) {
|
||||
}
|
||||
}
|
||||
|
||||
function onexit() {
|
||||
function onexit(code) {
|
||||
if (partition.end === undefined) {
|
||||
partition.end = Date.now();
|
||||
}
|
||||
|
||||
partition.duration = partition.end - partition.start;
|
||||
var summaryColor = partition.failed ? "fail" : "green";
|
||||
var summarySymbol = partition.failed ? Base.symbols.err : Base.symbols.ok;
|
||||
var summaryTests = (partition.passed === partition.tests ? partition.passed : partition.passed + "/" + partition.tests) + " passing";
|
||||
var isPartitionFail = partition.failed || code !== 0;
|
||||
var summaryColor = isPartitionFail ? "fail" : "green";
|
||||
var summarySymbol = isPartitionFail ? Base.symbols.err : Base.symbols.ok;
|
||||
|
||||
var summaryTests = (isPartitionFail ? partition.passed + "/" + partition.tests : partition.passed) + " passing";
|
||||
var summaryDuration = "(" + ms(partition.duration) + ")";
|
||||
var savedUseColors = Base.useColors;
|
||||
Base.useColors = !options.noColors;
|
||||
@@ -198,12 +212,34 @@ function runTests(taskConfigsFolder, run, options, cb) {
|
||||
failures = reporter.failures;
|
||||
|
||||
var duration = 0;
|
||||
var catastrophicError = "";
|
||||
for (var i = 0; i < numPartitions; i++) {
|
||||
var partition = partitions[i];
|
||||
stats.passes += partition.passed;
|
||||
stats.failures += partition.failed;
|
||||
stats.tests += partition.tests;
|
||||
duration += partition.duration;
|
||||
if (partition.catastrophicError !== "") {
|
||||
// Partition is written out to a temporary file as a JSON object.
|
||||
// Below is an example of how the partition JSON object looks like
|
||||
// {
|
||||
// "light":false,
|
||||
// "tasks":[
|
||||
// {
|
||||
// "runner":"compiler",
|
||||
// "files":["tests/cases/compiler/es6ImportNamedImportParsingError.ts"]
|
||||
// }
|
||||
// ],
|
||||
// "runUnitTests":false
|
||||
// }
|
||||
var jsonText = fs.readFileSync(partition.file);
|
||||
var configObj = JSON.parse(jsonText);
|
||||
if (configObj.tasks && configObj.tasks[0]) {
|
||||
catastrophicError += "Error from one or more of these files: " + configObj.tasks[0].files + os.EOL;
|
||||
catastrophicError += partition.catastrophicError;
|
||||
catastrophicError += os.EOL;
|
||||
}
|
||||
}
|
||||
for (var j = 0; j < partition.failures.length; j++) {
|
||||
var failure = partition.failures[j];
|
||||
failures.push(makeMochaTest(failure));
|
||||
@@ -223,6 +259,9 @@ function runTests(taskConfigsFolder, run, options, cb) {
|
||||
reporter.epilogue();
|
||||
}
|
||||
|
||||
if (catastrophicError !== "") {
|
||||
return cb(new Error(catastrophicError));
|
||||
}
|
||||
if (stats.failures) {
|
||||
return cb(new Error("Test failures reported: " + stats.failures));
|
||||
}
|
||||
|
||||
@@ -6,9 +6,7 @@ interface DiagnosticDetails {
|
||||
isEarly?: boolean;
|
||||
}
|
||||
|
||||
interface InputDiagnosticMessageTable {
|
||||
[msg: string]: DiagnosticDetails;
|
||||
}
|
||||
type InputDiagnosticMessageTable = ts.Map<DiagnosticDetails>;
|
||||
|
||||
function main(): void {
|
||||
var sys = ts.sys;
|
||||
@@ -28,101 +26,66 @@ function main(): void {
|
||||
var inputFilePath = sys.args[0].replace(/\\/g, "/");
|
||||
var inputStr = sys.readFile(inputFilePath);
|
||||
|
||||
var diagnosticMessages: InputDiagnosticMessageTable = JSON.parse(inputStr);
|
||||
var diagnosticMessagesJson: { [key: string]: DiagnosticDetails } = JSON.parse(inputStr);
|
||||
// Check that there are no duplicates.
|
||||
const seenNames = ts.createMap<true>();
|
||||
for (const name of Object.keys(diagnosticMessagesJson)) {
|
||||
if (seenNames.has(name))
|
||||
throw new Error(`Name ${name} appears twice`);
|
||||
seenNames.set(name, true);
|
||||
}
|
||||
|
||||
var names = Utilities.getObjectKeys(diagnosticMessages);
|
||||
var nameMap = buildUniqueNameMap(names);
|
||||
const diagnosticMessages: InputDiagnosticMessageTable = ts.createMapFromTemplate(diagnosticMessagesJson);
|
||||
|
||||
var infoFileOutput = buildInfoFileOutput(diagnosticMessages, nameMap);
|
||||
checkForUniqueCodes(names, diagnosticMessages);
|
||||
var infoFileOutput = buildInfoFileOutput(diagnosticMessages);
|
||||
checkForUniqueCodes(diagnosticMessages);
|
||||
writeFile("diagnosticInformationMap.generated.ts", infoFileOutput);
|
||||
|
||||
var messageOutput = buildDiagnosticMessageOutput(diagnosticMessages, nameMap);
|
||||
var messageOutput = buildDiagnosticMessageOutput(diagnosticMessages);
|
||||
writeFile("diagnosticMessages.generated.json", messageOutput);
|
||||
}
|
||||
|
||||
function checkForUniqueCodes(messages: string[], diagnosticTable: InputDiagnosticMessageTable) {
|
||||
const originalMessageForCode: string[] = [];
|
||||
let numConflicts = 0;
|
||||
|
||||
for (const currentMessage of messages) {
|
||||
const code = diagnosticTable[currentMessage].code;
|
||||
|
||||
if (code in originalMessageForCode) {
|
||||
const originalMessage = originalMessageForCode[code];
|
||||
ts.sys.write("\x1b[91m"); // High intensity red.
|
||||
ts.sys.write("Error");
|
||||
ts.sys.write("\x1b[0m"); // Reset formatting.
|
||||
ts.sys.write(`: Diagnostic code '${code}' conflicts between "${originalMessage}" and "${currentMessage}".`);
|
||||
ts.sys.write(ts.sys.newLine + ts.sys.newLine);
|
||||
|
||||
numConflicts++;
|
||||
}
|
||||
else {
|
||||
originalMessageForCode[code] = currentMessage;
|
||||
}
|
||||
}
|
||||
|
||||
if (numConflicts > 0) {
|
||||
throw new Error(`Found ${numConflicts} conflict(s) in diagnostic codes.`);
|
||||
}
|
||||
function checkForUniqueCodes(diagnosticTable: InputDiagnosticMessageTable) {
|
||||
const allCodes: { [key: number]: true | undefined } = [];
|
||||
diagnosticTable.forEach(({ code }) => {
|
||||
if (allCodes[code])
|
||||
throw new Error(`Diagnostic code ${code} appears more than once.`);
|
||||
allCodes[code] = true;
|
||||
});
|
||||
}
|
||||
|
||||
function buildUniqueNameMap(names: string[]): ts.Map<string> {
|
||||
var nameMap = ts.createMap<string>();
|
||||
|
||||
var uniqueNames = NameGenerator.ensureUniqueness(names, /* isCaseSensitive */ false, /* isFixed */ undefined);
|
||||
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
nameMap.set(names[i], uniqueNames[i]);
|
||||
}
|
||||
|
||||
return nameMap;
|
||||
}
|
||||
|
||||
function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable, nameMap: ts.Map<string>): string {
|
||||
function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable): string {
|
||||
var result =
|
||||
'// <auto-generated />\r\n' +
|
||||
'/// <reference path="types.ts" />\r\n' +
|
||||
'/* @internal */\r\n' +
|
||||
'namespace ts {\r\n' +
|
||||
" function diag(code: number, category: DiagnosticCategory, key: string, message: string): DiagnosticMessage {\r\n" +
|
||||
" return { code, category, key, message };\r\n" +
|
||||
" }\r\n" +
|
||||
' export const Diagnostics = {\r\n';
|
||||
var names = Utilities.getObjectKeys(messageTable);
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
var name = names[i];
|
||||
var diagnosticDetails = messageTable[name];
|
||||
var propName = convertPropertyName(nameMap.get(name));
|
||||
|
||||
result +=
|
||||
' ' + propName +
|
||||
': { code: ' + diagnosticDetails.code +
|
||||
', category: DiagnosticCategory.' + diagnosticDetails.category +
|
||||
', key: "' + createKey(propName, diagnosticDetails.code) + '"' +
|
||||
', message: "' + name.replace(/[\"]/g, '\\"') + '"' +
|
||||
' },\r\n';
|
||||
}
|
||||
messageTable.forEach(({ code, category }, name) => {
|
||||
const propName = convertPropertyName(name);
|
||||
result += ` ${propName}: diag(${code}, DiagnosticCategory.${category}, "${createKey(propName, code)}", ${JSON.stringify(name)}),\r\n`;
|
||||
});
|
||||
|
||||
result += ' };\r\n}';
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function buildDiagnosticMessageOutput(messageTable: InputDiagnosticMessageTable, nameMap: ts.Map<string>): string {
|
||||
var result =
|
||||
'{';
|
||||
var names = Utilities.getObjectKeys(messageTable);
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
var name = names[i];
|
||||
var diagnosticDetails = messageTable[name];
|
||||
var propName = convertPropertyName(nameMap.get(name));
|
||||
function buildDiagnosticMessageOutput(messageTable: InputDiagnosticMessageTable): string {
|
||||
let result = '{';
|
||||
messageTable.forEach(({ code }, name) => {
|
||||
const propName = convertPropertyName(name);
|
||||
result += `\r\n "${createKey(propName, code)}" : "${name.replace(/[\"]/g, '\\"')}",`;
|
||||
});
|
||||
|
||||
result += '\r\n "' + createKey(propName, diagnosticDetails.code) + '"' + ' : "' + name.replace(/[\"]/g, '\\"') + '"';
|
||||
if (i !== names.length - 1) {
|
||||
result += ',';
|
||||
}
|
||||
}
|
||||
// Shave trailing comma, then add newline and ending brace
|
||||
result = result.slice(0, result.length - 1) + '\r\n}';
|
||||
|
||||
result += '\r\n}';
|
||||
// Assert that we generated valid JSON
|
||||
JSON.parse(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -139,7 +102,6 @@ function convertPropertyName(origName: string): string {
|
||||
return /\w/.test(char) ? char : "_";
|
||||
}).join("");
|
||||
|
||||
|
||||
// get rid of all multi-underscores
|
||||
result = result.replace(/_+/g, "_");
|
||||
|
||||
@@ -152,93 +114,4 @@ function convertPropertyName(origName: string): string {
|
||||
return result;
|
||||
}
|
||||
|
||||
module NameGenerator {
|
||||
export function ensureUniqueness(names: string[], isCaseSensitive: boolean, isFixed?: boolean[]): string[]{
|
||||
if (!isFixed) {
|
||||
isFixed = names.map(() => false)
|
||||
}
|
||||
|
||||
var names = names.slice();
|
||||
ensureUniquenessInPlace(names, isCaseSensitive, isFixed);
|
||||
return names;
|
||||
}
|
||||
|
||||
function ensureUniquenessInPlace(names: string[], isCaseSensitive: boolean, isFixed: boolean[]): void {
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
var name = names[i];
|
||||
var collisionIndices = Utilities.collectMatchingIndices(name, names, isCaseSensitive);
|
||||
|
||||
// We will always have one "collision" because getCollisionIndices returns the index of name itself as well;
|
||||
// so if we only have one collision, then there are no issues.
|
||||
if (collisionIndices.length < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
handleCollisions(name, names, isFixed, collisionIndices, isCaseSensitive);
|
||||
}
|
||||
}
|
||||
|
||||
function handleCollisions(name: string, proposedNames: string[], isFixed: boolean[], collisionIndices: number[], isCaseSensitive: boolean): void {
|
||||
var suffix = 1;
|
||||
|
||||
for (var i = 0; i < collisionIndices.length; i++) {
|
||||
var collisionIndex = collisionIndices[i];
|
||||
|
||||
if (isFixed[collisionIndex]) {
|
||||
// can't do anything about this name.
|
||||
continue;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
var newName = name + suffix;
|
||||
suffix++;
|
||||
|
||||
// Check if we've synthesized a unique name, and if so
|
||||
// replace the conflicting name with the new one.
|
||||
if (!proposedNames.some(name => Utilities.stringEquals(name, newName, isCaseSensitive))) {
|
||||
proposedNames[collisionIndex] = newName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module Utilities {
|
||||
/// Return a list of all indices where a string occurs.
|
||||
export function collectMatchingIndices(name: string, proposedNames: string[], isCaseSensitive: boolean): number[] {
|
||||
var matchingIndices: number[] = [];
|
||||
|
||||
for (var i = 0; i < proposedNames.length; i++) {
|
||||
if (stringEquals(name, proposedNames[i], isCaseSensitive)) {
|
||||
matchingIndices.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
return matchingIndices;
|
||||
}
|
||||
|
||||
export function stringEquals(s1: string, s2: string, caseSensitive: boolean): boolean {
|
||||
if (caseSensitive) {
|
||||
s1 = s1.toLowerCase();
|
||||
s2 = s2.toLowerCase();
|
||||
}
|
||||
|
||||
return s1 == s2;
|
||||
}
|
||||
|
||||
// Like Object.keys
|
||||
export function getObjectKeys(obj: any): string[] {
|
||||
var result: string[] = [];
|
||||
|
||||
for (var name in obj) {
|
||||
if (obj.hasOwnProperty(name)) {
|
||||
result.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -27,13 +27,14 @@ function walk(ctx: Lint.WalkContext<void>): void {
|
||||
/** Skip certain function/method names whose parameter names are not informative. */
|
||||
function shouldIgnoreCalledExpression(expression: ts.Expression): boolean {
|
||||
if (expression.kind === ts.SyntaxKind.PropertyAccessExpression) {
|
||||
const methodName = (expression as ts.PropertyAccessExpression).name.text;
|
||||
const methodName = (expression as ts.PropertyAccessExpression).name.text as string;
|
||||
if (methodName.indexOf("set") === 0) {
|
||||
return true;
|
||||
}
|
||||
switch (methodName) {
|
||||
case "apply":
|
||||
case "assert":
|
||||
case "assertEqual":
|
||||
case "call":
|
||||
case "equal":
|
||||
case "fail":
|
||||
@@ -44,7 +45,7 @@ function walk(ctx: Lint.WalkContext<void>): void {
|
||||
}
|
||||
}
|
||||
else if (expression.kind === ts.SyntaxKind.Identifier) {
|
||||
const functionName = (expression as ts.Identifier).text;
|
||||
const functionName = (expression as ts.Identifier).text as string;
|
||||
if (functionName.indexOf("set") === 0) {
|
||||
return true;
|
||||
}
|
||||
@@ -69,7 +70,7 @@ function walk(ctx: Lint.WalkContext<void>): void {
|
||||
|
||||
const ranges = ts.getTrailingCommentRanges(sourceFile.text, arg.pos) || ts.getLeadingCommentRanges(sourceFile.text, arg.pos);
|
||||
if (ranges === undefined || ranges.length !== 1 || ranges[0].kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
|
||||
ctx.addFailureAtNode(arg, "Tag boolean argument with parameter name");
|
||||
ctx.addFailureAtNode(arg, "Tag argument with parameter name");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import * as Lint from "tslint/lib";
|
||||
import * as ts from "typescript";
|
||||
|
||||
export class Rule extends Lint.Rules.AbstractRule {
|
||||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
||||
return this.applyWithFunction(sourceFile, ctx => walk(ctx));
|
||||
}
|
||||
}
|
||||
|
||||
function walk(ctx: Lint.WalkContext<void>): void {
|
||||
ts.forEachChild(ctx.sourceFile, function recur(node) {
|
||||
if (ts.isCallExpression(node)) {
|
||||
checkCall(node);
|
||||
}
|
||||
ts.forEachChild(node, recur);
|
||||
});
|
||||
|
||||
function checkCall(node: ts.CallExpression) {
|
||||
if (!isDebugAssert(node.expression) || node.arguments.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const message = node.arguments[1];
|
||||
if (!ts.isStringLiteral(message)) {
|
||||
ctx.addFailureAtNode(message, "Second argument to 'Debug.assert' should be a string literal.");
|
||||
}
|
||||
|
||||
if (node.arguments.length < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
const message2 = node.arguments[2];
|
||||
if (!ts.isStringLiteral(message2) && !ts.isArrowFunction(message2)) {
|
||||
ctx.addFailureAtNode(message, "Third argument to 'Debug.assert' should be a string literal or arrow function.");
|
||||
}
|
||||
}
|
||||
|
||||
function isDebugAssert(expr: ts.Node): boolean {
|
||||
return ts.isPropertyAccessExpression(expr) && isName(expr.expression, "Debug") && isName(expr.name, "assert");
|
||||
}
|
||||
|
||||
function isName(expr: ts.Node, text: string): boolean {
|
||||
return ts.isIdentifier(expr) && expr.text === text;
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ function walk(ctx: Lint.WalkContext<void>): void {
|
||||
ts.forEachChild(node, recur);
|
||||
}
|
||||
|
||||
function check(types: ts.TypeNode[]): void {
|
||||
function check(types: ReadonlyArray<ts.TypeNode>): void {
|
||||
let expectedStart = types[0].end + 2; // space, | or &
|
||||
for (let i = 1; i < types.length; i++) {
|
||||
const currentType = types[i];
|
||||
|
||||
Vendored
-8
@@ -13,13 +13,5 @@ declare module "gulp-insert" {
|
||||
export function transform(cb: (contents: string, file: {path: string, relative: string}) => string): NodeJS.ReadWriteStream; // file is a vinyl file
|
||||
}
|
||||
|
||||
declare module "into-stream" {
|
||||
function IntoStream(content: string | Buffer | (string | Buffer)[]): NodeJS.ReadableStream;
|
||||
namespace IntoStream {
|
||||
export function obj(content: any): NodeJS.ReadableStream
|
||||
}
|
||||
export = IntoStream;
|
||||
}
|
||||
|
||||
declare module "sorcery";
|
||||
declare module "travis-fold";
|
||||
|
||||
+154
-182
@@ -10,7 +10,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
interface ActiveLabel {
|
||||
name: string;
|
||||
name: __String;
|
||||
breakTarget: FlowLabel;
|
||||
continueTarget: FlowLabel;
|
||||
referenced: boolean;
|
||||
@@ -132,8 +132,9 @@ namespace ts {
|
||||
let inStrictMode: boolean;
|
||||
|
||||
let symbolCount = 0;
|
||||
let Symbol: { new (flags: SymbolFlags, name: string): Symbol };
|
||||
let classifiableNames: Map<string>;
|
||||
|
||||
let Symbol: { new (flags: SymbolFlags, name: __String): Symbol };
|
||||
let classifiableNames: UnderscoreEscapedMap<true>;
|
||||
|
||||
const unreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
|
||||
const reportedUnreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
|
||||
@@ -147,7 +148,7 @@ namespace ts {
|
||||
options = opts;
|
||||
languageVersion = getEmitScriptTarget(options);
|
||||
inStrictMode = bindInStrictMode(file, opts);
|
||||
classifiableNames = createMap<string>();
|
||||
classifiableNames = createUnderscoreEscapedMap<true>();
|
||||
symbolCount = 0;
|
||||
skipTransformFlagAggregation = file.isDeclarationFile;
|
||||
|
||||
@@ -191,7 +192,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function createSymbol(flags: SymbolFlags, name: string): Symbol {
|
||||
function createSymbol(flags: SymbolFlags, name: __String): Symbol {
|
||||
symbolCount++;
|
||||
return new Symbol(flags, name);
|
||||
}
|
||||
@@ -207,11 +208,11 @@ namespace ts {
|
||||
symbol.declarations.push(node);
|
||||
|
||||
if (symbolFlags & SymbolFlags.HasExports && !symbol.exports) {
|
||||
symbol.exports = createMap<Symbol>();
|
||||
symbol.exports = createSymbolTable();
|
||||
}
|
||||
|
||||
if (symbolFlags & SymbolFlags.HasMembers && !symbol.members) {
|
||||
symbol.members = createMap<Symbol>();
|
||||
symbol.members = createSymbolTable();
|
||||
}
|
||||
|
||||
if (symbolFlags & SymbolFlags.Value) {
|
||||
@@ -226,67 +227,68 @@ namespace ts {
|
||||
|
||||
// Should not be called on a declaration with a computed property name,
|
||||
// unless it is a well known Symbol.
|
||||
function getDeclarationName(node: Declaration): string {
|
||||
function getDeclarationName(node: Declaration): __String {
|
||||
const name = getNameOfDeclaration(node);
|
||||
if (name) {
|
||||
if (isAmbientModule(node)) {
|
||||
return isGlobalScopeAugmentation(<ModuleDeclaration>node) ? "__global" : `"${(<LiteralExpression>name).text}"`;
|
||||
const moduleName = getTextOfIdentifierOrLiteral(<Identifier | LiteralExpression>name);
|
||||
return (isGlobalScopeAugmentation(<ModuleDeclaration>node) ? "__global" : `"${moduleName}"`) as __String;
|
||||
}
|
||||
if (name.kind === SyntaxKind.ComputedPropertyName) {
|
||||
const nameExpression = (<ComputedPropertyName>name).expression;
|
||||
// treat computed property names where expression is string/numeric literal as just string/numeric literal
|
||||
if (isStringOrNumericLiteral(nameExpression)) {
|
||||
return nameExpression.text;
|
||||
return escapeLeadingUnderscores(nameExpression.text);
|
||||
}
|
||||
|
||||
Debug.assert(isWellKnownSymbolSyntactically(nameExpression));
|
||||
return getPropertyNameForKnownSymbolName((<PropertyAccessExpression>nameExpression).name.text);
|
||||
return getPropertyNameForKnownSymbolName(unescapeLeadingUnderscores((<PropertyAccessExpression>nameExpression).name.escapedText));
|
||||
}
|
||||
return (<Identifier | LiteralExpression>name).text;
|
||||
return getEscapedTextOfIdentifierOrLiteral(<Identifier | LiteralExpression>name);
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
return "__constructor";
|
||||
return InternalSymbolName.Constructor;
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.CallSignature:
|
||||
return "__call";
|
||||
return InternalSymbolName.Call;
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
return "__new";
|
||||
return InternalSymbolName.New;
|
||||
case SyntaxKind.IndexSignature:
|
||||
return "__index";
|
||||
return InternalSymbolName.Index;
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
return "__export";
|
||||
return InternalSymbolName.ExportStar;
|
||||
case SyntaxKind.ExportAssignment:
|
||||
return (<ExportAssignment>node).isExportEquals ? "export=" : "default";
|
||||
return (<ExportAssignment>node).isExportEquals ? InternalSymbolName.ExportEquals : InternalSymbolName.Default;
|
||||
case SyntaxKind.BinaryExpression:
|
||||
if (getSpecialPropertyAssignmentKind(node as BinaryExpression) === SpecialPropertyAssignmentKind.ModuleExports) {
|
||||
// module.exports = ...
|
||||
return "export=";
|
||||
return InternalSymbolName.ExportEquals;
|
||||
}
|
||||
Debug.fail("Unknown binary declaration kind");
|
||||
break;
|
||||
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
return hasModifier(node, ModifierFlags.Default) ? "default" : undefined;
|
||||
return (hasModifier(node, ModifierFlags.Default) ? InternalSymbolName.Default : undefined);
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
return isJSDocConstructSignature(node) ? "__new" : "__call";
|
||||
return (isJSDocConstructSignature(node) ? InternalSymbolName.New : InternalSymbolName.Call);
|
||||
case SyntaxKind.Parameter:
|
||||
// Parameters with names are handled at the top of this function. Parameters
|
||||
// without names can only come from JSDocFunctionTypes.
|
||||
Debug.assert(node.parent.kind === SyntaxKind.JSDocFunctionType);
|
||||
const functionType = <JSDocFunctionType>node.parent;
|
||||
const index = indexOf(functionType.parameters, node);
|
||||
return "arg" + index;
|
||||
return "arg" + index as __String;
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
const parentNode = node.parent && node.parent.parent;
|
||||
let nameFromParentNode: string;
|
||||
let nameFromParentNode: __String;
|
||||
if (parentNode && parentNode.kind === SyntaxKind.VariableStatement) {
|
||||
if ((<VariableStatement>parentNode).declarationList.declarations.length > 0) {
|
||||
const nameIdentifier = (<VariableStatement>parentNode).declarationList.declarations[0].name;
|
||||
if (nameIdentifier.kind === SyntaxKind.Identifier) {
|
||||
nameFromParentNode = (<Identifier>nameIdentifier).text;
|
||||
if (isIdentifier(nameIdentifier)) {
|
||||
nameFromParentNode = nameIdentifier.escapedText;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -295,7 +297,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getDisplayName(node: Declaration): string {
|
||||
return (node as NamedDeclaration).name ? declarationNameToString((node as NamedDeclaration).name) : getDeclarationName(node);
|
||||
return (node as NamedDeclaration).name ? declarationNameToString((node as NamedDeclaration).name) : unescapeLeadingUnderscores(getDeclarationName(node));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -306,17 +308,17 @@ namespace ts {
|
||||
* @param includes - The SymbolFlags that node has in addition to its declaration type (eg: export, ambient, etc.)
|
||||
* @param excludes - The flags which node cannot be declared alongside in a symbol table. Used to report forbidden declarations.
|
||||
*/
|
||||
function declareSymbol(symbolTable: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol {
|
||||
function declareSymbol(symbolTable: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags, isReplaceableByMethod?: boolean): Symbol {
|
||||
Debug.assert(!hasDynamicName(node));
|
||||
|
||||
const isDefaultExport = hasModifier(node, ModifierFlags.Default);
|
||||
|
||||
// The exported symbol for an export default function/class node is always named "default"
|
||||
const name = isDefaultExport && parent ? "default" : getDeclarationName(node);
|
||||
const name = isDefaultExport && parent ? InternalSymbolName.Default : getDeclarationName(node);
|
||||
|
||||
let symbol: Symbol;
|
||||
if (name === undefined) {
|
||||
symbol = createSymbol(SymbolFlags.None, "__missing");
|
||||
symbol = createSymbol(SymbolFlags.None, InternalSymbolName.Missing);
|
||||
}
|
||||
else {
|
||||
// Check and see if the symbol table already has a symbol with this name. If not,
|
||||
@@ -343,15 +345,20 @@ namespace ts {
|
||||
// you have multiple 'vars' with the same name in the same container). In this case
|
||||
// just add this node into the declarations list of the symbol.
|
||||
symbol = symbolTable.get(name);
|
||||
|
||||
if (includes & SymbolFlags.Classifiable) {
|
||||
classifiableNames.set(name, true);
|
||||
}
|
||||
|
||||
if (!symbol) {
|
||||
symbolTable.set(name, symbol = createSymbol(SymbolFlags.None, name));
|
||||
if (isReplaceableByMethod) symbol.isReplaceableByMethod = true;
|
||||
}
|
||||
|
||||
if (name && (includes & SymbolFlags.Classifiable)) {
|
||||
classifiableNames.set(name, name);
|
||||
else if (isReplaceableByMethod && !symbol.isReplaceableByMethod) {
|
||||
// A symbol already exists, so don't add this as a declaration.
|
||||
return symbol;
|
||||
}
|
||||
|
||||
if (symbol.flags & excludes) {
|
||||
else if (symbol.flags & excludes) {
|
||||
if (symbol.isReplaceableByMethod) {
|
||||
// Javascript constructor-declared symbols can be discarded in favor of
|
||||
// prototype symbols like methods.
|
||||
@@ -414,9 +421,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Exported module members are given 2 symbols: A local symbol that is classified with an ExportValue,
|
||||
// ExportType, or ExportContainer flag, and an associated export symbol with all the correct flags set
|
||||
// on it. There are 2 main reasons:
|
||||
// Exported module members are given 2 symbols: A local symbol that is classified with an ExportValue flag,
|
||||
// and an associated export symbol with all the correct flags set on it. There are 2 main reasons:
|
||||
//
|
||||
// 1. We treat locals and exports of the same name as mutually exclusive within a container.
|
||||
// That means the binder will issue a Duplicate Identifier error if you mix locals and exports
|
||||
@@ -436,10 +442,7 @@ namespace ts {
|
||||
(node as JSDocTypedefTag).name.kind === SyntaxKind.Identifier &&
|
||||
((node as JSDocTypedefTag).name as Identifier).isInJSDocNamespace;
|
||||
if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || isJSDocTypedefInJSDocNamespace) {
|
||||
const exportKind =
|
||||
(symbolFlags & SymbolFlags.Value ? SymbolFlags.ExportValue : 0) |
|
||||
(symbolFlags & SymbolFlags.Type ? SymbolFlags.ExportType : 0) |
|
||||
(symbolFlags & SymbolFlags.Namespace ? SymbolFlags.ExportNamespace : 0);
|
||||
const exportKind = symbolFlags & SymbolFlags.Value ? SymbolFlags.ExportValue : 0;
|
||||
const local = declareSymbol(container.locals, /*parent*/ undefined, node, exportKind, symbolExcludes);
|
||||
local.exportSymbol = declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes);
|
||||
node.localSymbol = local;
|
||||
@@ -481,7 +484,7 @@ namespace ts {
|
||||
if (containerFlags & ContainerFlags.IsContainer) {
|
||||
container = blockScopeContainer = node;
|
||||
if (containerFlags & ContainerFlags.HasLocals) {
|
||||
container.locals = createMap<Symbol>();
|
||||
container.locals = createSymbolTable();
|
||||
}
|
||||
addToContainerChain(container);
|
||||
}
|
||||
@@ -595,7 +598,19 @@ namespace ts {
|
||||
// Binding of JsDocComment should be done before the current block scope container changes.
|
||||
// because the scope of JsDocComment should not be affected by whether the current node is a
|
||||
// container or not.
|
||||
forEach(node.jsDoc, bind);
|
||||
if (node.jsDoc) {
|
||||
if (isInJavaScriptFile(node)) {
|
||||
for (const j of node.jsDoc) {
|
||||
bind(j);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const j of node.jsDoc) {
|
||||
setParentPointers(node, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checkUnreachable(node)) {
|
||||
bindEachChild(node);
|
||||
return;
|
||||
@@ -612,7 +627,7 @@ namespace ts {
|
||||
break;
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.ForOfStatement:
|
||||
bindForInOrForOfStatement(<ForInStatement | ForOfStatement>node);
|
||||
bindForInOrForOfStatement(<ForInOrOfStatement>node);
|
||||
break;
|
||||
case SyntaxKind.IfStatement:
|
||||
bindIfStatement(<IfStatement>node);
|
||||
@@ -791,11 +806,7 @@ namespace ts {
|
||||
return antecedent;
|
||||
}
|
||||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowCondition>{
|
||||
flags,
|
||||
expression,
|
||||
antecedent
|
||||
};
|
||||
return { flags, expression, antecedent };
|
||||
}
|
||||
|
||||
function createFlowSwitchClause(antecedent: FlowNode, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): FlowNode {
|
||||
@@ -803,31 +814,18 @@ namespace ts {
|
||||
return antecedent;
|
||||
}
|
||||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowSwitchClause>{
|
||||
flags: FlowFlags.SwitchClause,
|
||||
switchStatement,
|
||||
clauseStart,
|
||||
clauseEnd,
|
||||
antecedent
|
||||
};
|
||||
return { flags: FlowFlags.SwitchClause, switchStatement, clauseStart, clauseEnd, antecedent };
|
||||
}
|
||||
|
||||
function createFlowAssignment(antecedent: FlowNode, node: Expression | VariableDeclaration | BindingElement): FlowNode {
|
||||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowAssignment>{
|
||||
flags: FlowFlags.Assignment,
|
||||
antecedent,
|
||||
node
|
||||
};
|
||||
return { flags: FlowFlags.Assignment, antecedent, node };
|
||||
}
|
||||
|
||||
function createFlowArrayMutation(antecedent: FlowNode, node: CallExpression | BinaryExpression): FlowNode {
|
||||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowArrayMutation>{
|
||||
flags: FlowFlags.ArrayMutation,
|
||||
antecedent,
|
||||
node
|
||||
};
|
||||
const res: FlowArrayMutation = { flags: FlowFlags.ArrayMutation, antecedent, node };
|
||||
return res;
|
||||
}
|
||||
|
||||
function finishFlowLabel(flow: FlowLabel): FlowNode {
|
||||
@@ -950,7 +948,7 @@ namespace ts {
|
||||
currentFlow = finishFlowLabel(postLoopLabel);
|
||||
}
|
||||
|
||||
function bindForInOrForOfStatement(node: ForInStatement | ForOfStatement): void {
|
||||
function bindForInOrForOfStatement(node: ForInOrOfStatement): void {
|
||||
const preLoopLabel = createLoopLabel();
|
||||
const postLoopLabel = createBranchLabel();
|
||||
addAntecedent(preLoopLabel, currentFlow);
|
||||
@@ -994,7 +992,7 @@ namespace ts {
|
||||
currentFlow = unreachableFlow;
|
||||
}
|
||||
|
||||
function findActiveLabel(name: string) {
|
||||
function findActiveLabel(name: __String) {
|
||||
if (activeLabels) {
|
||||
for (const label of activeLabels) {
|
||||
if (label.name === name) {
|
||||
@@ -1016,7 +1014,7 @@ namespace ts {
|
||||
function bindBreakOrContinueStatement(node: BreakOrContinueStatement): void {
|
||||
bind(node.label);
|
||||
if (node.label) {
|
||||
const activeLabel = findActiveLabel(node.label.text);
|
||||
const activeLabel = findActiveLabel(node.label.escapedText);
|
||||
if (activeLabel) {
|
||||
activeLabel.referenced = true;
|
||||
bindBreakOrContinueFlow(node, activeLabel.breakTarget, activeLabel.continueTarget);
|
||||
@@ -1157,8 +1155,8 @@ namespace ts {
|
||||
bindEach(node.statements);
|
||||
}
|
||||
|
||||
function pushActiveLabel(name: string, breakTarget: FlowLabel, continueTarget: FlowLabel): ActiveLabel {
|
||||
const activeLabel = {
|
||||
function pushActiveLabel(name: __String, breakTarget: FlowLabel, continueTarget: FlowLabel): ActiveLabel {
|
||||
const activeLabel: ActiveLabel = {
|
||||
name,
|
||||
breakTarget,
|
||||
continueTarget,
|
||||
@@ -1177,7 +1175,7 @@ namespace ts {
|
||||
const postStatementLabel = createBranchLabel();
|
||||
bind(node.label);
|
||||
addAntecedent(preStatementLabel, currentFlow);
|
||||
const activeLabel = pushActiveLabel(node.label.text, postStatementLabel, preStatementLabel);
|
||||
const activeLabel = pushActiveLabel(node.label.escapedText, postStatementLabel, preStatementLabel);
|
||||
bind(node.statement);
|
||||
popActiveLabel();
|
||||
if (!activeLabel.referenced && !options.allowUnusedLabels) {
|
||||
@@ -1317,7 +1315,7 @@ namespace ts {
|
||||
function bindInitializedVariableFlow(node: VariableDeclaration | ArrayBindingElement) {
|
||||
const name = !isOmittedExpression(node) ? node.name : undefined;
|
||||
if (isBindingPattern(name)) {
|
||||
for (const child of <ArrayBindingElement[]>name.elements) {
|
||||
for (const child of name.elements) {
|
||||
bindInitializedVariableFlow(child);
|
||||
}
|
||||
}
|
||||
@@ -1328,7 +1326,7 @@ namespace ts {
|
||||
|
||||
function bindVariableDeclarationFlow(node: VariableDeclaration) {
|
||||
bindEachChild(node);
|
||||
if (node.initializer || node.parent.parent.kind === SyntaxKind.ForInStatement || node.parent.parent.kind === SyntaxKind.ForOfStatement) {
|
||||
if (node.initializer || isForInOrOfStatement(node.parent.parent)) {
|
||||
bindInitializedVariableFlow(node);
|
||||
}
|
||||
}
|
||||
@@ -1385,14 +1383,12 @@ namespace ts {
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
case SyntaxKind.JSDocRecordType:
|
||||
case SyntaxKind.JsxAttributes:
|
||||
return ContainerFlags.IsContainer;
|
||||
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
return ContainerFlags.IsContainer | ContainerFlags.IsInterface;
|
||||
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.MappedType:
|
||||
@@ -1412,9 +1408,10 @@ namespace ts {
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike;
|
||||
|
||||
@@ -1490,10 +1487,9 @@ namespace ts {
|
||||
return declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes);
|
||||
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.JSDocRecordType:
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
case SyntaxKind.JsxAttributes:
|
||||
// Interface/Object-types always have their children added to the 'members' of
|
||||
// their container. They are only accessible through an instance of their
|
||||
@@ -1521,7 +1517,7 @@ namespace ts {
|
||||
// All the children of these container types are never visible through another
|
||||
// symbol (i.e. through another symbol's 'exports' or 'members'). Instead,
|
||||
// they're only accessed 'lexically' (i.e. from code that exists underneath
|
||||
// their container in the tree. To accomplish this, we simply add their declared
|
||||
// their container in the tree). To accomplish this, we simply add their declared
|
||||
// symbol to the 'locals' of the container. These symbols can then be found as
|
||||
// the type checker walks up the containers, checking them for matching names.
|
||||
return declareSymbol(container.locals, /*parent*/ undefined, node, symbolFlags, symbolExcludes);
|
||||
@@ -1633,10 +1629,10 @@ namespace ts {
|
||||
const symbol = createSymbol(SymbolFlags.Signature, getDeclarationName(node));
|
||||
addDeclarationToSymbol(symbol, node, SymbolFlags.Signature);
|
||||
|
||||
const typeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, "__type");
|
||||
const typeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, InternalSymbolName.Type);
|
||||
addDeclarationToSymbol(typeLiteralSymbol, node, SymbolFlags.TypeLiteral);
|
||||
typeLiteralSymbol.members = createMap<Symbol>();
|
||||
typeLiteralSymbol.members.set(symbol.name, symbol);
|
||||
typeLiteralSymbol.members = createSymbolTable();
|
||||
typeLiteralSymbol.members.set(symbol.escapedName, symbol);
|
||||
}
|
||||
|
||||
function bindObjectLiteralExpression(node: ObjectLiteralExpression) {
|
||||
@@ -1646,14 +1642,14 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (inStrictMode) {
|
||||
const seen = createMap<ElementKind>();
|
||||
const seen = createUnderscoreEscapedMap<ElementKind>();
|
||||
|
||||
for (const prop of node.properties) {
|
||||
if (prop.kind === SyntaxKind.SpreadAssignment || prop.name.kind !== SyntaxKind.Identifier) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const identifier = <Identifier>prop.name;
|
||||
const identifier = prop.name;
|
||||
|
||||
// ECMA-262 11.1.5 Object Initializer
|
||||
// If previous is not undefined then throw a SyntaxError exception if any of the following conditions are true
|
||||
@@ -1667,9 +1663,9 @@ namespace ts {
|
||||
? ElementKind.Property
|
||||
: ElementKind.Accessor;
|
||||
|
||||
const existingKind = seen.get(identifier.text);
|
||||
const existingKind = seen.get(identifier.escapedText);
|
||||
if (!existingKind) {
|
||||
seen.set(identifier.text, currentKind);
|
||||
seen.set(identifier.escapedText, currentKind);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1681,18 +1677,18 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
return bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, "__object");
|
||||
return bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, InternalSymbolName.Object);
|
||||
}
|
||||
|
||||
function bindJsxAttributes(node: JsxAttributes) {
|
||||
return bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, "__jsxAttributes");
|
||||
return bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, InternalSymbolName.JSXAttributes);
|
||||
}
|
||||
|
||||
function bindJsxAttribute(node: JsxAttribute, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
|
||||
return declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes);
|
||||
}
|
||||
|
||||
function bindAnonymousDeclaration(node: Declaration, symbolFlags: SymbolFlags, name: string) {
|
||||
function bindAnonymousDeclaration(node: Declaration, symbolFlags: SymbolFlags, name: __String) {
|
||||
const symbol = createSymbol(symbolFlags, name);
|
||||
addDeclarationToSymbol(symbol, node, symbolFlags);
|
||||
}
|
||||
@@ -1710,7 +1706,7 @@ namespace ts {
|
||||
// falls through
|
||||
default:
|
||||
if (!blockScopeContainer.locals) {
|
||||
blockScopeContainer.locals = createMap<Symbol>();
|
||||
blockScopeContainer.locals = createSymbolTable();
|
||||
addToContainerChain(blockScopeContainer);
|
||||
}
|
||||
declareSymbol(blockScopeContainer.locals, /*parent*/ undefined, node, symbolFlags, symbolExcludes);
|
||||
@@ -1779,8 +1775,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isEvalOrArgumentsIdentifier(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.Identifier &&
|
||||
((<Identifier>node).text === "eval" || (<Identifier>node).text === "arguments");
|
||||
return isIdentifier(node) && (node.escapedText === "eval" || node.escapedText === "arguments");
|
||||
}
|
||||
|
||||
function checkStrictModeEvalOrArguments(contextNode: Node, name: Node) {
|
||||
@@ -1791,7 +1786,7 @@ namespace ts {
|
||||
// otherwise report generic error message.
|
||||
const span = getErrorSpanForNode(file, name);
|
||||
file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length,
|
||||
getStrictModeEvalOrArgumentsMessage(contextNode), identifier.text));
|
||||
getStrictModeEvalOrArgumentsMessage(contextNode), unescapeLeadingUnderscores(identifier.escapedText)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1883,10 +1878,6 @@ namespace ts {
|
||||
file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, message, arg0, arg1, arg2));
|
||||
}
|
||||
|
||||
function getDestructuringParameterName(node: Declaration) {
|
||||
return "__" + indexOf((<SignatureDeclaration>node.parent).parameters, node);
|
||||
}
|
||||
|
||||
function bind(node: Node): void {
|
||||
if (!node) {
|
||||
return;
|
||||
@@ -1903,7 +1894,7 @@ namespace ts {
|
||||
// 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);
|
||||
if (isInJavaScriptFile(node)) 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
|
||||
@@ -1991,7 +1982,7 @@ namespace ts {
|
||||
// for typedef type names with namespaces, bind the new jsdoc type symbol here
|
||||
// because it requires all containing namespaces to be in effect, namely the
|
||||
// current "blockScopeContainer" needs to be set to its immediate namespace parent.
|
||||
if (isInJavaScriptFile(node) && (<Identifier>node).isInJSDocNamespace) {
|
||||
if ((<Identifier>node).isInJSDocNamespace) {
|
||||
let parentNode = node.parent;
|
||||
while (parentNode && parentNode.kind !== SyntaxKind.JSDocTypedefTag) {
|
||||
parentNode = parentNode.parent;
|
||||
@@ -2057,8 +2048,10 @@ namespace ts {
|
||||
case SyntaxKind.Parameter:
|
||||
return bindParameter(<ParameterDeclaration>node);
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return bindVariableDeclarationOrBindingElement(<VariableDeclaration>node);
|
||||
case SyntaxKind.BindingElement:
|
||||
return bindVariableDeclarationOrBindingElement(<VariableDeclaration | BindingElement>node);
|
||||
node.flowNode = currentFlow;
|
||||
return bindVariableDeclarationOrBindingElement(<BindingElement>node);
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.PropertySignature:
|
||||
return bindPropertyWorker(node as PropertyDeclaration | PropertySignature);
|
||||
@@ -2068,22 +2061,6 @@ namespace ts {
|
||||
case SyntaxKind.EnumMember:
|
||||
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes);
|
||||
|
||||
case SyntaxKind.SpreadAssignment:
|
||||
case SyntaxKind.JsxSpreadAttribute:
|
||||
let root = container;
|
||||
let hasRest = false;
|
||||
while (root.parent) {
|
||||
if (root.kind === SyntaxKind.ObjectLiteralExpression &&
|
||||
root.parent.kind === SyntaxKind.BinaryExpression &&
|
||||
(root.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken &&
|
||||
(root.parent as BinaryExpression).left === root) {
|
||||
hasRest = true;
|
||||
break;
|
||||
}
|
||||
root = root.parent;
|
||||
}
|
||||
return;
|
||||
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
@@ -2105,11 +2082,13 @@ namespace ts {
|
||||
case SyntaxKind.SetAccessor:
|
||||
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes);
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
return bindFunctionOrConstructorType(<SignatureDeclaration>node);
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
case SyntaxKind.MappedType:
|
||||
return bindAnonymousTypeWorker(node as TypeLiteralNode | MappedTypeNode);
|
||||
return bindAnonymousTypeWorker(node as TypeLiteralNode | MappedTypeNode | JSDocTypeLiteral);
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
return bindObjectLiteralExpression(<ObjectLiteralExpression>node);
|
||||
case SyntaxKind.FunctionExpression:
|
||||
@@ -2136,7 +2115,6 @@ namespace ts {
|
||||
return bindEnumDeclaration(<EnumDeclaration>node);
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
return bindModuleDeclaration(<ModuleDeclaration>node);
|
||||
|
||||
// Jsx-attributes
|
||||
case SyntaxKind.JsxAttributes:
|
||||
return bindJsxAttributes(<JsxAttributes>node);
|
||||
@@ -2168,25 +2146,17 @@ namespace ts {
|
||||
case SyntaxKind.ModuleBlock:
|
||||
return updateStrictModeStatementList((<Block | ModuleBlock>node).statements);
|
||||
|
||||
default:
|
||||
if (isInJavaScriptFile(node)) return bindJSDocWorker(node);
|
||||
}
|
||||
}
|
||||
|
||||
function bindJSDocWorker(node: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.JSDocRecordMember:
|
||||
return bindPropertyWorker(node as JSDocRecordMember);
|
||||
case SyntaxKind.JSDocParameterTag:
|
||||
if (node.parent.kind !== SyntaxKind.JSDocTypeLiteral) {
|
||||
break;
|
||||
}
|
||||
// falls through
|
||||
case SyntaxKind.JSDocPropertyTag:
|
||||
return declareSymbolAndAddToSymbolTable(node as JSDocPropertyTag,
|
||||
(node as JSDocPropertyTag).isBracketed || ((node as JSDocPropertyTag).typeExpression && (node as JSDocPropertyTag).typeExpression.type.kind === SyntaxKind.JSDocOptionalType) ?
|
||||
SymbolFlags.Property | SymbolFlags.Optional : SymbolFlags.Property,
|
||||
SymbolFlags.PropertyExcludes);
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
return bindFunctionOrConstructorType(<SignatureDeclaration>node);
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
case SyntaxKind.JSDocRecordType:
|
||||
return bindAnonymousTypeWorker(node as JSDocTypeLiteral | JSDocRecordType);
|
||||
const propTag = node as JSDocPropertyLikeTag;
|
||||
const flags = propTag.isBracketed || propTag.typeExpression.type.kind === SyntaxKind.JSDocOptionalType ?
|
||||
SymbolFlags.Property | SymbolFlags.Optional :
|
||||
SymbolFlags.Property;
|
||||
return declareSymbolAndAddToSymbolTable(propTag, flags, SymbolFlags.PropertyExcludes);
|
||||
case SyntaxKind.JSDocTypedefTag: {
|
||||
const { fullName } = node as JSDocTypedefTag;
|
||||
if (!fullName || fullName.kind === SyntaxKind.Identifier) {
|
||||
@@ -2201,8 +2171,8 @@ namespace ts {
|
||||
return bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property | (node.questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes);
|
||||
}
|
||||
|
||||
function bindAnonymousTypeWorker(node: TypeLiteralNode | MappedTypeNode | JSDocTypeLiteral | JSDocRecordType) {
|
||||
return bindAnonymousDeclaration(<Declaration>node, SymbolFlags.TypeLiteral, "__type");
|
||||
function bindAnonymousTypeWorker(node: TypeLiteralNode | MappedTypeNode | JSDocTypeLiteral) {
|
||||
return bindAnonymousDeclaration(<Declaration>node, SymbolFlags.TypeLiteral, InternalSymbolName.Type);
|
||||
}
|
||||
|
||||
function checkTypePredicate(node: TypePredicateNode) {
|
||||
@@ -2224,7 +2194,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function bindSourceFileAsExternalModule() {
|
||||
bindAnonymousDeclaration(file, SymbolFlags.ValueModule, `"${removeFileExtension(file.fileName)}"`);
|
||||
bindAnonymousDeclaration(file, SymbolFlags.ValueModule, `"${removeFileExtension(file.fileName)}"` as __String);
|
||||
}
|
||||
|
||||
function bindExportAssignment(node: ExportAssignment | BinaryExpression) {
|
||||
@@ -2268,7 +2238,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
file.symbol.globalExports = file.symbol.globalExports || createMap<Symbol>();
|
||||
file.symbol.globalExports = file.symbol.globalExports || createSymbolTable();
|
||||
declareSymbol(file.symbol.globalExports, file.symbol, node, SymbolFlags.Alias, SymbolFlags.AliasExcludes);
|
||||
}
|
||||
|
||||
@@ -2302,7 +2272,7 @@ namespace ts {
|
||||
// When we create a property via 'exports.foo = bar', the 'exports.foo' property access
|
||||
// expression is the declaration
|
||||
setCommonJsModuleIndicator(node);
|
||||
declareSymbol(file.symbol.exports, file.symbol, <PropertyAccessExpression>node.left, SymbolFlags.Property | SymbolFlags.Export, SymbolFlags.None);
|
||||
declareSymbol(file.symbol.exports, file.symbol, <PropertyAccessExpression>node.left, SymbolFlags.Property | SymbolFlags.ExportValue, SymbolFlags.None);
|
||||
}
|
||||
|
||||
function isExportsOrModuleExportsOrAlias(node: Node): boolean {
|
||||
@@ -2312,21 +2282,17 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isNameOfExportsOrModuleExportsAliasDeclaration(node: Node) {
|
||||
if (node.kind === SyntaxKind.Identifier) {
|
||||
const symbol = lookupSymbolForName((<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);
|
||||
}
|
||||
}
|
||||
if (isIdentifier(node)) {
|
||||
const symbol = lookupSymbolForName(node.escapedText);
|
||||
return symbol && symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) &&
|
||||
symbol.valueDeclaration.initializer && isExportsOrModuleExportsOrAliasOrAssignment(symbol.valueDeclaration.initializer);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isExportsOrModuleExportsOrAliasOrAssignemnt(node: Node): boolean {
|
||||
function isExportsOrModuleExportsOrAliasOrAssignment(node: Node): boolean {
|
||||
return isExportsOrModuleExportsOrAlias(node) ||
|
||||
(isAssignmentExpression(node, /*excludeCompoundAssignements*/ true) && (isExportsOrModuleExportsOrAliasOrAssignemnt(node.left) || isExportsOrModuleExportsOrAliasOrAssignemnt(node.right)));
|
||||
(isAssignmentExpression(node, /*excludeCompoundAssignements*/ true) && (isExportsOrModuleExportsOrAliasOrAssignment(node.left) || isExportsOrModuleExportsOrAliasOrAssignment(node.right)));
|
||||
}
|
||||
|
||||
function bindModuleExportsAssignment(node: BinaryExpression) {
|
||||
@@ -2343,7 +2309,7 @@ namespace ts {
|
||||
|
||||
// 'module.exports = expr' assignment
|
||||
setCommonJsModuleIndicator(node);
|
||||
declareSymbol(file.symbol.exports, file.symbol, node, SymbolFlags.Property | SymbolFlags.Export | SymbolFlags.ValueModule, SymbolFlags.None);
|
||||
declareSymbol(file.symbol.exports, file.symbol, node, SymbolFlags.Property | SymbolFlags.ExportValue | SymbolFlags.ValueModule, SymbolFlags.None);
|
||||
}
|
||||
|
||||
function bindThisPropertyAssignment(node: BinaryExpression) {
|
||||
@@ -2353,7 +2319,7 @@ namespace ts {
|
||||
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>();
|
||||
container.symbol.members = container.symbol.members || createSymbolTable();
|
||||
// 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;
|
||||
@@ -2366,11 +2332,8 @@ namespace ts {
|
||||
// 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;
|
||||
}
|
||||
const symbolTable = hasModifier(container, ModifierFlags.Static) ? containingClass.symbol.exports : containingClass.symbol.members;
|
||||
declareSymbol(symbolTable, containingClass.symbol, node, SymbolFlags.Property, SymbolFlags.None, /*isReplaceableByMethod*/ true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2389,7 +2352,7 @@ namespace ts {
|
||||
constructorFunction.parent = classPrototype;
|
||||
classPrototype.parent = leftSideOfAssignment;
|
||||
|
||||
bindPropertyAssignment(constructorFunction.text, leftSideOfAssignment, /*isPrototypeProperty*/ true);
|
||||
bindPropertyAssignment(constructorFunction.escapedText, leftSideOfAssignment, /*isPrototypeProperty*/ true);
|
||||
}
|
||||
|
||||
function bindStaticPropertyAssignment(node: BinaryExpression) {
|
||||
@@ -2411,15 +2374,15 @@ namespace ts {
|
||||
bindExportsPropertyAssignment(node);
|
||||
}
|
||||
else {
|
||||
bindPropertyAssignment(target.text, leftSideOfAssignment, /*isPrototypeProperty*/ false);
|
||||
bindPropertyAssignment(target.escapedText, leftSideOfAssignment, /*isPrototypeProperty*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
function lookupSymbolForName(name: string) {
|
||||
function lookupSymbolForName(name: __String) {
|
||||
return (container.symbol && container.symbol.exports && container.symbol.exports.get(name)) || (container.locals && container.locals.get(name));
|
||||
}
|
||||
|
||||
function bindPropertyAssignment(functionName: string, propertyAccessExpression: PropertyAccessExpression, isPrototypeProperty: boolean) {
|
||||
function bindPropertyAssignment(functionName: __String, propertyAccessExpression: PropertyAccessExpression, isPrototypeProperty: boolean) {
|
||||
let targetSymbol = lookupSymbolForName(functionName);
|
||||
|
||||
if (targetSymbol && isDeclarationOfFunctionOrClassExpression(targetSymbol)) {
|
||||
@@ -2432,8 +2395,8 @@ namespace ts {
|
||||
|
||||
// Set up the members collection if it doesn't exist already
|
||||
const symbolTable = isPrototypeProperty ?
|
||||
(targetSymbol.members || (targetSymbol.members = createMap<Symbol>())) :
|
||||
(targetSymbol.exports || (targetSymbol.exports = createMap<Symbol>()));
|
||||
(targetSymbol.members || (targetSymbol.members = createSymbolTable())) :
|
||||
(targetSymbol.exports || (targetSymbol.exports = createSymbolTable()));
|
||||
|
||||
// Declare the method/property
|
||||
declareSymbol(symbolTable, targetSymbol, propertyAccessExpression, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
|
||||
@@ -2452,11 +2415,11 @@ namespace ts {
|
||||
bindBlockScopedDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes);
|
||||
}
|
||||
else {
|
||||
const bindingName = node.name ? node.name.text : "__class";
|
||||
const bindingName = node.name ? node.name.escapedText : InternalSymbolName.Class;
|
||||
bindAnonymousDeclaration(node, SymbolFlags.Class, bindingName);
|
||||
// Add name of class expression into the map for semantic classifier
|
||||
if (node.name) {
|
||||
classifiableNames.set(node.name.text, node.name.text);
|
||||
classifiableNames.set(node.name.escapedText, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2471,15 +2434,15 @@ namespace ts {
|
||||
// Note: we check for this here because this class may be merging into a module. The
|
||||
// module might have an exported variable called 'prototype'. We can't allow that as
|
||||
// that would clash with the built-in 'prototype' for the class.
|
||||
const prototypeSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Prototype, "prototype");
|
||||
const symbolExport = symbol.exports.get(prototypeSymbol.name);
|
||||
const prototypeSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Prototype, "prototype" as __String);
|
||||
const symbolExport = symbol.exports.get(prototypeSymbol.escapedName);
|
||||
if (symbolExport) {
|
||||
if (node.name) {
|
||||
node.name.parent = node;
|
||||
}
|
||||
file.bindDiagnostics.push(createDiagnosticForNode(symbolExport.declarations[0], Diagnostics.Duplicate_identifier_0, prototypeSymbol.name));
|
||||
file.bindDiagnostics.push(createDiagnosticForNode(symbolExport.declarations[0], Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(prototypeSymbol.escapedName)));
|
||||
}
|
||||
symbol.exports.set(prototypeSymbol.name, prototypeSymbol);
|
||||
symbol.exports.set(prototypeSymbol.escapedName, prototypeSymbol);
|
||||
prototypeSymbol.parent = symbol;
|
||||
}
|
||||
|
||||
@@ -2524,7 +2487,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (isBindingPattern(node.name)) {
|
||||
bindAnonymousDeclaration(node, SymbolFlags.FunctionScopedVariable, getDestructuringParameterName(node));
|
||||
bindAnonymousDeclaration(node, SymbolFlags.FunctionScopedVariable, "__" + indexOf(node.parent.parameters, node) as __String);
|
||||
}
|
||||
else {
|
||||
declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes);
|
||||
@@ -2565,7 +2528,7 @@ namespace ts {
|
||||
node.flowNode = currentFlow;
|
||||
}
|
||||
checkStrictModeFunctionName(node);
|
||||
const bindingName = node.name ? node.name.text : "__function";
|
||||
const bindingName = node.name ? node.name.escapedText : InternalSymbolName.Function;
|
||||
return bindAnonymousDeclaration(node, SymbolFlags.Function, bindingName);
|
||||
}
|
||||
|
||||
@@ -2579,7 +2542,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
return hasDynamicName(node)
|
||||
? bindAnonymousDeclaration(node, symbolFlags, "__computed")
|
||||
? bindAnonymousDeclaration(node, symbolFlags, InternalSymbolName.Computed)
|
||||
: declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes);
|
||||
}
|
||||
|
||||
@@ -2804,7 +2767,6 @@ namespace ts {
|
||||
|
||||
function computeParameter(node: ParameterDeclaration, subtreeFlags: TransformFlags) {
|
||||
let transformFlags = subtreeFlags;
|
||||
const modifierFlags = getModifierFlags(node);
|
||||
const name = node.name;
|
||||
const initializer = node.initializer;
|
||||
const dotDotDotToken = node.dotDotDotToken;
|
||||
@@ -2819,7 +2781,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// If a parameter has an accessibility modifier, then it is TypeScript syntax.
|
||||
if (modifierFlags & ModifierFlags.ParameterPropertyModifier) {
|
||||
if (hasModifier(node, ModifierFlags.ParameterPropertyModifier)) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsParameterPropertyAssignments;
|
||||
}
|
||||
|
||||
@@ -2864,9 +2826,8 @@ namespace ts {
|
||||
|
||||
function computeClassDeclaration(node: ClassDeclaration, subtreeFlags: TransformFlags) {
|
||||
let transformFlags: TransformFlags;
|
||||
const modifierFlags = getModifierFlags(node);
|
||||
|
||||
if (modifierFlags & ModifierFlags.Ambient) {
|
||||
if (hasModifier(node, ModifierFlags.Ambient)) {
|
||||
// An ambient declaration is TypeScript syntax.
|
||||
transformFlags = TransformFlags.AssertTypeScript;
|
||||
}
|
||||
@@ -2941,7 +2902,10 @@ namespace ts {
|
||||
function computeCatchClause(node: CatchClause, subtreeFlags: TransformFlags) {
|
||||
let transformFlags = subtreeFlags;
|
||||
|
||||
if (node.variableDeclaration && isBindingPattern(node.variableDeclaration.name)) {
|
||||
if (!node.variableDeclaration) {
|
||||
transformFlags |= TransformFlags.AssertESNext;
|
||||
}
|
||||
else if (isBindingPattern(node.variableDeclaration.name)) {
|
||||
transformFlags |= TransformFlags.AssertES2015;
|
||||
}
|
||||
|
||||
@@ -3207,11 +3171,10 @@ namespace ts {
|
||||
|
||||
function computeVariableStatement(node: VariableStatement, subtreeFlags: TransformFlags) {
|
||||
let transformFlags: TransformFlags;
|
||||
const modifierFlags = getModifierFlags(node);
|
||||
const declarationListTransformFlags = node.declarationList.transformFlags;
|
||||
|
||||
// An ambient declaration is TypeScript syntax.
|
||||
if (modifierFlags & ModifierFlags.Ambient) {
|
||||
if (hasModifier(node, ModifierFlags.Ambient)) {
|
||||
transformFlags = TransformFlags.AssertTypeScript;
|
||||
}
|
||||
else {
|
||||
@@ -3600,4 +3563,13 @@ namespace ts {
|
||||
return TransformFlags.NodeExcludes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* "Binds" JSDoc nodes in TypeScript code.
|
||||
* Since we will never create symbols for JSDoc, we just set parent pointers instead.
|
||||
*/
|
||||
function setParentPointers(parent: Node, child: Node): void {
|
||||
child.parent = parent;
|
||||
forEachChild(child, (childsChild) => setParentPointers(child, childsChild));
|
||||
}
|
||||
}
|
||||
|
||||
+1782
-1435
File diff suppressed because it is too large
Load Diff
+712
-245
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ namespace ts {
|
||||
setWriter(writer: EmitTextWriter): void;
|
||||
emitNodeWithComments(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
|
||||
emitBodyWithDetachedComments(node: Node, detachedRange: TextRange, emitCallback: (node: Node) => void): void;
|
||||
emitTrailingCommentsOfPosition(pos: number): void;
|
||||
emitTrailingCommentsOfPosition(pos: number, prefixSpace?: boolean): void;
|
||||
emitLeadingCommentsOfPosition(pos: number): void;
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function emitTrailingCommentsOfPosition(pos: number) {
|
||||
function emitTrailingCommentsOfPosition(pos: number, prefixSpace?: boolean) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
@@ -315,7 +315,7 @@ namespace ts {
|
||||
performance.mark("beforeEmitTrailingCommentsOfPosition");
|
||||
}
|
||||
|
||||
forEachTrailingCommentToEmit(pos, emitTrailingCommentOfPosition);
|
||||
forEachTrailingCommentToEmit(pos, prefixSpace ? emitTrailingComment : emitTrailingCommentOfPosition);
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.measure("commentTime", "beforeEmitTrailingCommentsOfPosition");
|
||||
@@ -415,17 +415,7 @@ namespace ts {
|
||||
* @return true if the comment is a triple-slash comment else false
|
||||
*/
|
||||
function isTripleSlashComment(commentPos: number, commentEnd: number) {
|
||||
// Verify this is /// comment, but do the regexp match only when we first can find /// in the comment text
|
||||
// so that we don't end up computing comment string and doing match for all // comments
|
||||
if (currentText.charCodeAt(commentPos + 1) === CharacterCodes.slash &&
|
||||
commentPos + 2 < commentEnd &&
|
||||
currentText.charCodeAt(commentPos + 2) === CharacterCodes.slash) {
|
||||
const textSubStr = currentText.substring(commentPos, commentEnd);
|
||||
return textSubStr.match(fullTripleSlashReferencePathRegEx) ||
|
||||
textSubStr.match(fullTripleSlashAMDReferencePathRegEx) ?
|
||||
true : false;
|
||||
}
|
||||
return false;
|
||||
return isRecognizedTripleSlashComment(currentText, commentPos, commentEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
+315
-241
File diff suppressed because it is too large
Load Diff
@@ -211,7 +211,7 @@ namespace ts {
|
||||
decreaseIndent = newWriter.decreaseIndent;
|
||||
}
|
||||
|
||||
function writeAsynchronousModuleElements(nodes: Node[]) {
|
||||
function writeAsynchronousModuleElements(nodes: ReadonlyArray<Node>) {
|
||||
const oldWriter = writer;
|
||||
forEach(nodes, declaration => {
|
||||
let nodeToCheck: Node;
|
||||
@@ -335,9 +335,12 @@ namespace ts {
|
||||
write(": ");
|
||||
|
||||
// use the checker's type, not the declared type,
|
||||
// for non-optional initialized parameters that aren't a parameter property
|
||||
// for optional parameter properties
|
||||
// and also for non-optional initialized parameters that aren't a parameter property
|
||||
// these types may need to add `undefined`.
|
||||
const shouldUseResolverType = declaration.kind === SyntaxKind.Parameter &&
|
||||
resolver.isRequiredInitializedParameter(declaration as ParameterDeclaration);
|
||||
(resolver.isRequiredInitializedParameter(declaration as ParameterDeclaration) ||
|
||||
resolver.isOptionalUninitializedParameterProperty(declaration as ParameterDeclaration));
|
||||
if (type && !shouldUseResolverType) {
|
||||
// Write the type
|
||||
emitType(type);
|
||||
@@ -346,7 +349,6 @@ namespace ts {
|
||||
errorNameNode = declaration.name;
|
||||
const format = TypeFormatFlags.UseTypeOfFunction |
|
||||
TypeFormatFlags.WriteClassExpressionAsTypeLiteral |
|
||||
TypeFormatFlags.UseTypeAliasValue |
|
||||
(shouldUseResolverType ? TypeFormatFlags.AddUndefined : 0);
|
||||
resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, format, writer);
|
||||
errorNameNode = undefined;
|
||||
@@ -365,19 +367,19 @@ namespace ts {
|
||||
resolver.writeReturnTypeOfSignatureDeclaration(
|
||||
signature,
|
||||
enclosingDeclaration,
|
||||
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
|
||||
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
|
||||
writer);
|
||||
errorNameNode = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function emitLines(nodes: Node[]) {
|
||||
function emitLines(nodes: ReadonlyArray<Node>) {
|
||||
for (const node of nodes) {
|
||||
emit(node);
|
||||
}
|
||||
}
|
||||
|
||||
function emitSeparatedList(nodes: Node[], separator: string, eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) {
|
||||
function emitSeparatedList(nodes: ReadonlyArray<Node>, separator: string, eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) {
|
||||
let currentWriterPos = writer.getTextPos();
|
||||
for (const node of nodes) {
|
||||
if (!canEmitFn || canEmitFn(node)) {
|
||||
@@ -390,7 +392,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function emitCommaList(nodes: Node[], eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) {
|
||||
function emitCommaList(nodes: ReadonlyArray<Node>, eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) {
|
||||
emitSeparatedList(nodes, ", ", eachNodeEmitFn, canEmitFn);
|
||||
}
|
||||
|
||||
@@ -596,7 +598,7 @@ namespace ts {
|
||||
currentIdentifiers = node.identifiers;
|
||||
isCurrentFileExternalModule = isExternalModule(node);
|
||||
enclosingDeclaration = node;
|
||||
emitDetachedComments(currentText, currentLineMap, writer, writeCommentRange, node, newLine, /*removeComents*/ true);
|
||||
emitDetachedComments(currentText, currentLineMap, writer, writeCommentRange, node, newLine, /*removeComments*/ true);
|
||||
emitLines(node.statements);
|
||||
}
|
||||
|
||||
@@ -630,7 +632,7 @@ namespace ts {
|
||||
resolver.writeTypeOfExpression(
|
||||
expr,
|
||||
enclosingDeclaration,
|
||||
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
|
||||
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
|
||||
writer);
|
||||
write(";");
|
||||
writeLine();
|
||||
@@ -1004,7 +1006,7 @@ namespace ts {
|
||||
return node.parent.kind === SyntaxKind.MethodDeclaration && hasModifier(node.parent, ModifierFlags.Private);
|
||||
}
|
||||
|
||||
function emitTypeParameters(typeParameters: TypeParameterDeclaration[]) {
|
||||
function emitTypeParameters(typeParameters: ReadonlyArray<TypeParameterDeclaration>) {
|
||||
function emitTypeParameter(node: TypeParameterDeclaration) {
|
||||
increaseIndent();
|
||||
emitJsDocComments(node);
|
||||
@@ -1106,7 +1108,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function emitHeritageClause(typeReferences: ExpressionWithTypeArguments[], isImplementsList: boolean) {
|
||||
function emitHeritageClause(typeReferences: ReadonlyArray<ExpressionWithTypeArguments>, isImplementsList: boolean) {
|
||||
if (typeReferences) {
|
||||
write(isImplementsList ? " implements " : " extends ");
|
||||
emitCommaList(typeReferences, emitTypeOfTypeReference);
|
||||
@@ -1161,7 +1163,7 @@ namespace ts {
|
||||
if (baseTypeNode && !isEntityNameExpression(baseTypeNode.expression)) {
|
||||
tempVarName = baseTypeNode.expression.kind === SyntaxKind.NullKeyword ?
|
||||
"null" :
|
||||
emitTempVariableDeclaration(baseTypeNode.expression, `${node.name.text}_base`, {
|
||||
emitTempVariableDeclaration(baseTypeNode.expression, `${node.name.escapedText}_base`, {
|
||||
diagnosticMessage: Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1,
|
||||
errorNode: baseTypeNode,
|
||||
typeName: node.name
|
||||
@@ -1364,6 +1366,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
function writeVariableStatement(node: VariableStatement) {
|
||||
// If binding pattern doesn't have name, then there is nothing to be emitted for declaration file i.e. const [,] = [1,2].
|
||||
if (every(node.declarationList && node.declarationList.declarations, decl => decl.name && isEmptyBindingPattern(decl.name))) {
|
||||
return;
|
||||
}
|
||||
emitJsDocComments(node);
|
||||
emitModuleElementDeclarationFlags(node);
|
||||
if (isLet(node.declarationList)) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
{
|
||||
"Unterminated string literal.": {
|
||||
"category": "Error",
|
||||
"code": 1002
|
||||
@@ -707,7 +707,7 @@
|
||||
"category": "Error",
|
||||
"code": 1223
|
||||
},
|
||||
"Signature '{0}' must have a type predicate.": {
|
||||
"Signature '{0}' must be a type predicate.": {
|
||||
"category": "Error",
|
||||
"code": 1224
|
||||
},
|
||||
@@ -899,6 +899,14 @@
|
||||
"category": "Error",
|
||||
"code": 1326
|
||||
},
|
||||
"String literal with double quotes expected.": {
|
||||
"category": "Error",
|
||||
"code": 1327
|
||||
},
|
||||
"Property value can only be string literal, numeric literal, 'true', 'false', 'null', object literal or array literal.": {
|
||||
"category": "Error",
|
||||
"code": 1328
|
||||
},
|
||||
|
||||
"Duplicate identifier '{0}'.": {
|
||||
"category": "Error",
|
||||
@@ -1900,6 +1908,18 @@
|
||||
"category": "Error",
|
||||
"code": 2559
|
||||
},
|
||||
"Value of type '{0}' has no properties in common with type '{1}'. Did you mean to call it?": {
|
||||
"category": "Error",
|
||||
"code": 2560
|
||||
},
|
||||
"Object literal may only specify known properties, but '{0}' does not exist in type '{1}'. Did you mean to write '{2}'?": {
|
||||
"category": "Error",
|
||||
"code": 2561
|
||||
},
|
||||
"Base class expressions cannot reference class type parameters.": {
|
||||
"category": "Error",
|
||||
"code": 2562
|
||||
},
|
||||
"JSX element attributes type '{0}' may not be a union type.": {
|
||||
"category": "Error",
|
||||
"code": 2600
|
||||
@@ -2056,7 +2076,7 @@
|
||||
"category": "Error",
|
||||
"code": 2679
|
||||
},
|
||||
"A 'this' parameter must be the first parameter.": {
|
||||
"A '{0}' parameter must be the first parameter.": {
|
||||
"category": "Error",
|
||||
"code": 2680
|
||||
},
|
||||
@@ -2184,6 +2204,10 @@
|
||||
"category": "Error",
|
||||
"code": 2712
|
||||
},
|
||||
"Cannot access '{0}.{1}' because '{0}' is a type, but not a namespace. Did you mean to retrieve the type of the property '{1}' in '{0}' with '{0}[\"{1}\"]'?": {
|
||||
"category": "Error",
|
||||
"code": 2713
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
@@ -2646,11 +2670,15 @@
|
||||
"category": "Message",
|
||||
"code": 6012
|
||||
},
|
||||
"Do not resolve the real path of symlinks.": {
|
||||
"category": "Message",
|
||||
"code": 6013
|
||||
},
|
||||
"Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'.": {
|
||||
"category": "Message",
|
||||
"code": 6015
|
||||
},
|
||||
"Specify module code generation: 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.": {
|
||||
"Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.": {
|
||||
"category": "Message",
|
||||
"code": 6016
|
||||
},
|
||||
@@ -3278,6 +3306,10 @@
|
||||
"category": "Message",
|
||||
"code": 6184
|
||||
},
|
||||
"Disable strict checking of generic signatures in function types.": {
|
||||
"category": "Message",
|
||||
"code": 6185
|
||||
},
|
||||
"Variable '{0}' implicitly has an '{1}' type.": {
|
||||
"category": "Error",
|
||||
"code": 7005
|
||||
@@ -3443,6 +3475,10 @@
|
||||
"category": "Error",
|
||||
"code": 8012
|
||||
},
|
||||
"'non-null assertions' can only be used in a .ts file.": {
|
||||
"category": "Error",
|
||||
"code": 8013
|
||||
},
|
||||
"'enum declarations' can only be used in a .ts file.": {
|
||||
"category": "Error",
|
||||
"code": 8015
|
||||
@@ -3451,6 +3487,22 @@
|
||||
"category": "Error",
|
||||
"code": 8016
|
||||
},
|
||||
"Octal literal types must use ES2015 syntax. Use the syntax '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 8017
|
||||
},
|
||||
"Octal literals are not allowed in enums members initializer. Use the syntax '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 8018
|
||||
},
|
||||
"Report errors in .js files.": {
|
||||
"category": "Message",
|
||||
"code": 8019
|
||||
},
|
||||
"JSDoc types can only be used inside documentation comments.": {
|
||||
"category": "Error",
|
||||
"code": 8020
|
||||
},
|
||||
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clause.": {
|
||||
"category": "Error",
|
||||
"code": 9002
|
||||
@@ -3621,7 +3673,15 @@
|
||||
"category": "Message",
|
||||
"code": 90024
|
||||
},
|
||||
|
||||
"Prefix '{0}' with an underscore.": {
|
||||
"category": "Message",
|
||||
"code": 90025
|
||||
},
|
||||
"Rewrite as the indexed access type '{0}'.": {
|
||||
"category": "Message",
|
||||
"code": 90026
|
||||
},
|
||||
|
||||
"Convert function to an ES2015 class": {
|
||||
"category": "Message",
|
||||
"code": 95001
|
||||
@@ -3631,16 +3691,13 @@
|
||||
"code": 95002
|
||||
},
|
||||
|
||||
"Octal literal types must use ES2015 syntax. Use the syntax '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 8017
|
||||
},
|
||||
"Octal literals are not allowed in enums members initializer. Use the syntax '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 8018
|
||||
},
|
||||
"Report errors in .js files.": {
|
||||
"Extract function": {
|
||||
"category": "Message",
|
||||
"code": 8019
|
||||
"code": 95003
|
||||
},
|
||||
|
||||
"Extract function into '{0}'": {
|
||||
"category": "Message",
|
||||
"code": 95004
|
||||
}
|
||||
}
|
||||
|
||||
+101
-19
@@ -8,6 +8,70 @@ namespace ts {
|
||||
const delimiters = createDelimiterMap();
|
||||
const brackets = createBracketsMap();
|
||||
|
||||
/*@internal*/
|
||||
/**
|
||||
* Iterates over the source files that are expected to have an emit output.
|
||||
*
|
||||
* @param host An EmitHost.
|
||||
* @param action The action to execute.
|
||||
* @param sourceFilesOrTargetSourceFile
|
||||
* If an array, the full list of source files to emit.
|
||||
* Else, calls `getSourceFilesToEmit` with the (optional) target source file to determine the list of source files to emit.
|
||||
*/
|
||||
export function forEachEmittedFile(
|
||||
host: EmitHost, action: (emitFileNames: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle, emitOnlyDtsFiles: boolean) => void,
|
||||
sourceFilesOrTargetSourceFile?: SourceFile[] | SourceFile,
|
||||
emitOnlyDtsFiles?: boolean) {
|
||||
|
||||
const sourceFiles = isArray(sourceFilesOrTargetSourceFile) ? sourceFilesOrTargetSourceFile : getSourceFilesToEmit(host, sourceFilesOrTargetSourceFile);
|
||||
const options = host.getCompilerOptions();
|
||||
if (options.outFile || options.out) {
|
||||
if (sourceFiles.length) {
|
||||
const jsFilePath = options.outFile || options.out;
|
||||
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
|
||||
const declarationFilePath = options.declaration ? removeFileExtension(jsFilePath) + Extension.Dts : "";
|
||||
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, createBundle(sourceFiles), emitOnlyDtsFiles);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const sourceFile of sourceFiles) {
|
||||
const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, getOutputExtension(sourceFile, options));
|
||||
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
|
||||
const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (emitOnlyDtsFiles || options.declaration) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
|
||||
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, sourceFile, emitOnlyDtsFiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getSourceMapFilePath(jsFilePath: string, options: CompilerOptions) {
|
||||
return options.sourceMap ? jsFilePath + ".map" : undefined;
|
||||
}
|
||||
|
||||
// JavaScript files are always LanguageVariant.JSX, as JSX syntax is allowed in .js files also.
|
||||
// So for JavaScript files, '.jsx' is only emitted if the input was '.jsx', and JsxEmit.Preserve.
|
||||
// For TypeScript, the only time to emit with a '.jsx' extension, is on JSX input, and JsxEmit.Preserve
|
||||
function getOutputExtension(sourceFile: SourceFile, options: CompilerOptions): Extension {
|
||||
if (options.jsx === JsxEmit.Preserve) {
|
||||
if (isSourceFileJavaScript(sourceFile)) {
|
||||
if (fileExtensionIs(sourceFile.fileName, Extension.Jsx)) {
|
||||
return Extension.Jsx;
|
||||
}
|
||||
}
|
||||
else if (sourceFile.languageVariant === LanguageVariant.JSX) {
|
||||
// TypeScript source file preserving JSX syntax
|
||||
return Extension.Jsx;
|
||||
}
|
||||
}
|
||||
return Extension.Js;
|
||||
}
|
||||
|
||||
function getOriginalSourceFileOrBundle(sourceFileOrBundle: SourceFile | Bundle) {
|
||||
if (sourceFileOrBundle.kind === SyntaxKind.Bundle) {
|
||||
return updateBundle(sourceFileOrBundle, sameMap(sourceFileOrBundle.sourceFiles, getOriginalSourceFile));
|
||||
}
|
||||
return getOriginalSourceFile(sourceFileOrBundle);
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
|
||||
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile, emitOnlyDtsFiles?: boolean, transformers?: TransformerFactory<SourceFile>[]): EmitResult {
|
||||
@@ -217,7 +281,7 @@ namespace ts {
|
||||
let currentSourceFile: SourceFile | undefined;
|
||||
let nodeIdToGeneratedName: string[]; // Map of generated names for specific nodes.
|
||||
let autoGeneratedIdToGeneratedName: string[]; // Map of generated names for temp and loop variables.
|
||||
let generatedNames: Map<string>; // Set of names generated by the NameGenerator.
|
||||
let generatedNames: Map<true>; // Set of names generated by the NameGenerator.
|
||||
let tempFlagsStack: TempFlags[]; // Stack of enclosing name generation scopes.
|
||||
let tempFlags: TempFlags; // TempFlags for the current name generation scope.
|
||||
let writer: EmitTextWriter;
|
||||
@@ -335,7 +399,7 @@ namespace ts {
|
||||
function reset() {
|
||||
nodeIdToGeneratedName = [];
|
||||
autoGeneratedIdToGeneratedName = [];
|
||||
generatedNames = createMap<string>();
|
||||
generatedNames = createMap<true>();
|
||||
tempFlagsStack = [];
|
||||
tempFlags = TempFlags.Auto;
|
||||
comments.reset();
|
||||
@@ -1131,7 +1195,9 @@ namespace ts {
|
||||
if (!(getEmitFlags(node) & EmitFlags.NoIndentation)) {
|
||||
const dotRangeStart = node.expression.end;
|
||||
const dotRangeEnd = skipTrivia(currentSourceFile.text, node.expression.end) + 1;
|
||||
const dotToken = <Node>{ kind: SyntaxKind.DotToken, pos: dotRangeStart, end: dotRangeEnd };
|
||||
const dotToken = createToken(SyntaxKind.DotToken);
|
||||
dotToken.pos = dotRangeStart;
|
||||
dotToken.end = dotRangeEnd;
|
||||
indentBeforeDot = needsIndentation(node, node.expression, dotToken);
|
||||
indentAfterDot = needsIndentation(node, dotToken, node.name);
|
||||
}
|
||||
@@ -1282,7 +1348,9 @@ namespace ts {
|
||||
|
||||
emitExpression(node.left);
|
||||
increaseIndentIf(indentBeforeOperator, isCommaOperator ? " " : undefined);
|
||||
emitLeadingCommentsOfPosition(node.operatorToken.pos);
|
||||
writeTokenNode(node.operatorToken);
|
||||
emitTrailingCommentsOfPosition(node.operatorToken.end, /*prefixSpace*/ true); // Binary operators should have a space before the comment starts
|
||||
increaseIndentIf(indentAfterOperator, " ");
|
||||
emitExpression(node.right);
|
||||
decreaseIndentIf(indentBeforeOperator, indentAfterOperator);
|
||||
@@ -1506,8 +1574,20 @@ namespace ts {
|
||||
write(";");
|
||||
}
|
||||
|
||||
function emitTokenWithComment(token: SyntaxKind, pos: number, contextNode?: Node) {
|
||||
const node = contextNode && getParseTreeNode(contextNode);
|
||||
if (node && node.kind === contextNode.kind) {
|
||||
pos = skipTrivia(currentSourceFile.text, pos);
|
||||
}
|
||||
pos = writeToken(token, pos, /*contextNode*/ contextNode);
|
||||
if (node && node.kind === contextNode.kind) {
|
||||
emitTrailingCommentsOfPosition(pos, /*prefixSpace*/ true);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
function emitReturnStatement(node: ReturnStatement) {
|
||||
writeToken(SyntaxKind.ReturnKeyword, node.pos, /*contextNode*/ node);
|
||||
emitTokenWithComment(SyntaxKind.ReturnKeyword, node.pos, /*contextNode*/ node);
|
||||
emitExpressionWithPrefix(" ", node.expression);
|
||||
write(";");
|
||||
}
|
||||
@@ -2067,10 +2147,12 @@ namespace ts {
|
||||
function emitCatchClause(node: CatchClause) {
|
||||
const openParenPos = writeToken(SyntaxKind.CatchKeyword, node.pos);
|
||||
write(" ");
|
||||
writeToken(SyntaxKind.OpenParenToken, openParenPos);
|
||||
emit(node.variableDeclaration);
|
||||
writeToken(SyntaxKind.CloseParenToken, node.variableDeclaration ? node.variableDeclaration.end : openParenPos);
|
||||
write(" ");
|
||||
if (node.variableDeclaration) {
|
||||
writeToken(SyntaxKind.OpenParenToken, openParenPos);
|
||||
emit(node.variableDeclaration);
|
||||
writeToken(SyntaxKind.CloseParenToken, node.variableDeclaration.end);
|
||||
write(" ");
|
||||
}
|
||||
emit(node.block);
|
||||
}
|
||||
|
||||
@@ -2164,7 +2246,7 @@ namespace ts {
|
||||
* Emits any prologue directives at the start of a Statement list, returning the
|
||||
* number of prologue directives written to the output.
|
||||
*/
|
||||
function emitPrologueDirectives(statements: Node[], startWithNewLine?: boolean, seenPrologueDirectives?: Map<String>): number {
|
||||
function emitPrologueDirectives(statements: ReadonlyArray<Node>, startWithNewLine?: boolean, seenPrologueDirectives?: Map<true>): number {
|
||||
for (let i = 0; i < statements.length; i++) {
|
||||
const statement = statements[i];
|
||||
if (isPrologueDirective(statement)) {
|
||||
@@ -2175,7 +2257,7 @@ namespace ts {
|
||||
}
|
||||
emit(statement);
|
||||
if (seenPrologueDirectives) {
|
||||
seenPrologueDirectives.set(statement.expression.text, statement.expression.text);
|
||||
seenPrologueDirectives.set(statement.expression.text, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2194,7 +2276,7 @@ namespace ts {
|
||||
emitPrologueDirectives((sourceFileOrBundle as SourceFile).statements);
|
||||
}
|
||||
else {
|
||||
const seenPrologueDirectives = createMap<String>();
|
||||
const seenPrologueDirectives = createMap<true>();
|
||||
for (const sourceFile of (sourceFileOrBundle as Bundle).sourceFiles) {
|
||||
setSourceFile(sourceFile);
|
||||
emitPrologueDirectives(sourceFile.statements, /*startWithNewLine*/ true, seenPrologueDirectives);
|
||||
@@ -2697,7 +2779,7 @@ namespace ts {
|
||||
return generateName(node);
|
||||
}
|
||||
else if (isIdentifier(node) && (nodeIsSynthesized(node) || !node.parent)) {
|
||||
return unescapeIdentifier(node.text);
|
||||
return unescapeLeadingUnderscores(node.escapedText);
|
||||
}
|
||||
else if (node.kind === SyntaxKind.StringLiteral && (<StringLiteral>node).textSourceNode) {
|
||||
return getTextOfNode((<StringLiteral>node).textSourceNode, includeTrivia);
|
||||
@@ -2754,13 +2836,13 @@ namespace ts {
|
||||
// Auto, Loop, and Unique names are cached based on their unique
|
||||
// autoGenerateId.
|
||||
const autoGenerateId = name.autoGenerateId;
|
||||
return autoGeneratedIdToGeneratedName[autoGenerateId] || (autoGeneratedIdToGeneratedName[autoGenerateId] = unescapeIdentifier(makeName(name)));
|
||||
return autoGeneratedIdToGeneratedName[autoGenerateId] || (autoGeneratedIdToGeneratedName[autoGenerateId] = makeName(name));
|
||||
}
|
||||
}
|
||||
|
||||
function generateNameCached(node: Node) {
|
||||
const nodeId = getNodeId(node);
|
||||
return nodeIdToGeneratedName[nodeId] || (nodeIdToGeneratedName[nodeId] = unescapeIdentifier(generateNameForNode(node)));
|
||||
return nodeIdToGeneratedName[nodeId] || (nodeIdToGeneratedName[nodeId] = generateNameForNode(node));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2779,7 +2861,7 @@ namespace ts {
|
||||
function isUniqueLocalName(name: string, container: Node): boolean {
|
||||
for (let node = container; isNodeDescendantOf(node, container); node = node.nextContainer) {
|
||||
if (node.locals) {
|
||||
const local = node.locals.get(name);
|
||||
const local = node.locals.get(escapeLeadingUnderscores(name));
|
||||
// We conservatively include alias symbols to cover cases where they're emitted as locals
|
||||
if (local && local.flags & (SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias)) {
|
||||
return false;
|
||||
@@ -2832,7 +2914,7 @@ namespace ts {
|
||||
while (true) {
|
||||
const generatedName = baseName + i;
|
||||
if (isUniqueName(generatedName)) {
|
||||
generatedNames.set(generatedName, generatedName);
|
||||
generatedNames.set(generatedName, true);
|
||||
return generatedName;
|
||||
}
|
||||
i++;
|
||||
@@ -2853,8 +2935,8 @@ namespace ts {
|
||||
*/
|
||||
function generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) {
|
||||
const expr = getExternalModuleName(node);
|
||||
const baseName = expr.kind === SyntaxKind.StringLiteral ?
|
||||
escapeIdentifier(makeIdentifierFromModuleName((<LiteralExpression>expr).text)) : "module";
|
||||
const baseName = isStringLiteral(expr) ?
|
||||
makeIdentifierFromModuleName(expr.text) : "module";
|
||||
return makeUniqueName(baseName);
|
||||
}
|
||||
|
||||
@@ -2917,7 +2999,7 @@ namespace ts {
|
||||
case GeneratedIdentifierKind.Loop:
|
||||
return makeTempVariableName(TempFlags._i);
|
||||
case GeneratedIdentifierKind.Unique:
|
||||
return makeUniqueName(unescapeIdentifier(name.text));
|
||||
return makeUniqueName(unescapeLeadingUnderscores(name.escapedText));
|
||||
}
|
||||
|
||||
Debug.fail("Unsupported GeneratedIdentifierKind.");
|
||||
|
||||
+352
-314
File diff suppressed because it is too large
Load Diff
@@ -19,13 +19,26 @@ namespace ts {
|
||||
push(value: T): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of trying to resolve a module.
|
||||
* At least one of `ts` and `js` should be defined, or the whole thing should be `undefined`.
|
||||
*/
|
||||
function withPackageId(packageId: PackageId | undefined, r: PathAndExtension | undefined): Resolved {
|
||||
return r && { path: r.path, extension: r.ext, packageId };
|
||||
}
|
||||
|
||||
function noPackageId(r: PathAndExtension | undefined): Resolved {
|
||||
return withPackageId(/*packageId*/ undefined, r);
|
||||
}
|
||||
|
||||
/** Result of trying to resolve a module. */
|
||||
interface Resolved {
|
||||
path: string;
|
||||
extension: Extension;
|
||||
packageId: PackageId | undefined;
|
||||
}
|
||||
|
||||
/** Result of trying to resolve a module at a file. Needs to have 'packageId' added later. */
|
||||
interface PathAndExtension {
|
||||
path: string;
|
||||
// (Use a different name than `extension` to make sure Resolved isn't assignable to PathAndExtension.)
|
||||
ext: Extension;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,24 +62,27 @@ namespace ts {
|
||||
|
||||
function createResolvedModuleWithFailedLookupLocations(resolved: Resolved | undefined, isExternalLibraryImport: boolean, failedLookupLocations: string[]): ResolvedModuleWithFailedLookupLocations {
|
||||
return {
|
||||
resolvedModule: resolved && { resolvedFileName: resolved.path, extension: resolved.extension, isExternalLibraryImport },
|
||||
resolvedModule: resolved && { resolvedFileName: resolved.path, extension: resolved.extension, isExternalLibraryImport, packageId: resolved.packageId },
|
||||
failedLookupLocations
|
||||
};
|
||||
}
|
||||
|
||||
export function moduleHasNonRelativeName(moduleName: string): boolean {
|
||||
return !(isRootedDiskPath(moduleName) || isExternalModuleNameRelative(moduleName));
|
||||
}
|
||||
|
||||
interface ModuleResolutionState {
|
||||
host: ModuleResolutionHost;
|
||||
compilerOptions: CompilerOptions;
|
||||
traceEnabled: boolean;
|
||||
}
|
||||
|
||||
interface PackageJson {
|
||||
name?: string;
|
||||
version?: string;
|
||||
typings?: string;
|
||||
types?: string;
|
||||
main?: string;
|
||||
}
|
||||
|
||||
/** Reads from "main" or "types"/"typings" depending on `extensions`. */
|
||||
function tryReadPackageJsonFields(readTypes: boolean, packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string | undefined {
|
||||
const jsonContent = readJson(packageJsonPath, state.host);
|
||||
function tryReadPackageJsonFields(readTypes: boolean, jsonContent: PackageJson, baseDirectory: string, state: ModuleResolutionState): string | undefined {
|
||||
return readTypes ? tryReadFromField("typings") || tryReadFromField("types") : tryReadFromField("main");
|
||||
|
||||
function tryReadFromField(fieldName: "typings" | "types" | "main"): string | undefined {
|
||||
@@ -93,7 +109,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function readJson(path: string, host: ModuleResolutionHost): { typings?: string, types?: string, main?: string } {
|
||||
function readJson(path: string, host: ModuleResolutionHost): PackageJson {
|
||||
try {
|
||||
const jsonText = host.readFile(path);
|
||||
return jsonText ? JSON.parse(jsonText) : {};
|
||||
@@ -151,11 +167,7 @@ namespace ts {
|
||||
*/
|
||||
export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string, containingFile: string | undefined, options: CompilerOptions, host: ModuleResolutionHost): ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
|
||||
const traceEnabled = isTraceEnabled(options, host);
|
||||
const moduleResolutionState: ModuleResolutionState = {
|
||||
compilerOptions: options,
|
||||
host: host,
|
||||
traceEnabled
|
||||
};
|
||||
const moduleResolutionState: ModuleResolutionState = { compilerOptions: options, host, traceEnabled };
|
||||
|
||||
const typeRoots = getEffectiveTypeRoots(options, host);
|
||||
if (traceEnabled) {
|
||||
@@ -188,7 +200,10 @@ namespace ts {
|
||||
|
||||
let resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined;
|
||||
if (resolved) {
|
||||
resolved = realpath(resolved, host, traceEnabled);
|
||||
if (!options.preserveSymlinks) {
|
||||
resolved = realPath(resolved, host, traceEnabled);
|
||||
}
|
||||
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, resolved, primary);
|
||||
}
|
||||
@@ -270,6 +285,8 @@ namespace ts {
|
||||
for (const typeDirectivePath of host.getDirectories(root)) {
|
||||
const normalized = normalizePath(typeDirectivePath);
|
||||
const packageJsonPath = pathToPackageJson(combinePaths(root, normalized));
|
||||
// `types-publisher` sometimes creates packages with `"typings": null` for packages that don't provide their own types.
|
||||
// See `createNotNeededPackageJSON` in the types-publisher` repo.
|
||||
// tslint:disable-next-line:no-null-keyword
|
||||
const isNotNeededPackage = host.fileExists(packageJsonPath) && readJson(packageJsonPath, host).typings === null;
|
||||
if (!isNotNeededPackage) {
|
||||
@@ -306,7 +323,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function createModuleResolutionCache(currentDirectory: string, getCanonicalFileName: (s: string) => string): ModuleResolutionCache {
|
||||
const directoryToModuleNameMap = createFileMap<Map<ResolvedModuleWithFailedLookupLocations>>();
|
||||
const directoryToModuleNameMap = createMap<Map<ResolvedModuleWithFailedLookupLocations>>();
|
||||
const moduleNameToDirectoryMap = createMap<PerModuleNameCache>();
|
||||
|
||||
return { getOrCreateCacheForDirectory, getOrCreateCacheForModuleName };
|
||||
@@ -322,7 +339,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getOrCreateCacheForModuleName(nonRelativeModuleName: string) {
|
||||
if (!moduleHasNonRelativeName(nonRelativeModuleName)) {
|
||||
if (isExternalModuleNameRelative(nonRelativeModuleName)) {
|
||||
return undefined;
|
||||
}
|
||||
let perModuleNameCache = moduleNameToDirectoryMap.get(nonRelativeModuleName);
|
||||
@@ -334,7 +351,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function createPerModuleNameCache(): PerModuleNameCache {
|
||||
const directoryPathMap = createFileMap<ResolvedModuleWithFailedLookupLocations>();
|
||||
const directoryPathMap = createMap<ResolvedModuleWithFailedLookupLocations>();
|
||||
|
||||
return { get, set };
|
||||
|
||||
@@ -356,7 +373,7 @@ namespace ts {
|
||||
function set(directory: string, result: ResolvedModuleWithFailedLookupLocations): void {
|
||||
const path = toPath(directory, currentDirectory, getCanonicalFileName);
|
||||
// if entry is already in cache do nothing
|
||||
if (directoryPathMap.contains(path)) {
|
||||
if (directoryPathMap.has(path)) {
|
||||
return;
|
||||
}
|
||||
directoryPathMap.set(path, result);
|
||||
@@ -370,7 +387,7 @@ namespace ts {
|
||||
let current = path;
|
||||
while (true) {
|
||||
const parent = getDirectoryPath(current);
|
||||
if (parent === current || directoryPathMap.contains(parent)) {
|
||||
if (parent === current || directoryPathMap.has(parent)) {
|
||||
break;
|
||||
}
|
||||
directoryPathMap.set(parent, result);
|
||||
@@ -539,7 +556,7 @@ namespace ts {
|
||||
function tryLoadModuleUsingOptionalResolutionSettings(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
|
||||
failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
|
||||
|
||||
if (moduleHasNonRelativeName(moduleName)) {
|
||||
if (!isExternalModuleNameRelative(moduleName)) {
|
||||
return tryLoadModuleUsingBaseUrl(extensions, moduleName, loader, failedLookupLocations, state);
|
||||
}
|
||||
else {
|
||||
@@ -658,7 +675,7 @@ namespace ts {
|
||||
if (extension !== undefined) {
|
||||
const path = tryFile(candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state);
|
||||
if (path !== undefined) {
|
||||
return { path, extension };
|
||||
return { path, extension, packageId: undefined };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -690,7 +707,7 @@ namespace ts {
|
||||
const { resolvedModule, failedLookupLocations } =
|
||||
nodeModuleNameResolverWorker(moduleName, initialDir, { moduleResolution: ts.ModuleResolutionKind.NodeJs, allowJs: true }, host, /*cache*/ undefined, /*jsOnly*/ true);
|
||||
if (!resolvedModule) {
|
||||
throw new Error(`Could not resolve JS module ${moduleName} starting at ${initialDir}. Looked in: ${failedLookupLocations.join(", ")}`);
|
||||
throw new Error(`Could not resolve JS module '${moduleName}' starting at '${initialDir}'. Looked in: ${failedLookupLocations.join(", ")}`);
|
||||
}
|
||||
return resolvedModule.resolvedFileName;
|
||||
}
|
||||
@@ -715,23 +732,30 @@ namespace ts {
|
||||
return toSearchResult({ resolved, isExternalLibraryImport: false });
|
||||
}
|
||||
|
||||
if (moduleHasNonRelativeName(moduleName)) {
|
||||
if (!isExternalModuleNameRelative(moduleName)) {
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Loading_module_0_from_node_modules_folder_target_file_type_1, moduleName, Extensions[extensions]);
|
||||
}
|
||||
const resolved = loadModuleFromNodeModules(extensions, moduleName, containingDirectory, failedLookupLocations, state, cache);
|
||||
if (!resolved) return undefined;
|
||||
|
||||
let resolvedValue = resolved.value;
|
||||
if (!compilerOptions.preserveSymlinks) {
|
||||
resolvedValue = resolvedValue && { ...resolved.value, path: realPath(resolved.value.path, host, traceEnabled), extension: resolved.value.extension };
|
||||
}
|
||||
// For node_modules lookups, get the real path so that multiple accesses to an `npm link`-ed module do not create duplicate files.
|
||||
return resolved && { value: resolved.value && { resolved: { path: realpath(resolved.value.path, host, traceEnabled), extension: resolved.value.extension }, isExternalLibraryImport: true } };
|
||||
return { value: resolvedValue && { resolved: resolvedValue, isExternalLibraryImport: true } };
|
||||
}
|
||||
else {
|
||||
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
|
||||
const { path: candidate, parts } = normalizePathAndParts(combinePaths(containingDirectory, moduleName));
|
||||
const resolved = nodeLoadModuleByRelativeName(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state, /*considerPackageJson*/ true);
|
||||
return resolved && toSearchResult({ resolved, isExternalLibraryImport: false });
|
||||
// Treat explicit "node_modules" import as an external library import.
|
||||
return resolved && toSearchResult({ resolved, isExternalLibraryImport: contains(parts, "node_modules") });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function realpath(path: string, host: ModuleResolutionHost, traceEnabled: boolean): string {
|
||||
function realPath(path: string, host: ModuleResolutionHost, traceEnabled: boolean): string {
|
||||
if (!host.realpath) {
|
||||
return path;
|
||||
}
|
||||
@@ -759,7 +783,7 @@ namespace ts {
|
||||
}
|
||||
const resolvedFromFile = loadModuleFromFile(extensions, candidate, failedLookupLocations, onlyRecordFailures, state);
|
||||
if (resolvedFromFile) {
|
||||
return resolvedFromFile;
|
||||
return noPackageId(resolvedFromFile);
|
||||
}
|
||||
}
|
||||
if (!onlyRecordFailures) {
|
||||
@@ -780,11 +804,15 @@ namespace ts {
|
||||
return !host.directoryExists || host.directoryExists(directoryName);
|
||||
}
|
||||
|
||||
function loadModuleFromFileNoPackageId(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved {
|
||||
return noPackageId(loadModuleFromFile(extensions, candidate, failedLookupLocations, onlyRecordFailures, state));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} onlyRecordFailures - if true then function won't try to actually load files but instead record all attempts as failures. This flag is necessary
|
||||
* in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations.
|
||||
*/
|
||||
function loadModuleFromFile(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
|
||||
function loadModuleFromFile(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
// First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts"
|
||||
const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, failedLookupLocations, onlyRecordFailures, state);
|
||||
if (resolvedByAddingExtension) {
|
||||
@@ -804,7 +832,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** Try to return an existing file that adds one of the `extensions` to `candidate`. */
|
||||
function tryAddingExtensions(candidate: string, extensions: Extensions, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
|
||||
function tryAddingExtensions(candidate: string, extensions: Extensions, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
if (!onlyRecordFailures) {
|
||||
// check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing
|
||||
const directory = getDirectoryPath(candidate);
|
||||
@@ -815,16 +843,16 @@ namespace ts {
|
||||
|
||||
switch (extensions) {
|
||||
case Extensions.DtsOnly:
|
||||
return tryExtension(".d.ts", Extension.Dts);
|
||||
return tryExtension(Extension.Dts);
|
||||
case Extensions.TypeScript:
|
||||
return tryExtension(".ts", Extension.Ts) || tryExtension(".tsx", Extension.Tsx) || tryExtension(".d.ts", Extension.Dts);
|
||||
return tryExtension(Extension.Ts) || tryExtension(Extension.Tsx) || tryExtension(Extension.Dts);
|
||||
case Extensions.JavaScript:
|
||||
return tryExtension(".js", Extension.Js) || tryExtension(".jsx", Extension.Jsx);
|
||||
return tryExtension(Extension.Js) || tryExtension(Extension.Jsx);
|
||||
}
|
||||
|
||||
function tryExtension(ext: string, extension: Extension): Resolved | undefined {
|
||||
function tryExtension(ext: Extension): PathAndExtension | undefined {
|
||||
const path = tryFile(candidate + ext, failedLookupLocations, onlyRecordFailures, state);
|
||||
return path && { path, extension };
|
||||
return path && { path, ext };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -850,12 +878,23 @@ namespace ts {
|
||||
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true): Resolved | undefined {
|
||||
const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host);
|
||||
|
||||
let packageId: PackageId | undefined;
|
||||
|
||||
if (considerPackageJson) {
|
||||
const packageJsonPath = pathToPackageJson(candidate);
|
||||
if (directoryExists && state.host.fileExists(packageJsonPath)) {
|
||||
const fromPackageJson = loadModuleFromPackageJson(packageJsonPath, extensions, candidate, failedLookupLocations, state);
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Found_package_json_at_0, packageJsonPath);
|
||||
}
|
||||
const jsonContent = readJson(packageJsonPath, state.host);
|
||||
|
||||
if (typeof jsonContent.name === "string" && typeof jsonContent.version === "string") {
|
||||
packageId = { name: jsonContent.name, version: jsonContent.version };
|
||||
}
|
||||
|
||||
const fromPackageJson = loadModuleFromPackageJson(jsonContent, extensions, candidate, failedLookupLocations, state);
|
||||
if (fromPackageJson) {
|
||||
return fromPackageJson;
|
||||
return withPackageId(packageId, fromPackageJson);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -867,15 +906,11 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
return loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state);
|
||||
return withPackageId(packageId, loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state));
|
||||
}
|
||||
|
||||
function loadModuleFromPackageJson(packageJsonPath: string, extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Found_package_json_at_0, packageJsonPath);
|
||||
}
|
||||
|
||||
const file = tryReadPackageJsonFields(extensions !== Extensions.JavaScript, packageJsonPath, candidate, state);
|
||||
function loadModuleFromPackageJson(jsonContent: PackageJson, extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
const file = tryReadPackageJsonFields(extensions !== Extensions.JavaScript, jsonContent, candidate, state);
|
||||
if (!file) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -895,13 +930,18 @@ namespace ts {
|
||||
// Even if extensions is DtsOnly, we can still look up a .ts file as a result of package.json "types"
|
||||
const nextExtensions = extensions === Extensions.DtsOnly ? Extensions.TypeScript : extensions;
|
||||
// Don't do package.json lookup recursively, because Node.js' package lookup doesn't.
|
||||
return nodeLoadModuleByRelativeName(nextExtensions, file, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/ false);
|
||||
const result = nodeLoadModuleByRelativeName(nextExtensions, file, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/ false);
|
||||
if (result) {
|
||||
// It won't have a `packageId` set, because we disabled `considerPackageJson`.
|
||||
Debug.assert(result.packageId === undefined);
|
||||
return { path: result.path, ext: result.extension };
|
||||
}
|
||||
}
|
||||
|
||||
/** Resolve from an arbitrarily specified file. Return `undefined` if it has an unsupported extension. */
|
||||
function resolvedIfExtensionMatches(extensions: Extensions, path: string): Resolved | undefined {
|
||||
const extension = tryGetExtensionFromPath(path);
|
||||
return extension !== undefined && extensionIsOk(extensions, extension) ? { path, extension } : undefined;
|
||||
function resolvedIfExtensionMatches(extensions: Extensions, path: string): PathAndExtension | undefined {
|
||||
const ext = tryGetExtensionFromPath(path);
|
||||
return ext !== undefined && extensionIsOk(extensions, ext) ? { path, ext } : undefined;
|
||||
}
|
||||
|
||||
/** True if `extension` is one of the supported `extensions`. */
|
||||
@@ -923,7 +963,7 @@ namespace ts {
|
||||
function loadModuleFromNodeModulesFolder(extensions: Extensions, moduleName: string, nodeModulesFolder: string, nodeModulesFolderExists: boolean, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
|
||||
const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
|
||||
|
||||
return loadModuleFromFile(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) ||
|
||||
return loadModuleFromFileNoPackageId(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) ||
|
||||
loadNodeModuleFromDirectory(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state);
|
||||
}
|
||||
|
||||
@@ -995,7 +1035,7 @@ namespace ts {
|
||||
export function getPackageNameFromAtTypesDirectory(mangledName: string): string {
|
||||
const withoutAtTypePrefix = removePrefix(mangledName, "@types/");
|
||||
if (withoutAtTypePrefix !== mangledName) {
|
||||
return withoutAtTypePrefix.indexOf("__") !== -1 ?
|
||||
return withoutAtTypePrefix.indexOf(mangledScopedPackageSeparator) !== -1 ?
|
||||
"@" + withoutAtTypePrefix.replace(mangledScopedPackageSeparator, ts.directorySeparator) :
|
||||
withoutAtTypePrefix;
|
||||
}
|
||||
@@ -1008,7 +1048,7 @@ namespace ts {
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache, moduleName);
|
||||
}
|
||||
return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, extension: result.resolvedModule.extension } };
|
||||
return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId } };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1022,13 +1062,13 @@ namespace ts {
|
||||
return createResolvedModuleWithFailedLookupLocations(resolved && resolved.value, /*isExternalLibraryImport*/ false, failedLookupLocations);
|
||||
|
||||
function tryResolve(extensions: Extensions): SearchResult<Resolved> {
|
||||
const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFile, failedLookupLocations, state);
|
||||
const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, failedLookupLocations, state);
|
||||
if (resolvedUsingSettings) {
|
||||
return { value: resolvedUsingSettings };
|
||||
}
|
||||
const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName);
|
||||
|
||||
if (moduleHasNonRelativeName(moduleName)) {
|
||||
if (!isExternalModuleNameRelative(moduleName)) {
|
||||
// Climb up parent directories looking for a module.
|
||||
const resolved = forEachAncestorDirectory(containingDirectory, directory => {
|
||||
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, directory, traceEnabled, host);
|
||||
@@ -1036,7 +1076,7 @@ namespace ts {
|
||||
return resolutionFromCache;
|
||||
}
|
||||
const searchName = normalizePath(combinePaths(directory, moduleName));
|
||||
return toSearchResult(loadModuleFromFile(extensions, searchName, failedLookupLocations, /*onlyRecordFailures*/ false, state));
|
||||
return toSearchResult(loadModuleFromFileNoPackageId(extensions, searchName, failedLookupLocations, /*onlyRecordFailures*/ false, state));
|
||||
});
|
||||
if (resolved) {
|
||||
return resolved;
|
||||
@@ -1048,7 +1088,7 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
|
||||
return toSearchResult(loadModuleFromFile(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state));
|
||||
return toSearchResult(loadModuleFromFileNoPackageId(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+599
-683
File diff suppressed because it is too large
Load Diff
+299
-79
@@ -3,7 +3,6 @@
|
||||
/// <reference path="core.ts" />
|
||||
|
||||
namespace ts {
|
||||
const emptyArray: any[] = [];
|
||||
const ignoreDiagnosticCommentRegEx = /(^\s*$)|(^\s*\/\/\/?\s*(@ts-ignore)?)/;
|
||||
|
||||
export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName = "tsconfig.json"): string {
|
||||
@@ -332,6 +331,7 @@ namespace ts {
|
||||
const categoryColor = getCategoryFormat(diagnostic.category);
|
||||
const category = DiagnosticCategory[diagnostic.category].toLowerCase();
|
||||
output += `${ formatAndReset(category, categoryColor) } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }`;
|
||||
output += sys.newLine;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
@@ -382,7 +382,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
interface DiagnosticCache {
|
||||
perFile?: FileMap<Diagnostic[]>;
|
||||
perFile?: Map<Diagnostic[]>;
|
||||
allDiagnostics?: Diagnostic[];
|
||||
}
|
||||
|
||||
@@ -405,7 +405,7 @@ namespace ts {
|
||||
let commonSourceDirectory: string;
|
||||
let diagnosticsProducingTypeChecker: TypeChecker;
|
||||
let noDiagnosticsTypeChecker: TypeChecker;
|
||||
let classifiableNames: Map<string>;
|
||||
let classifiableNames: UnderscoreEscapedMap<true>;
|
||||
let modifiedFilePaths: Path[] | undefined;
|
||||
|
||||
const cachedSemanticDiagnosticsForFile: DiagnosticCache = {};
|
||||
@@ -441,12 +441,13 @@ namespace ts {
|
||||
const supportedExtensions = getSupportedExtensions(options);
|
||||
|
||||
// Map storing if there is emit blocking diagnostics for given input
|
||||
const hasEmitBlockingDiagnostics = createFileMap<boolean>(getCanonicalFileName);
|
||||
const hasEmitBlockingDiagnostics = createMap<boolean>();
|
||||
let _compilerOptionsObjectLiteralSyntax: ObjectLiteralExpression;
|
||||
|
||||
let moduleResolutionCache: ModuleResolutionCache;
|
||||
let resolveModuleNamesWorker: (moduleNames: string[], containingFile: string) => ResolvedModuleFull[];
|
||||
if (host.resolveModuleNames) {
|
||||
resolveModuleNamesWorker = (moduleNames, containingFile) => host.resolveModuleNames(moduleNames, containingFile).map(resolved => {
|
||||
resolveModuleNamesWorker = (moduleNames, containingFile) => host.resolveModuleNames(checkAllDefined(moduleNames), containingFile).map(resolved => {
|
||||
// An older host may have omitted extension, in which case we should infer it from the file extension of resolvedFileName.
|
||||
if (!resolved || (resolved as ResolvedModuleFull).extension !== undefined) {
|
||||
return resolved as ResolvedModuleFull;
|
||||
@@ -459,22 +460,31 @@ namespace ts {
|
||||
else {
|
||||
moduleResolutionCache = createModuleResolutionCache(currentDirectory, x => host.getCanonicalFileName(x));
|
||||
const loader = (moduleName: string, containingFile: string) => resolveModuleName(moduleName, containingFile, options, host, moduleResolutionCache).resolvedModule;
|
||||
resolveModuleNamesWorker = (moduleNames, containingFile) => loadWithLocalCache(moduleNames, containingFile, loader);
|
||||
resolveModuleNamesWorker = (moduleNames, containingFile) => loadWithLocalCache(checkAllDefined(moduleNames), containingFile, loader);
|
||||
}
|
||||
|
||||
let resolveTypeReferenceDirectiveNamesWorker: (typeDirectiveNames: string[], containingFile: string) => ResolvedTypeReferenceDirective[];
|
||||
if (host.resolveTypeReferenceDirectives) {
|
||||
resolveTypeReferenceDirectiveNamesWorker = (typeDirectiveNames, containingFile) => host.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile);
|
||||
resolveTypeReferenceDirectiveNamesWorker = (typeDirectiveNames, containingFile) => host.resolveTypeReferenceDirectives(checkAllDefined(typeDirectiveNames), containingFile);
|
||||
}
|
||||
else {
|
||||
const loader = (typesRef: string, containingFile: string) => resolveTypeReferenceDirective(typesRef, containingFile, options, host).resolvedTypeReferenceDirective;
|
||||
resolveTypeReferenceDirectiveNamesWorker = (typeReferenceDirectiveNames, containingFile) => loadWithLocalCache(typeReferenceDirectiveNames, containingFile, loader);
|
||||
resolveTypeReferenceDirectiveNamesWorker = (typeReferenceDirectiveNames, containingFile) => loadWithLocalCache(checkAllDefined(typeReferenceDirectiveNames), containingFile, loader);
|
||||
}
|
||||
|
||||
const filesByName = createFileMap<SourceFile>();
|
||||
// Map from a stringified PackageId to the source file with that id.
|
||||
// Only one source file may have a given packageId. Others become redirects (see createRedirectSourceFile).
|
||||
// `packageIdToSourceFile` is only used while building the program, while `sourceFileToPackageName` and `isSourceFileTargetOfRedirect` are kept around.
|
||||
const packageIdToSourceFile = createMap<SourceFile>();
|
||||
// Maps from a SourceFile's `.path` to the name of the package it was imported with.
|
||||
let sourceFileToPackageName = createMap<string>();
|
||||
// See `sourceFileIsRedirectedTo`.
|
||||
let redirectTargetsSet = createMap<true>();
|
||||
|
||||
const filesByName = createMap<SourceFile | undefined>();
|
||||
// stores 'filename -> file association' ignoring case
|
||||
// used to track cases when two file names differ only in casing
|
||||
const filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? createFileMap<SourceFile>(fileName => fileName.toLowerCase()) : undefined;
|
||||
const filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? createMap<SourceFile>() : undefined;
|
||||
|
||||
const structuralIsReused = tryReuseStructureFromOldProgram();
|
||||
if (structuralIsReused !== StructureIsReused.Completely) {
|
||||
@@ -512,6 +522,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
const missingFilePaths = arrayFrom(filesByName.keys(), p => <Path>p).filter(p => !filesByName.get(p));
|
||||
|
||||
// unconditionally set moduleResolutionCache to undefined to avoid unnecessary leaks
|
||||
moduleResolutionCache = undefined;
|
||||
|
||||
@@ -523,6 +535,7 @@ namespace ts {
|
||||
getSourceFile,
|
||||
getSourceFileByPath,
|
||||
getSourceFiles: () => files,
|
||||
getMissingFilePaths: () => missingFilePaths,
|
||||
getCompilerOptions: () => options,
|
||||
getSyntacticDiagnostics,
|
||||
getOptionsDiagnostics,
|
||||
@@ -544,6 +557,8 @@ namespace ts {
|
||||
isSourceFileFromExternalLibrary,
|
||||
dropDiagnosticsProducingTypeChecker,
|
||||
getSourceFileFromReference,
|
||||
sourceFileToPackageName,
|
||||
redirectTargetsSet,
|
||||
};
|
||||
|
||||
verifyCompilerOptions();
|
||||
@@ -552,6 +567,10 @@ namespace ts {
|
||||
|
||||
return program;
|
||||
|
||||
function toPath(fileName: string): Path {
|
||||
return ts.toPath(fileName, currentDirectory, getCanonicalFileName);
|
||||
}
|
||||
|
||||
function getCommonSourceDirectory() {
|
||||
if (commonSourceDirectory === undefined) {
|
||||
const emittedFiles = filter(files, file => sourceFileMayBeEmitted(file, options, isSourceFileFromExternalLibrary));
|
||||
@@ -576,7 +595,7 @@ namespace ts {
|
||||
if (!classifiableNames) {
|
||||
// Initialize a checker so that all our files are bound.
|
||||
getTypeChecker();
|
||||
classifiableNames = createMap<string>();
|
||||
classifiableNames = createUnderscoreEscapedMap<true>();
|
||||
|
||||
for (const sourceFile of files) {
|
||||
copyEntries(sourceFile.classifiableNames, classifiableNames);
|
||||
@@ -765,8 +784,12 @@ namespace ts {
|
||||
const modifiedSourceFiles: { oldFile: SourceFile, newFile: SourceFile }[] = [];
|
||||
oldProgram.structureIsReused = StructureIsReused.Completely;
|
||||
|
||||
for (const oldSourceFile of oldProgram.getSourceFiles()) {
|
||||
const newSourceFile = host.getSourceFileByPath
|
||||
const oldSourceFiles = oldProgram.getSourceFiles();
|
||||
const enum SeenPackageName { Exists, Modified }
|
||||
const seenPackageNames = createMap<SeenPackageName>();
|
||||
|
||||
for (const oldSourceFile of oldSourceFiles) {
|
||||
let newSourceFile = host.getSourceFileByPath
|
||||
? host.getSourceFileByPath(oldSourceFile.fileName, oldSourceFile.path, options.target)
|
||||
: host.getSourceFile(oldSourceFile.fileName, options.target);
|
||||
|
||||
@@ -774,10 +797,46 @@ namespace ts {
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
|
||||
Debug.assert(!newSourceFile.redirectInfo, "Host should not return a redirect source file from `getSourceFile`");
|
||||
|
||||
let fileChanged: boolean;
|
||||
if (oldSourceFile.redirectInfo) {
|
||||
// We got `newSourceFile` by path, so it is actually for the unredirected file.
|
||||
// This lets us know if the unredirected file has changed. If it has we should break the redirect.
|
||||
if (newSourceFile !== oldSourceFile.redirectInfo.unredirected) {
|
||||
// Underlying file has changed. Might not redirect anymore. Must rebuild program.
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
fileChanged = false;
|
||||
newSourceFile = oldSourceFile; // Use the redirect.
|
||||
}
|
||||
else if (oldProgram.redirectTargetsSet.has(oldSourceFile.path)) {
|
||||
// If a redirected-to source file changes, the redirect may be broken.
|
||||
if (newSourceFile !== oldSourceFile) {
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
fileChanged = false;
|
||||
}
|
||||
else {
|
||||
fileChanged = newSourceFile !== oldSourceFile;
|
||||
}
|
||||
|
||||
newSourceFile.path = oldSourceFile.path;
|
||||
filePaths.push(newSourceFile.path);
|
||||
|
||||
if (oldSourceFile !== newSourceFile) {
|
||||
const packageName = oldProgram.sourceFileToPackageName.get(oldSourceFile.path);
|
||||
if (packageName !== undefined) {
|
||||
// If there are 2 different source files for the same package name and at least one of them changes,
|
||||
// they might become redirects. So we must rebuild the program.
|
||||
const prevKind = seenPackageNames.get(packageName);
|
||||
const newKind = fileChanged ? SeenPackageName.Modified : SeenPackageName.Exists;
|
||||
if ((prevKind !== undefined && newKind === SeenPackageName.Modified) || prevKind === SeenPackageName.Modified) {
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
seenPackageNames.set(packageName, newKind);
|
||||
}
|
||||
|
||||
if (fileChanged) {
|
||||
// The `newSourceFile` object was created for the new program.
|
||||
|
||||
if (oldSourceFile.hasNoDefaultLib !== newSourceFile.hasNoDefaultLib) {
|
||||
@@ -802,6 +861,10 @@ namespace ts {
|
||||
// moduleAugmentations has changed
|
||||
oldProgram.structureIsReused = StructureIsReused.SafeModules;
|
||||
}
|
||||
if ((oldSourceFile.flags & NodeFlags.PossiblyContainsDynamicImport) !== (newSourceFile.flags & NodeFlags.PossiblyContainsDynamicImport)) {
|
||||
// dynamicImport has changed
|
||||
oldProgram.structureIsReused = StructureIsReused.SafeModules;
|
||||
}
|
||||
|
||||
if (!arrayIsEqualTo(oldSourceFile.typeReferenceDirectives, newSourceFile.typeReferenceDirectives, fileReferenceIsEqualTo)) {
|
||||
// 'types' references has changed
|
||||
@@ -857,6 +920,21 @@ namespace ts {
|
||||
return oldProgram.structureIsReused;
|
||||
}
|
||||
|
||||
// If a file has ceased to be missing, then we need to discard some of the old
|
||||
// structure in order to pick it up.
|
||||
// Caution: if the file has created and then deleted between since it was discovered to
|
||||
// be missing, then the corresponding file watcher will have been closed and no new one
|
||||
// will be created until we encounter a change that prevents complete structure reuse.
|
||||
// During this interval, creation of the file will go unnoticed. We expect this to be
|
||||
// both rare and low-impact.
|
||||
if (oldProgram.getMissingFilePaths().some(missingFilePath => host.fileExists(missingFilePath))) {
|
||||
return oldProgram.structureIsReused = StructureIsReused.SafeModules;
|
||||
}
|
||||
|
||||
for (const p of oldProgram.getMissingFilePaths()) {
|
||||
filesByName.set(p, undefined);
|
||||
}
|
||||
|
||||
// update fileName -> file mapping
|
||||
for (let i = 0; i < newSourceFiles.length; i++) {
|
||||
filesByName.set(filePaths[i], newSourceFiles[i]);
|
||||
@@ -870,6 +948,9 @@ namespace ts {
|
||||
}
|
||||
resolvedTypeReferenceDirectives = oldProgram.getResolvedTypeReferenceDirectives();
|
||||
|
||||
sourceFileToPackageName = oldProgram.sourceFileToPackageName;
|
||||
redirectTargetsSet = oldProgram.redirectTargetsSet;
|
||||
|
||||
return oldProgram.structureIsReused = StructureIsReused.Completely;
|
||||
}
|
||||
|
||||
@@ -911,7 +992,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isEmitBlocked(emitFileName: string): boolean {
|
||||
return hasEmitBlockingDiagnostics.contains(toPath(emitFileName, currentDirectory, getCanonicalFileName));
|
||||
return hasEmitBlockingDiagnostics.has(toPath(emitFileName));
|
||||
}
|
||||
|
||||
function emitWorker(program: Program, sourceFile: SourceFile, writeFileCallback: WriteFileCallback, cancellationToken: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult {
|
||||
@@ -970,7 +1051,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getSourceFile(fileName: string): SourceFile {
|
||||
return getSourceFileByPath(toPath(fileName, currentDirectory, getCanonicalFileName));
|
||||
return getSourceFileByPath(toPath(fileName));
|
||||
}
|
||||
|
||||
function getSourceFileByPath(path: Path): SourceFile {
|
||||
@@ -1132,7 +1213,6 @@ namespace ts {
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
// type annotation
|
||||
if ((<FunctionLikeDeclaration | VariableDeclaration | ParameterDeclaration | PropertyDeclaration>parent).type === node) {
|
||||
@@ -1170,10 +1250,14 @@ namespace ts {
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.enum_declarations_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
const typeAssertionExpression = <TypeAssertion>node;
|
||||
diagnostics.push(createDiagnosticForNode(typeAssertionExpression.type, Diagnostics.type_assertion_expressions_can_only_be_used_in_a_ts_file));
|
||||
case SyntaxKind.NonNullExpression:
|
||||
diagnostics.push(createDiagnosticForNode(node, Diagnostics.non_null_assertions_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
case SyntaxKind.AsExpression:
|
||||
diagnostics.push(createDiagnosticForNode((node as AsExpression).type, Diagnostics.type_assertion_expressions_can_only_be_used_in_a_ts_file));
|
||||
return;
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
Debug.fail(); // Won't parse these in a JS file anyway, as they are interpreted as JSX.
|
||||
}
|
||||
|
||||
const prevParent = parent;
|
||||
@@ -1197,7 +1281,6 @@ namespace ts {
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
// Check type parameters
|
||||
if (nodes === (<ClassDeclaration | FunctionLikeDeclaration>parent).typeParameters) {
|
||||
diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.type_parameter_declarations_can_only_be_used_in_a_ts_file));
|
||||
@@ -1311,7 +1394,7 @@ namespace ts {
|
||||
const result = getDiagnostics(sourceFile, cancellationToken) || emptyArray;
|
||||
if (sourceFile) {
|
||||
if (!cache.perFile) {
|
||||
cache.perFile = createFileMap<Diagnostic[]>();
|
||||
cache.perFile = createMap<Diagnostic[]>();
|
||||
}
|
||||
cache.perFile.set(sourceFile.path, result);
|
||||
}
|
||||
@@ -1328,7 +1411,11 @@ namespace ts {
|
||||
function getOptionsDiagnostics(): Diagnostic[] {
|
||||
return sortAndDeduplicateDiagnostics(concatenate(
|
||||
fileProcessingDiagnostics.getGlobalDiagnostics(),
|
||||
programDiagnostics.getGlobalDiagnostics()));
|
||||
concatenate(
|
||||
programDiagnostics.getGlobalDiagnostics(),
|
||||
options.configFile ? programDiagnostics.getDiagnostics(options.configFile.fileName) : []
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
function getGlobalDiagnostics(): Diagnostic[] {
|
||||
@@ -1360,8 +1447,8 @@ namespace ts {
|
||||
const isExternalModuleFile = isExternalModule(file);
|
||||
|
||||
// file.imports may not be undefined if there exists dynamic import
|
||||
let imports: LiteralExpression[];
|
||||
let moduleAugmentations: LiteralExpression[];
|
||||
let imports: StringLiteral[];
|
||||
let moduleAugmentations: StringLiteral[];
|
||||
let ambientModules: string[];
|
||||
|
||||
// If we are importing helpers, we need to add a synthetic reference to resolve the
|
||||
@@ -1379,7 +1466,7 @@ namespace ts {
|
||||
|
||||
for (const node of file.statements) {
|
||||
collectModuleReferences(node, /*inAmbientModule*/ false);
|
||||
if ((file.flags & NodeFlags.PossiblyContainDynamicImport) || isJavaScriptFile) {
|
||||
if ((file.flags & NodeFlags.PossiblyContainsDynamicImport) || isJavaScriptFile) {
|
||||
collectDynamicImportOrRequireCalls(node);
|
||||
}
|
||||
}
|
||||
@@ -1396,35 +1483,36 @@ namespace ts {
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
const moduleNameExpr = getExternalModuleName(node);
|
||||
if (!moduleNameExpr || moduleNameExpr.kind !== SyntaxKind.StringLiteral) {
|
||||
if (!moduleNameExpr || !isStringLiteral(moduleNameExpr)) {
|
||||
break;
|
||||
}
|
||||
if (!(<LiteralExpression>moduleNameExpr).text) {
|
||||
if (!moduleNameExpr.text) {
|
||||
break;
|
||||
}
|
||||
|
||||
// TypeScript 1.0 spec (April 2014): 12.1.6
|
||||
// An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference other external modules
|
||||
// only through top - level external module names. Relative external module names are not permitted.
|
||||
if (!inAmbientModule || !isExternalModuleNameRelative((<LiteralExpression>moduleNameExpr).text)) {
|
||||
(imports || (imports = [])).push(<LiteralExpression>moduleNameExpr);
|
||||
if (!inAmbientModule || !isExternalModuleNameRelative(moduleNameExpr.text)) {
|
||||
(imports || (imports = [])).push(moduleNameExpr);
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
if (isAmbientModule(<ModuleDeclaration>node) && (inAmbientModule || hasModifier(node, ModifierFlags.Ambient) || file.isDeclarationFile)) {
|
||||
const moduleName = <LiteralExpression>(<ModuleDeclaration>node).name;
|
||||
const moduleName = <StringLiteral>(<ModuleDeclaration>node).name; // TODO: GH#17347
|
||||
const nameText = ts.getTextOfIdentifierOrLiteral(moduleName);
|
||||
// Ambient module declarations can be interpreted as augmentations for some existing external modules.
|
||||
// This will happen in two cases:
|
||||
// - if current file is external module then module augmentation is a ambient module declaration defined in the top level scope
|
||||
// - if current file is not external module then module augmentation is an ambient module declaration with non-relative module name
|
||||
// immediately nested in top level ambient module declaration .
|
||||
if (isExternalModuleFile || (inAmbientModule && !isExternalModuleNameRelative(moduleName.text))) {
|
||||
if (isExternalModuleFile || (inAmbientModule && !isExternalModuleNameRelative(nameText))) {
|
||||
(moduleAugmentations || (moduleAugmentations = [])).push(moduleName);
|
||||
}
|
||||
else if (!inAmbientModule) {
|
||||
if (file.isDeclarationFile) {
|
||||
// for global .d.ts files record name of ambient module
|
||||
(ambientModules || (ambientModules = [])).push(moduleName.text);
|
||||
(ambientModules || (ambientModules = [])).push(nameText);
|
||||
}
|
||||
// An AmbientExternalModuleDeclaration declares an external module.
|
||||
// This type of declaration is permitted only in the global module.
|
||||
@@ -1459,7 +1547,7 @@ namespace ts {
|
||||
|
||||
/** This should have similar behavior to 'processSourceFile' without diagnostics or mutation. */
|
||||
function getSourceFileFromReference(referencingFile: SourceFile, ref: FileReference): SourceFile | undefined {
|
||||
return getSourceFileFromReferenceWorker(resolveTripleslashReference(ref.fileName, referencingFile.fileName), fileName => filesByName.get(toPath(fileName, currentDirectory, getCanonicalFileName)));
|
||||
return getSourceFileFromReferenceWorker(resolveTripleslashReference(ref.fileName, referencingFile.fileName), fileName => filesByName.get(toPath(fileName)));
|
||||
}
|
||||
|
||||
function getSourceFileFromReferenceWorker(
|
||||
@@ -1495,7 +1583,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const sourceFileWithAddedExtension = forEach(supportedExtensions, extension => getSourceFile(fileName + extension));
|
||||
if (fail && !sourceFileWithAddedExtension) fail(Diagnostics.File_0_not_found, fileName + ".ts");
|
||||
if (fail && !sourceFileWithAddedExtension) fail(Diagnostics.File_0_not_found, fileName + Extension.Ts);
|
||||
return sourceFileWithAddedExtension;
|
||||
}
|
||||
}
|
||||
@@ -1503,7 +1591,7 @@ namespace ts {
|
||||
/** This has side effects through `findSourceFile`. */
|
||||
function processSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): void {
|
||||
getSourceFileFromReferenceWorker(fileName,
|
||||
fileName => findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd),
|
||||
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, refFile, refPos, refEnd, /*packageId*/ undefined),
|
||||
(diagnostic, ...args) => {
|
||||
fileProcessingDiagnostics.add(refFile !== undefined && refEnd !== undefined && refPos !== undefined
|
||||
? createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...args)
|
||||
@@ -1522,9 +1610,27 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function createRedirectSourceFile(redirectTarget: SourceFile, unredirected: SourceFile, fileName: string, path: Path): SourceFile {
|
||||
const redirect: SourceFile = Object.create(redirectTarget);
|
||||
redirect.fileName = fileName;
|
||||
redirect.path = path;
|
||||
redirect.redirectInfo = { redirectTarget, unredirected };
|
||||
Object.defineProperties(redirect, {
|
||||
id: {
|
||||
get(this: SourceFile) { return this.redirectInfo.redirectTarget.id; },
|
||||
set(this: SourceFile, value: SourceFile["id"]) { this.redirectInfo.redirectTarget.id = value; },
|
||||
},
|
||||
symbol: {
|
||||
get(this: SourceFile) { return this.redirectInfo.redirectTarget.symbol; },
|
||||
set(this: SourceFile, value: SourceFile["symbol"]) { this.redirectInfo.redirectTarget.symbol = value; },
|
||||
},
|
||||
});
|
||||
return redirect;
|
||||
}
|
||||
|
||||
// Get source file from normalized fileName
|
||||
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile {
|
||||
if (filesByName.contains(path)) {
|
||||
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, refFile: SourceFile, refPos: number, refEnd: number, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
if (filesByName.has(path)) {
|
||||
const file = filesByName.get(path);
|
||||
// try to check if we've already seen this file but with a different casing in path
|
||||
// NOTE: this only makes sense for case-insensitive file systems
|
||||
@@ -1566,19 +1672,40 @@ namespace ts {
|
||||
}
|
||||
});
|
||||
|
||||
if (packageId) {
|
||||
const packageIdKey = `${packageId.name}@${packageId.version}`;
|
||||
const fileFromPackageId = packageIdToSourceFile.get(packageIdKey);
|
||||
if (fileFromPackageId) {
|
||||
// Some other SourceFile already exists with this package name and version.
|
||||
// Instead of creating a duplicate, just redirect to the existing one.
|
||||
const dupFile = createRedirectSourceFile(fileFromPackageId, file, fileName, path);
|
||||
redirectTargetsSet.set(fileFromPackageId.path, true);
|
||||
filesByName.set(path, dupFile);
|
||||
sourceFileToPackageName.set(path, packageId.name);
|
||||
files.push(dupFile);
|
||||
return dupFile;
|
||||
}
|
||||
else if (file) {
|
||||
// This is the first source file to have this packageId.
|
||||
packageIdToSourceFile.set(packageIdKey, file);
|
||||
sourceFileToPackageName.set(path, packageId.name);
|
||||
}
|
||||
}
|
||||
|
||||
filesByName.set(path, file);
|
||||
if (file) {
|
||||
sourceFilesFoundSearchingNodeModules.set(path, currentNodeModulesDepth > 0);
|
||||
file.path = path;
|
||||
|
||||
if (host.useCaseSensitiveFileNames()) {
|
||||
const pathLowerCase = path.toLowerCase();
|
||||
// for case-sensitive file systems check if we've already seen some file with similar filename ignoring case
|
||||
const existingFile = filesByNameIgnoreCase.get(path);
|
||||
const existingFile = filesByNameIgnoreCase.get(pathLowerCase);
|
||||
if (existingFile) {
|
||||
reportFileNamesDifferOnlyInCasingError(fileName, existingFile.fileName, refFile, refPos, refEnd);
|
||||
}
|
||||
else {
|
||||
filesByNameIgnoreCase.set(path, file);
|
||||
filesByNameIgnoreCase.set(pathLowerCase, file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1725,9 +1852,9 @@ namespace ts {
|
||||
modulesWithElidedImports.set(file.path, true);
|
||||
}
|
||||
else if (shouldAddFile) {
|
||||
const path = toPath(resolvedFileName, currentDirectory, getCanonicalFileName);
|
||||
const path = toPath(resolvedFileName);
|
||||
const pos = skipTrivia(file.text, file.imports[i].pos);
|
||||
findSourceFile(resolvedFileName, path, /*isDefaultLib*/ false, file, pos, file.imports[i].end);
|
||||
findSourceFile(resolvedFileName, path, /*isDefaultLib*/ false, file, pos, file.imports[i].end, resolution.packageId);
|
||||
}
|
||||
|
||||
if (isFromNodeModulesSearch) {
|
||||
@@ -1773,33 +1900,33 @@ namespace ts {
|
||||
function verifyCompilerOptions() {
|
||||
if (options.isolatedModules) {
|
||||
if (options.declaration) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "declaration", "isolatedModules"));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "declaration", "isolatedModules");
|
||||
}
|
||||
|
||||
if (options.noEmitOnError) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noEmitOnError", "isolatedModules"));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noEmitOnError", "isolatedModules");
|
||||
}
|
||||
|
||||
if (options.out) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "isolatedModules"));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "isolatedModules");
|
||||
}
|
||||
|
||||
if (options.outFile) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "outFile", "isolatedModules"));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "outFile", "isolatedModules");
|
||||
}
|
||||
}
|
||||
|
||||
if (options.inlineSourceMap) {
|
||||
if (options.sourceMap) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "sourceMap", "inlineSourceMap"));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "sourceMap", "inlineSourceMap");
|
||||
}
|
||||
if (options.mapRoot) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "mapRoot", "inlineSourceMap"));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "mapRoot", "inlineSourceMap");
|
||||
}
|
||||
}
|
||||
|
||||
if (options.paths && options.baseUrl === undefined) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_paths_cannot_be_used_without_specifying_baseUrl_option));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_paths_cannot_be_used_without_specifying_baseUrl_option, "paths");
|
||||
}
|
||||
|
||||
if (options.paths) {
|
||||
@@ -1808,63 +1935,65 @@ namespace ts {
|
||||
continue;
|
||||
}
|
||||
if (!hasZeroOrOneAsteriskCharacter(key)) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, key));
|
||||
createDiagnosticForOptionPaths(/*onKey*/ true, key, Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, key);
|
||||
}
|
||||
if (isArray(options.paths[key])) {
|
||||
if (options.paths[key].length === 0) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substitutions_for_pattern_0_shouldn_t_be_an_empty_array, key));
|
||||
const len = options.paths[key].length;
|
||||
if (len === 0) {
|
||||
createDiagnosticForOptionPaths(/*onKey*/ false, key, Diagnostics.Substitutions_for_pattern_0_shouldn_t_be_an_empty_array, key);
|
||||
}
|
||||
for (const subst of options.paths[key]) {
|
||||
for (let i = 0; i < len; i++) {
|
||||
const subst = options.paths[key][i];
|
||||
const typeOfSubst = typeof subst;
|
||||
if (typeOfSubst === "string") {
|
||||
if (!hasZeroOrOneAsteriskCharacter(subst)) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substitution_0_in_pattern_1_in_can_have_at_most_one_Asterisk_character, subst, key));
|
||||
createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Substitution_0_in_pattern_1_in_can_have_at_most_one_Asterisk_character, subst, key);
|
||||
}
|
||||
}
|
||||
else {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substitution_0_for_pattern_1_has_incorrect_type_expected_string_got_2, subst, key, typeOfSubst));
|
||||
createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Substitution_0_for_pattern_1_has_incorrect_type_expected_string_got_2, subst, key, typeOfSubst);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substitutions_for_pattern_0_should_be_an_array, key));
|
||||
createDiagnosticForOptionPaths(/*onKey*/ false, key, Diagnostics.Substitutions_for_pattern_0_should_be_an_array, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.sourceMap && !options.inlineSourceMap) {
|
||||
if (options.inlineSources) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "inlineSources"));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "inlineSources");
|
||||
}
|
||||
if (options.sourceRoot) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "sourceRoot"));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "sourceRoot");
|
||||
}
|
||||
}
|
||||
|
||||
if (options.out && options.outFile) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "outFile"));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "outFile");
|
||||
}
|
||||
|
||||
if (options.mapRoot && !options.sourceMap) {
|
||||
// Error to specify --mapRoot without --sourcemap
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "mapRoot", "sourceMap"));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "mapRoot", "sourceMap");
|
||||
}
|
||||
|
||||
if (options.declarationDir) {
|
||||
if (!options.declaration) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "declarationDir", "declaration"));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "declarationDir", "declaration");
|
||||
}
|
||||
if (options.out || options.outFile) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "declarationDir", options.out ? "out" : "outFile"));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "declarationDir", options.out ? "out" : "outFile");
|
||||
}
|
||||
}
|
||||
|
||||
if (options.lib && options.noLib) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "lib", "noLib"));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "lib", "noLib");
|
||||
}
|
||||
|
||||
if (options.noImplicitUseStrict && (options.alwaysStrict === undefined ? options.strict : options.alwaysStrict)) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noImplicitUseStrict", "alwaysStrict"));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noImplicitUseStrict", "alwaysStrict");
|
||||
}
|
||||
|
||||
const languageVersion = options.target || ScriptTarget.ES3;
|
||||
@@ -1873,7 +2002,7 @@ namespace ts {
|
||||
const firstNonAmbientExternalModuleSourceFile = forEach(files, f => isExternalModule(f) && !f.isDeclarationFile ? f : undefined);
|
||||
if (options.isolatedModules) {
|
||||
if (options.module === ModuleKind.None && languageVersion < ScriptTarget.ES2015) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher, "isolatedModules", "target");
|
||||
}
|
||||
|
||||
const firstNonExternalModuleSourceFile = forEach(files, f => !isExternalModule(f) && !f.isDeclarationFile ? f : undefined);
|
||||
@@ -1891,7 +2020,7 @@ namespace ts {
|
||||
// Cannot specify module gen that isn't amd or system with --out
|
||||
if (outFile) {
|
||||
if (options.module && !(options.module === ModuleKind.AMD || options.module === ModuleKind.System)) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Only_amd_and_system_modules_are_supported_alongside_0, options.out ? "out" : "outFile"));
|
||||
createDiagnosticForOptionName(Diagnostics.Only_amd_and_system_modules_are_supported_alongside_0, options.out ? "out" : "outFile", "module");
|
||||
}
|
||||
else if (options.module === undefined && firstNonAmbientExternalModuleSourceFile) {
|
||||
const span = getErrorSpanForNode(firstNonAmbientExternalModuleSourceFile, firstNonAmbientExternalModuleSourceFile.externalModuleIndicator);
|
||||
@@ -1910,12 +2039,12 @@ namespace ts {
|
||||
|
||||
// If we failed to find a good common directory, but outDir is specified and at least one of our files is on a windows drive/URL/other resource, add a failure
|
||||
if (options.outDir && dir === "" && forEach(files, file => getRootLength(file.fileName) > 1)) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files));
|
||||
createDiagnosticForOptionName(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files, "outDir");
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.noEmit && options.allowJs && options.declaration) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration"));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration");
|
||||
}
|
||||
|
||||
if (options.checkJs && !options.allowJs) {
|
||||
@@ -1924,25 +2053,25 @@ namespace ts {
|
||||
|
||||
if (options.emitDecoratorMetadata &&
|
||||
!options.experimentalDecorators) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "emitDecoratorMetadata", "experimentalDecorators"));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "emitDecoratorMetadata", "experimentalDecorators");
|
||||
}
|
||||
|
||||
if (options.jsxFactory) {
|
||||
if (options.reactNamespace) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "reactNamespace", "jsxFactory"));
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "reactNamespace", "jsxFactory");
|
||||
}
|
||||
if (!parseIsolatedEntityName(options.jsxFactory, languageVersion)) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Invalid_value_for_jsxFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFactory));
|
||||
createOptionValueDiagnostic("jsxFactory", Diagnostics.Invalid_value_for_jsxFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFactory);
|
||||
}
|
||||
}
|
||||
else if (options.reactNamespace && !isIdentifierText(options.reactNamespace, languageVersion)) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Invalid_value_for_reactNamespace_0_is_not_a_valid_identifier, options.reactNamespace));
|
||||
createOptionValueDiagnostic("reactNamespace", Diagnostics.Invalid_value_for_reactNamespace_0_is_not_a_valid_identifier, options.reactNamespace);
|
||||
}
|
||||
|
||||
// If the emit is enabled make sure that every output file is unique and not overwriting any of the input files
|
||||
if (!options.noEmit && !options.suppressOutputPathCheck) {
|
||||
const emitHost = getEmitHost();
|
||||
const emitFilesSeen = createFileMap<boolean>(!host.useCaseSensitiveFileNames() ? key => key.toLocaleLowerCase() : undefined);
|
||||
const emitFilesSeen = createMap<true>();
|
||||
forEachEmittedFile(emitHost, (emitFileNames) => {
|
||||
verifyEmitFilePath(emitFileNames.jsFilePath, emitFilesSeen);
|
||||
verifyEmitFilePath(emitFileNames.declarationFilePath, emitFilesSeen);
|
||||
@@ -1950,11 +2079,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Verify that all the emit files are unique and don't overwrite input files
|
||||
function verifyEmitFilePath(emitFileName: string, emitFilesSeen: FileMap<boolean>) {
|
||||
function verifyEmitFilePath(emitFileName: string, emitFilesSeen: Map<true>) {
|
||||
if (emitFileName) {
|
||||
const emitFilePath = toPath(emitFileName, currentDirectory, getCanonicalFileName);
|
||||
const emitFilePath = toPath(emitFileName);
|
||||
// Report error if the output overwrites input file
|
||||
if (filesByName.contains(emitFilePath)) {
|
||||
if (filesByName.has(emitFilePath)) {
|
||||
let chain: DiagnosticMessageChain;
|
||||
if (!options.configFilePath) {
|
||||
// The program is from either an inferred project or an external project
|
||||
@@ -1964,20 +2093,106 @@ namespace ts {
|
||||
blockEmittingOfFile(emitFileName, createCompilerDiagnosticFromMessageChain(chain));
|
||||
}
|
||||
|
||||
const emitFileKey = !host.useCaseSensitiveFileNames() ? emitFilePath.toLocaleLowerCase() : emitFilePath;
|
||||
// Report error if multiple files write into same file
|
||||
if (emitFilesSeen.contains(emitFilePath)) {
|
||||
if (emitFilesSeen.has(emitFileKey)) {
|
||||
// Already seen the same emit file - report error
|
||||
blockEmittingOfFile(emitFileName, createCompilerDiagnostic(Diagnostics.Cannot_write_file_0_because_it_would_be_overwritten_by_multiple_input_files, emitFileName));
|
||||
}
|
||||
else {
|
||||
emitFilesSeen.set(emitFilePath, true);
|
||||
emitFilesSeen.set(emitFileKey, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createDiagnosticForOptionPathKeyValue(key: string, valueIndex: number, message: DiagnosticMessage, arg0: string | number, arg1: string | number, arg2?: string | number) {
|
||||
let needCompilerDiagnostic = true;
|
||||
const pathsSyntax = getOptionPathsSyntax();
|
||||
for (const pathProp of pathsSyntax) {
|
||||
if (isObjectLiteralExpression(pathProp.initializer)) {
|
||||
for (const keyProps of getPropertyAssignment(pathProp.initializer, key)) {
|
||||
if (isArrayLiteralExpression(keyProps.initializer) &&
|
||||
keyProps.initializer.elements.length > valueIndex) {
|
||||
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile, keyProps.initializer.elements[valueIndex], message, arg0, arg1, arg2));
|
||||
needCompilerDiagnostic = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needCompilerDiagnostic) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1, arg2));
|
||||
}
|
||||
}
|
||||
|
||||
function createDiagnosticForOptionPaths(onKey: boolean, key: string, message: DiagnosticMessage, arg0: string | number) {
|
||||
let needCompilerDiagnostic = true;
|
||||
const pathsSyntax = getOptionPathsSyntax();
|
||||
for (const pathProp of pathsSyntax) {
|
||||
if (isObjectLiteralExpression(pathProp.initializer) &&
|
||||
createOptionDiagnosticInObjectLiteralSyntax(
|
||||
pathProp.initializer, onKey, key, /*key2*/ undefined,
|
||||
message, arg0)) {
|
||||
needCompilerDiagnostic = false;
|
||||
}
|
||||
}
|
||||
if (needCompilerDiagnostic) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(message, arg0));
|
||||
}
|
||||
}
|
||||
|
||||
function getOptionPathsSyntax() {
|
||||
const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax();
|
||||
if (compilerOptionsObjectLiteralSyntax) {
|
||||
return getPropertyAssignment(compilerOptionsObjectLiteralSyntax, "paths");
|
||||
}
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
function createDiagnosticForOptionName(message: DiagnosticMessage, option1: string, option2?: string) {
|
||||
createDiagnosticForOption(/*onKey*/ true, option1, option2, message, option1, option2);
|
||||
}
|
||||
|
||||
function createOptionValueDiagnostic(option1: string, message: DiagnosticMessage, arg0: string) {
|
||||
createDiagnosticForOption(/*onKey*/ false, option1, /*option2*/ undefined, message, arg0);
|
||||
}
|
||||
|
||||
function createDiagnosticForOption(onKey: boolean, option1: string, option2: string, message: DiagnosticMessage, arg0: string | number, arg1?: string | number) {
|
||||
const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax();
|
||||
const needCompilerDiagnostic = !compilerOptionsObjectLiteralSyntax ||
|
||||
!createOptionDiagnosticInObjectLiteralSyntax(compilerOptionsObjectLiteralSyntax, onKey, option1, option2, message, arg0, arg1);
|
||||
|
||||
if (needCompilerDiagnostic) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1));
|
||||
}
|
||||
}
|
||||
|
||||
function getCompilerOptionsObjectLiteralSyntax() {
|
||||
if (_compilerOptionsObjectLiteralSyntax === undefined) {
|
||||
_compilerOptionsObjectLiteralSyntax = null; // tslint:disable-line:no-null-keyword
|
||||
if (options.configFile && options.configFile.jsonObject) {
|
||||
for (const prop of getPropertyAssignment(options.configFile.jsonObject, "compilerOptions")) {
|
||||
if (isObjectLiteralExpression(prop.initializer)) {
|
||||
_compilerOptionsObjectLiteralSyntax = prop.initializer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return _compilerOptionsObjectLiteralSyntax;
|
||||
}
|
||||
|
||||
function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string, message: DiagnosticMessage, arg0: string | number, arg1?: string | number): boolean {
|
||||
const props = getPropertyAssignment(objectLiteral, key1, key2);
|
||||
for (const prop of props) {
|
||||
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile, onKey ? prop.name : prop.initializer, message, arg0, arg1));
|
||||
}
|
||||
return !!props.length;
|
||||
}
|
||||
|
||||
function blockEmittingOfFile(emitFileName: string, diag: Diagnostic) {
|
||||
hasEmitBlockingDiagnostics.set(toPath(emitFileName, currentDirectory, getCanonicalFileName), true);
|
||||
hasEmitBlockingDiagnostics.set(toPath(emitFileName), true);
|
||||
programDiagnostics.add(diag);
|
||||
}
|
||||
}
|
||||
@@ -2009,4 +2224,9 @@ namespace ts {
|
||||
return options.allowJs ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_allowJs_is_not_set;
|
||||
}
|
||||
}
|
||||
|
||||
function checkAllDefined(names: string[]): string[] {
|
||||
Debug.assert(names.every(name => name !== undefined), "A name is undefined.", () => JSON.stringify(names));
|
||||
return names;
|
||||
}
|
||||
}
|
||||
|
||||
+12
-5
File diff suppressed because one or more lines are too long
@@ -145,7 +145,7 @@ namespace ts {
|
||||
|
||||
// Initialize source map data
|
||||
sourceMapData = {
|
||||
sourceMapFilePath: sourceMapFilePath,
|
||||
sourceMapFilePath,
|
||||
jsSourceMappingURL: !compilerOptions.inlineSourceMap ? getBaseFileName(normalizeSlashes(sourceMapFilePath)) : undefined,
|
||||
sourceMapFile: getBaseFileName(normalizeSlashes(filePath)),
|
||||
sourceMapSourceRoot: compilerOptions.sourceRoot || "",
|
||||
@@ -292,8 +292,8 @@ namespace ts {
|
||||
|
||||
// New span
|
||||
lastRecordedSourceMapSpan = {
|
||||
emittedLine: emittedLine,
|
||||
emittedColumn: emittedColumn,
|
||||
emittedLine,
|
||||
emittedColumn,
|
||||
sourceLine: sourceLinePos.line,
|
||||
sourceColumn: sourceLinePos.character,
|
||||
sourceIndex: sourceMapSourceIndex
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
/** @internal */
|
||||
namespace ts {
|
||||
export function createGetSymbolWalker(
|
||||
getRestTypeOfSignature: (sig: Signature) => Type,
|
||||
getReturnTypeOfSignature: (sig: Signature) => Type,
|
||||
getBaseTypes: (type: Type) => Type[],
|
||||
resolveStructuredTypeMembers: (type: ObjectType) => ResolvedType,
|
||||
getTypeOfSymbol: (sym: Symbol) => Type,
|
||||
getResolvedSymbol: (node: Node) => Symbol,
|
||||
getIndexTypeOfStructuredType: (type: Type, kind: IndexKind) => Type,
|
||||
getConstraintFromTypeParameter: (typeParameter: TypeParameter) => Type,
|
||||
getFirstIdentifier: (node: EntityNameOrEntityNameExpression) => Identifier) {
|
||||
|
||||
return getSymbolWalker;
|
||||
|
||||
function getSymbolWalker(accept: (symbol: Symbol) => boolean = () => true): SymbolWalker {
|
||||
const visitedTypes = createMap<Type>(); // Key is id as string
|
||||
const visitedSymbols = createMap<Symbol>(); // Key is id as string
|
||||
|
||||
return {
|
||||
walkType: type => {
|
||||
visitedTypes.clear();
|
||||
visitedSymbols.clear();
|
||||
visitType(type);
|
||||
return { visitedTypes: arrayFrom(visitedTypes.values()), visitedSymbols: arrayFrom(visitedSymbols.values()) };
|
||||
},
|
||||
walkSymbol: symbol => {
|
||||
visitedTypes.clear();
|
||||
visitedSymbols.clear();
|
||||
visitSymbol(symbol);
|
||||
return { visitedTypes: arrayFrom(visitedTypes.values()), visitedSymbols: arrayFrom(visitedSymbols.values()) };
|
||||
},
|
||||
};
|
||||
|
||||
function visitType(type: Type): void {
|
||||
if (!type) {
|
||||
return;
|
||||
}
|
||||
|
||||
const typeIdString = type.id.toString();
|
||||
if (visitedTypes.has(typeIdString)) {
|
||||
return;
|
||||
}
|
||||
visitedTypes.set(typeIdString, type);
|
||||
|
||||
// Reuse visitSymbol to visit the type's symbol,
|
||||
// but be sure to bail on recuring into the type if accept declines the symbol.
|
||||
const shouldBail = visitSymbol(type.symbol);
|
||||
if (shouldBail) return;
|
||||
|
||||
// Visit the type's related types, if any
|
||||
if (type.flags & TypeFlags.Object) {
|
||||
const objectType = type as ObjectType;
|
||||
const objectFlags = objectType.objectFlags;
|
||||
if (objectFlags & ObjectFlags.Reference) {
|
||||
visitTypeReference(type as TypeReference);
|
||||
}
|
||||
if (objectFlags & ObjectFlags.Mapped) {
|
||||
visitMappedType(type as MappedType);
|
||||
}
|
||||
if (objectFlags & (ObjectFlags.Class | ObjectFlags.Interface)) {
|
||||
visitInterfaceType(type as InterfaceType);
|
||||
}
|
||||
if (objectFlags & (ObjectFlags.Tuple | ObjectFlags.Anonymous)) {
|
||||
visitObjectType(objectType);
|
||||
}
|
||||
}
|
||||
if (type.flags & TypeFlags.TypeParameter) {
|
||||
visitTypeParameter(type as TypeParameter);
|
||||
}
|
||||
if (type.flags & TypeFlags.UnionOrIntersection) {
|
||||
visitUnionOrIntersectionType(type as UnionOrIntersectionType);
|
||||
}
|
||||
if (type.flags & TypeFlags.Index) {
|
||||
visitIndexType(type as IndexType);
|
||||
}
|
||||
if (type.flags & TypeFlags.IndexedAccess) {
|
||||
visitIndexedAccessType(type as IndexedAccessType);
|
||||
}
|
||||
}
|
||||
|
||||
function visitTypeList(types: Type[]): void {
|
||||
if (!types) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
visitType(types[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function visitTypeReference(type: TypeReference): void {
|
||||
visitType(type.target);
|
||||
visitTypeList(type.typeArguments);
|
||||
}
|
||||
|
||||
function visitTypeParameter(type: TypeParameter): void {
|
||||
visitType(getConstraintFromTypeParameter(type));
|
||||
}
|
||||
|
||||
function visitUnionOrIntersectionType(type: UnionOrIntersectionType): void {
|
||||
visitTypeList(type.types);
|
||||
}
|
||||
|
||||
function visitIndexType(type: IndexType): void {
|
||||
visitType(type.type);
|
||||
}
|
||||
|
||||
function visitIndexedAccessType(type: IndexedAccessType): void {
|
||||
visitType(type.objectType);
|
||||
visitType(type.indexType);
|
||||
visitType(type.constraint);
|
||||
}
|
||||
|
||||
function visitMappedType(type: MappedType): void {
|
||||
visitType(type.typeParameter);
|
||||
visitType(type.constraintType);
|
||||
visitType(type.templateType);
|
||||
visitType(type.modifiersType);
|
||||
}
|
||||
|
||||
function visitSignature(signature: Signature): void {
|
||||
if (signature.typePredicate) {
|
||||
visitType(signature.typePredicate.type);
|
||||
}
|
||||
visitTypeList(signature.typeParameters);
|
||||
|
||||
for (const parameter of signature.parameters){
|
||||
visitSymbol(parameter);
|
||||
}
|
||||
visitType(getRestTypeOfSignature(signature));
|
||||
visitType(getReturnTypeOfSignature(signature));
|
||||
}
|
||||
|
||||
function visitInterfaceType(interfaceT: InterfaceType): void {
|
||||
visitObjectType(interfaceT);
|
||||
visitTypeList(interfaceT.typeParameters);
|
||||
visitTypeList(getBaseTypes(interfaceT));
|
||||
visitType(interfaceT.thisType);
|
||||
}
|
||||
|
||||
function visitObjectType(type: ObjectType): void {
|
||||
const stringIndexType = getIndexTypeOfStructuredType(type, IndexKind.String);
|
||||
visitType(stringIndexType);
|
||||
const numberIndexType = getIndexTypeOfStructuredType(type, IndexKind.Number);
|
||||
visitType(numberIndexType);
|
||||
|
||||
// The two checks above *should* have already resolved the type (if needed), so this should be cached
|
||||
const resolved = resolveStructuredTypeMembers(type);
|
||||
for (const signature of resolved.callSignatures) {
|
||||
visitSignature(signature);
|
||||
}
|
||||
for (const signature of resolved.constructSignatures) {
|
||||
visitSignature(signature);
|
||||
}
|
||||
for (const p of resolved.properties) {
|
||||
visitSymbol(p);
|
||||
}
|
||||
}
|
||||
|
||||
function visitSymbol(symbol: Symbol): boolean {
|
||||
if (!symbol) {
|
||||
return;
|
||||
}
|
||||
const symbolIdString = getSymbolId(symbol).toString();
|
||||
if (visitedSymbols.has(symbolIdString)) {
|
||||
return;
|
||||
}
|
||||
visitedSymbols.set(symbolIdString, symbol);
|
||||
if (!accept(symbol)) {
|
||||
return true;
|
||||
}
|
||||
const t = getTypeOfSymbol(symbol);
|
||||
visitType(t); // Should handle members on classes and such
|
||||
if (symbol.flags & SymbolFlags.HasExports) {
|
||||
symbol.exports.forEach(visitSymbol);
|
||||
}
|
||||
forEach(symbol.declarations, d => {
|
||||
// Type queries are too far resolved when we just visit the symbol's type
|
||||
// (their type resolved directly to the member deeply referenced)
|
||||
// So to get the intervening symbols, we need to check if there's a type
|
||||
// query node on any of the symbol's declarations and get symbols there
|
||||
if ((d as any).type && (d as any).type.kind === SyntaxKind.TypeQuery) {
|
||||
const query = (d as any).type as TypeQueryNode;
|
||||
const entity = getResolvedSymbol(getFirstIdentifier(query.exprName));
|
||||
visitSymbol(entity);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+58
-20
@@ -4,7 +4,25 @@ declare function setTimeout(handler: (...args: any[]) => void, timeout: number):
|
||||
declare function clearTimeout(handle: any): void;
|
||||
|
||||
namespace ts {
|
||||
export type FileWatcherCallback = (fileName: string, removed?: boolean) => void;
|
||||
/**
|
||||
* Set a high stack trace limit to provide more information in case of an error.
|
||||
* Called for command-line and server use cases.
|
||||
* Not called if TypeScript is used as a library.
|
||||
*/
|
||||
/* @internal */
|
||||
export function setStackTraceLimit() {
|
||||
if ((Error as any).stackTraceLimit < 100) { // Also tests that we won't set the property if it doesn't exist.
|
||||
(Error as any).stackTraceLimit = 100;
|
||||
}
|
||||
}
|
||||
|
||||
export enum FileWatcherEventKind {
|
||||
Created,
|
||||
Changed,
|
||||
Deleted
|
||||
}
|
||||
|
||||
export type FileWatcherCallback = (fileName: string, eventKind: FileWatcherEventKind) => void;
|
||||
export type DirectoryWatcherCallback = (fileName: string) => void;
|
||||
export interface WatchedFile {
|
||||
fileName: string;
|
||||
@@ -17,7 +35,7 @@ namespace ts {
|
||||
newLine: string;
|
||||
useCaseSensitiveFileNames: boolean;
|
||||
write(s: string): void;
|
||||
readFile(path: string, encoding?: string): string;
|
||||
readFile(path: string, encoding?: string): string | undefined;
|
||||
getFileSize?(path: string): number;
|
||||
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
|
||||
/**
|
||||
@@ -33,8 +51,12 @@ namespace ts {
|
||||
getExecutingFilePath(): string;
|
||||
getCurrentDirectory(): string;
|
||||
getDirectories(path: string): string[];
|
||||
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[];
|
||||
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
|
||||
getModifiedTime?(path: string): Date;
|
||||
/**
|
||||
* This should be cryptographically secure.
|
||||
* A good implementation is node.js' `crypto.createHash`. (https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm)
|
||||
*/
|
||||
createHash?(data: string): string;
|
||||
getMemoryUsage?(): number;
|
||||
exit(exitCode?: number): void;
|
||||
@@ -87,10 +109,10 @@ namespace ts {
|
||||
directoryExists(path: string): boolean;
|
||||
createDirectory(path: string): void;
|
||||
resolvePath(path: string): string;
|
||||
readFile(path: string): string;
|
||||
readFile(path: string): string | undefined;
|
||||
writeFile(path: string, contents: string): void;
|
||||
getDirectories(path: string): string[];
|
||||
readDirectory(path: string, extensions?: string[], basePaths?: string[], excludeEx?: string, includeFileEx?: string, includeDirEx?: string): string[];
|
||||
readDirectory(path: string, extensions?: ReadonlyArray<string>, basePaths?: ReadonlyArray<string>, excludeEx?: string, includeFileEx?: string, includeDirEx?: string): string[];
|
||||
watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
|
||||
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
realpath(path: string): string;
|
||||
@@ -131,7 +153,7 @@ namespace ts {
|
||||
return;
|
||||
}
|
||||
watcher = _fs.watch(
|
||||
dirPath,
|
||||
dirPath || ".",
|
||||
{ persistent: true },
|
||||
(eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath)
|
||||
);
|
||||
@@ -170,7 +192,7 @@ namespace ts {
|
||||
const callbacks = fileWatcherCallbacks.get(fileName);
|
||||
if (callbacks) {
|
||||
for (const fileCallback of callbacks) {
|
||||
fileCallback(fileName);
|
||||
fileCallback(fileName, FileWatcherEventKind.Changed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,15 +208,22 @@ namespace ts {
|
||||
if (platform === "win32" || platform === "win64") {
|
||||
return false;
|
||||
}
|
||||
// convert current file name to upper case / lower case and check if file exists
|
||||
// (guards against cases when name is already all uppercase or lowercase)
|
||||
return !fileExists(__filename.toUpperCase()) || !fileExists(__filename.toLowerCase());
|
||||
// If this file exists under a different case, we must be case-insensitve.
|
||||
return !fileExists(swapCase(__filename));
|
||||
}
|
||||
|
||||
/** Convert all lowercase chars to uppercase, and vice-versa */
|
||||
function swapCase(s: string): string {
|
||||
return s.replace(/\w/g, (ch) => {
|
||||
const up = ch.toUpperCase();
|
||||
return ch === up ? ch.toLowerCase() : up;
|
||||
});
|
||||
}
|
||||
|
||||
const platform: string = _os.platform();
|
||||
const useCaseSensitiveFileNames = isFileSystemCaseSensitive();
|
||||
|
||||
function readFile(fileName: string, _encoding?: string): string {
|
||||
function readFile(fileName: string, _encoding?: string): string | undefined {
|
||||
if (!fileExists(fileName)) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -277,8 +306,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function readDirectory(path: string, extensions?: string[], excludes?: string[], includes?: string[]): string[] {
|
||||
return matchFiles(path, extensions, excludes, includes, useCaseSensitiveFileNames, process.cwd(), getAccessibleFileSystemEntries);
|
||||
function readDirectory(path: string, extensions?: ReadonlyArray<string>, excludes?: ReadonlyArray<string>, includes?: ReadonlyArray<string>, depth?: number): string[] {
|
||||
return matchFiles(path, extensions, excludes, includes, useCaseSensitiveFileNames, process.cwd(), depth, getAccessibleFileSystemEntries);
|
||||
}
|
||||
|
||||
const enum FileSystemEntryKind {
|
||||
@@ -315,7 +344,7 @@ namespace ts {
|
||||
const nodeSystem: System = {
|
||||
args: process.argv.slice(2),
|
||||
newLine: _os.EOL,
|
||||
useCaseSensitiveFileNames: useCaseSensitiveFileNames,
|
||||
useCaseSensitiveFileNames,
|
||||
write(s: string): void {
|
||||
process.stdout.write(s);
|
||||
},
|
||||
@@ -336,11 +365,22 @@ namespace ts {
|
||||
}
|
||||
|
||||
function fileChanged(curr: any, prev: any) {
|
||||
if (+curr.mtime <= +prev.mtime) {
|
||||
const isCurrZero = +curr.mtime === 0;
|
||||
const isPrevZero = +prev.mtime === 0;
|
||||
const created = !isCurrZero && isPrevZero;
|
||||
const deleted = isCurrZero && !isPrevZero;
|
||||
|
||||
const eventKind = created
|
||||
? FileWatcherEventKind.Created
|
||||
: deleted
|
||||
? FileWatcherEventKind.Deleted
|
||||
: FileWatcherEventKind.Changed;
|
||||
|
||||
if (eventKind === FileWatcherEventKind.Changed && +curr.mtime <= +prev.mtime) {
|
||||
return;
|
||||
}
|
||||
|
||||
callback(fileName);
|
||||
callback(fileName, eventKind);
|
||||
}
|
||||
},
|
||||
watchDirectory: (directoryName, callback, recursive) => {
|
||||
@@ -373,9 +413,7 @@ namespace ts {
|
||||
}
|
||||
);
|
||||
},
|
||||
resolvePath: function(path: string): string {
|
||||
return _path.resolve(path);
|
||||
},
|
||||
resolvePath: path => _path.resolve(path),
|
||||
fileExists,
|
||||
directoryExists,
|
||||
createDirectory(directoryName: string) {
|
||||
@@ -471,7 +509,7 @@ namespace ts {
|
||||
getCurrentDirectory: () => ChakraHost.currentDirectory,
|
||||
getDirectories: ChakraHost.getDirectories,
|
||||
getEnvironmentVariable: ChakraHost.getEnvironmentVariable || (() => ""),
|
||||
readDirectory: (path: string, extensions?: string[], excludes?: string[], includes?: string[]) => {
|
||||
readDirectory(path, extensions, excludes, includes, _depth) {
|
||||
const pattern = getFileMatcherPatterns(path, excludes, includes, !!ChakraHost.useCaseSensitiveFileNames, ChakraHost.currentDirectory);
|
||||
return ChakraHost.readDirectory(path, extensions, pattern.basePaths, pattern.excludePattern, pattern.includeFilePattern, pattern.includeDirectoryPattern);
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/// <reference path="visitor.ts" />
|
||||
/// <reference path="transformers/utilities.ts" />
|
||||
/// <reference path="transformers/ts.ts" />
|
||||
/// <reference path="transformers/jsx.ts" />
|
||||
/// <reference path="transformers/esnext.ts" />
|
||||
@@ -239,7 +240,7 @@ namespace ts {
|
||||
function hoistVariableDeclaration(name: Identifier): void {
|
||||
Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization.");
|
||||
Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed.");
|
||||
const decl = createVariableDeclaration(name);
|
||||
const decl = setEmitFlags(createVariableDeclaration(name), EmitFlags.NoNestedSourceMaps);
|
||||
if (!lexicalEnvironmentVariableDeclarations) {
|
||||
lexicalEnvironmentVariableDeclarations = [decl];
|
||||
}
|
||||
|
||||
@@ -331,11 +331,14 @@ namespace ts {
|
||||
location
|
||||
);
|
||||
}
|
||||
else if (numElements !== 1 && (flattenContext.level < FlattenLevel.ObjectRest || numElements === 0)) {
|
||||
else if (numElements !== 1 && (flattenContext.level < FlattenLevel.ObjectRest || numElements === 0)
|
||||
|| every(elements, isOmittedExpression)) {
|
||||
// For anything other than a single-element destructuring we need to generate a temporary
|
||||
// to ensure value is evaluated exactly once. Additionally, if we have zero elements
|
||||
// we need to emit *something* to ensure that in case a 'var' keyword was already emitted,
|
||||
// so in that case, we'll intentionally create that temporary.
|
||||
// Or all the elements of the binding pattern are omitted expression such as "var [,] = [1,2]",
|
||||
// then we will create temporary variable.
|
||||
const reuseIdentifierExpressions = !isDeclarationBindingElement(parent) || numElements !== 0;
|
||||
value = ensureIdentifier(flattenContext, value, reuseIdentifierExpressions, location);
|
||||
}
|
||||
@@ -411,11 +414,11 @@ namespace ts {
|
||||
}
|
||||
else if (isStringOrNumericLiteral(propertyName)) {
|
||||
const argumentExpression = getSynthesizedClone(propertyName);
|
||||
argumentExpression.text = unescapeIdentifier(argumentExpression.text);
|
||||
argumentExpression.text = argumentExpression.text;
|
||||
return createElementAccess(value, argumentExpression);
|
||||
}
|
||||
else {
|
||||
const name = createIdentifier(unescapeIdentifier(propertyName.text));
|
||||
const name = createIdentifier(unescapeLeadingUnderscores(propertyName.escapedText));
|
||||
return createPropertyAccess(value, name);
|
||||
}
|
||||
}
|
||||
@@ -492,7 +495,7 @@ namespace ts {
|
||||
/** Given value: o, propName: p, pattern: { a, b, ...p } from the original statement
|
||||
* `{ a, b, ...p } = o`, create `p = __rest(o, ["a", "b"]);`
|
||||
*/
|
||||
function createRestCall(context: TransformationContext, value: Expression, elements: BindingOrAssignmentElement[], computedTempVariables: Expression[], location: TextRange): Expression {
|
||||
function createRestCall(context: TransformationContext, value: Expression, elements: ReadonlyArray<BindingOrAssignmentElement>, computedTempVariables: ReadonlyArray<Expression>, location: TextRange): Expression {
|
||||
context.requestEmitHelper(restHelper);
|
||||
const propertyNames: Expression[] = [];
|
||||
let computedTempVariableOffset = 0;
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace ts {
|
||||
* set of labels that occurred inside the converted loop
|
||||
* used to determine if labeled jump can be emitted as is or it should be dispatched to calling code
|
||||
*/
|
||||
labels?: Map<string>;
|
||||
labels?: Map<boolean>;
|
||||
/*
|
||||
* collection of labeled jumps that transfer control outside the converted loop.
|
||||
* maps store association 'label -> labelMarker' where
|
||||
@@ -394,7 +394,7 @@ namespace ts {
|
||||
function shouldVisitNode(node: Node): boolean {
|
||||
return (node.transformFlags & TransformFlags.ContainsES2015) !== 0
|
||||
|| convertedLoopState !== undefined
|
||||
|| (hierarchyFacts & HierarchyFacts.ConstructorWithCapturedSuper && isStatement(node))
|
||||
|| (hierarchyFacts & HierarchyFacts.ConstructorWithCapturedSuper && (isStatement(node) || (node.kind === SyntaxKind.Block)))
|
||||
|| (isIterationStatement(node, /*lookInLabeledStatements*/ false) && shouldConvertIterationStatementBody(node))
|
||||
|| isTypeScriptClassWrapper(node);
|
||||
}
|
||||
@@ -647,7 +647,7 @@ namespace ts {
|
||||
if (isGeneratedIdentifier(node)) {
|
||||
return node;
|
||||
}
|
||||
if (node.text !== "arguments" || !resolver.isArgumentsLocalBinding(node)) {
|
||||
if (node.escapedText !== "arguments" || !resolver.isArgumentsLocalBinding(node)) {
|
||||
return node;
|
||||
}
|
||||
return convertedLoopState.argumentsName || (convertedLoopState.argumentsName = createUniqueName("arguments"));
|
||||
@@ -661,7 +661,7 @@ namespace ts {
|
||||
// - break/continue is non-labeled and located in non-converted loop/switch statement
|
||||
const jump = node.kind === SyntaxKind.BreakStatement ? Jump.Break : Jump.Continue;
|
||||
const canUseBreakOrContinue =
|
||||
(node.label && convertedLoopState.labels && convertedLoopState.labels.get(node.label.text)) ||
|
||||
(node.label && convertedLoopState.labels && convertedLoopState.labels.get(unescapeLeadingUnderscores(node.label.escapedText))) ||
|
||||
(!node.label && (convertedLoopState.allowedNonLabeledJumps & jump));
|
||||
|
||||
if (!canUseBreakOrContinue) {
|
||||
@@ -679,12 +679,12 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
if (node.kind === SyntaxKind.BreakStatement) {
|
||||
labelMarker = `break-${node.label.text}`;
|
||||
setLabeledJump(convertedLoopState, /*isBreak*/ true, node.label.text, labelMarker);
|
||||
labelMarker = `break-${node.label.escapedText}`;
|
||||
setLabeledJump(convertedLoopState, /*isBreak*/ true, unescapeLeadingUnderscores(node.label.escapedText), labelMarker);
|
||||
}
|
||||
else {
|
||||
labelMarker = `continue-${node.label.text}`;
|
||||
setLabeledJump(convertedLoopState, /*isBreak*/ false, node.label.text, labelMarker);
|
||||
labelMarker = `continue-${node.label.escapedText}`;
|
||||
setLabeledJump(convertedLoopState, /*isBreak*/ false, unescapeLeadingUnderscores(node.label.escapedText), labelMarker);
|
||||
}
|
||||
}
|
||||
let returnExpression: Expression = createLiteral(labelMarker);
|
||||
@@ -840,7 +840,7 @@ namespace ts {
|
||||
outer.end = skipTrivia(currentText, node.pos);
|
||||
setEmitFlags(outer, EmitFlags.NoComments);
|
||||
|
||||
return createParen(
|
||||
const result = createParen(
|
||||
createCall(
|
||||
outer,
|
||||
/*typeArguments*/ undefined,
|
||||
@@ -849,6 +849,8 @@ namespace ts {
|
||||
: []
|
||||
)
|
||||
);
|
||||
addSyntheticLeadingComment(result, SyntaxKind.MultiLineCommentTrivia, "* @class ");
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1963,7 +1965,7 @@ namespace ts {
|
||||
updated,
|
||||
setTextRange(
|
||||
createNodeArray(
|
||||
prependCaptureNewTargetIfNeeded(updated.statements, node, /*copyOnWrite*/ true)
|
||||
prependCaptureNewTargetIfNeeded(updated.statements as MutableNodeArray<Statement>, node, /*copyOnWrite*/ true)
|
||||
),
|
||||
/*location*/ updated.statements
|
||||
)
|
||||
@@ -2105,13 +2107,14 @@ namespace ts {
|
||||
setCommentRange(declarationList, node);
|
||||
|
||||
if (node.transformFlags & TransformFlags.ContainsBindingPattern
|
||||
&& (isBindingPattern(node.declarations[0].name)
|
||||
|| isBindingPattern(lastOrUndefined(node.declarations).name))) {
|
||||
&& (isBindingPattern(node.declarations[0].name) || isBindingPattern(lastOrUndefined(node.declarations).name))) {
|
||||
// If the first or last declaration is a binding pattern, we need to modify
|
||||
// the source map range for the declaration list.
|
||||
const firstDeclaration = firstOrUndefined(declarations);
|
||||
const lastDeclaration = lastOrUndefined(declarations);
|
||||
setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end));
|
||||
if (firstDeclaration) {
|
||||
const lastDeclaration = lastOrUndefined(declarations);
|
||||
setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end));
|
||||
}
|
||||
}
|
||||
|
||||
return declarationList;
|
||||
@@ -2236,16 +2239,16 @@ namespace ts {
|
||||
}
|
||||
|
||||
function recordLabel(node: LabeledStatement) {
|
||||
convertedLoopState.labels.set(node.label.text, node.label.text);
|
||||
convertedLoopState.labels.set(unescapeLeadingUnderscores(node.label.escapedText), true);
|
||||
}
|
||||
|
||||
function resetLabel(node: LabeledStatement) {
|
||||
convertedLoopState.labels.set(node.label.text, undefined);
|
||||
convertedLoopState.labels.set(unescapeLeadingUnderscores(node.label.escapedText), false);
|
||||
}
|
||||
|
||||
function visitLabeledStatement(node: LabeledStatement): VisitResult<Statement> {
|
||||
if (convertedLoopState && !convertedLoopState.labels) {
|
||||
convertedLoopState.labels = createMap<string>();
|
||||
convertedLoopState.labels = createMap<boolean>();
|
||||
}
|
||||
const statement = unwrapInnermostStatementOfLabel(node, convertedLoopState && recordLabel);
|
||||
return isIterationStatement(statement, /*lookInLabeledStatements*/ false)
|
||||
@@ -2491,7 +2494,7 @@ namespace ts {
|
||||
const catchVariable = getGeneratedNameForNode(errorRecord);
|
||||
const returnMethod = createTempVariable(/*recordTempVariable*/ undefined);
|
||||
const values = createValuesHelper(context, expression, node.expression);
|
||||
const next = createCall(createPropertyAccess(iterator, "next" ), /*typeArguments*/ undefined, []);
|
||||
const next = createCall(createPropertyAccess(iterator, "next"), /*typeArguments*/ undefined, []);
|
||||
|
||||
hoistVariableDeclaration(errorRecord);
|
||||
hoistVariableDeclaration(returnMethod);
|
||||
@@ -3053,7 +3056,7 @@ namespace ts {
|
||||
else {
|
||||
loopParameters.push(createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name));
|
||||
if (resolver.getNodeCheckFlags(decl) & NodeCheckFlags.NeedsLoopOutParameter) {
|
||||
const outParamName = createUniqueName("out_" + unescapeIdentifier(name.text));
|
||||
const outParamName = createUniqueName("out_" + unescapeLeadingUnderscores(name.escapedText));
|
||||
loopOutParameters.push({ originalName: name, outParamName });
|
||||
}
|
||||
}
|
||||
@@ -3173,6 +3176,7 @@ namespace ts {
|
||||
function visitCatchClause(node: CatchClause): CatchClause {
|
||||
const ancestorFacts = enterSubtree(HierarchyFacts.BlockScopeExcludes, HierarchyFacts.BlockScopeIncludes);
|
||||
let updated: CatchClause;
|
||||
Debug.assert(!!node.variableDeclaration, "Catch clause variable should always be present when downleveling ES2015.");
|
||||
if (isBindingPattern(node.variableDeclaration.name)) {
|
||||
const temp = createTempVariable(/*recordTempVariable*/ undefined);
|
||||
const newVariableDeclaration = createVariableDeclaration(temp);
|
||||
@@ -3199,7 +3203,7 @@ namespace ts {
|
||||
|
||||
function addStatementToStartOfBlock(block: Block, statement: Statement): Block {
|
||||
const transformedStatements = visitNodes(block.statements, visitor, isStatement);
|
||||
return updateBlock(block, [statement].concat(transformedStatements));
|
||||
return updateBlock(block, [statement, ...transformedStatements]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3401,28 +3405,19 @@ namespace ts {
|
||||
classBodyStart++;
|
||||
}
|
||||
|
||||
// We reuse the comment and source-map positions from the original variable statement
|
||||
// and class alias, while converting the function declaration for the class constructor
|
||||
// into an expression.
|
||||
// The next statement is the function declaration.
|
||||
statements.push(funcStatements[classBodyStart]);
|
||||
classBodyStart++;
|
||||
|
||||
// Add the class alias following the declaration.
|
||||
statements.push(
|
||||
updateVariableStatement(
|
||||
varStatement,
|
||||
/*modifiers*/ undefined,
|
||||
updateVariableDeclarationList(varStatement.declarationList, [
|
||||
updateVariableDeclaration(variable,
|
||||
variable.name,
|
||||
/*type*/ undefined,
|
||||
updateBinary(aliasAssignment,
|
||||
aliasAssignment.left,
|
||||
convertFunctionDeclarationToExpression(
|
||||
cast(funcStatements[classBodyStart], isFunctionDeclaration)
|
||||
)
|
||||
)
|
||||
)
|
||||
])
|
||||
createStatement(
|
||||
createAssignment(
|
||||
aliasAssignment.left,
|
||||
cast(variable.name, isIdentifier)
|
||||
)
|
||||
)
|
||||
);
|
||||
classBodyStart++;
|
||||
}
|
||||
|
||||
// Find the trailing 'return' statement (4)
|
||||
@@ -3588,7 +3583,7 @@ namespace ts {
|
||||
// Map spans of spread expressions into their expressions and spans of other
|
||||
// expressions into an array literal.
|
||||
const numElements = elements.length;
|
||||
const segments = flatten(
|
||||
const segments = flatten<Expression>(
|
||||
spanMap(elements, partitionSpread, (partition, visitPartition, _start, end) =>
|
||||
visitPartition(partition, multiLine, hasTrailingComma && end === numElements)
|
||||
)
|
||||
@@ -3600,7 +3595,7 @@ namespace ts {
|
||||
if (isCallExpression(firstSegment)
|
||||
&& isIdentifier(firstSegment.expression)
|
||||
&& (getEmitFlags(firstSegment.expression) & EmitFlags.HelperName)
|
||||
&& firstSegment.expression.text === "___spread") {
|
||||
&& firstSegment.expression.escapedText === "___spread") {
|
||||
return segments[0];
|
||||
}
|
||||
}
|
||||
@@ -3851,7 +3846,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function visitMetaProperty(node: MetaProperty) {
|
||||
if (node.keywordToken === SyntaxKind.NewKeyword && node.name.text === "target") {
|
||||
if (node.keywordToken === SyntaxKind.NewKeyword && node.name.escapedText === "target") {
|
||||
if (hierarchyFacts & HierarchyFacts.ComputedPropertyName) {
|
||||
hierarchyFacts |= HierarchyFacts.NewTargetInComputedPropertyName;
|
||||
}
|
||||
@@ -4076,7 +4071,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const expression = (<SpreadElement>callArgument).expression;
|
||||
return isIdentifier(expression) && expression.text === "arguments";
|
||||
return isIdentifier(expression) && expression.escapedText === "arguments";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -369,7 +369,7 @@ namespace ts {
|
||||
function substitutePropertyAccessExpression(node: PropertyAccessExpression) {
|
||||
if (node.expression.kind === SyntaxKind.SuperKeyword) {
|
||||
return createSuperAccessInAsyncMethod(
|
||||
createLiteral(node.name.text),
|
||||
createLiteral(unescapeLeadingUnderscores(node.name.escapedText)),
|
||||
node
|
||||
);
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace ts {
|
||||
* @param name An Identifier
|
||||
*/
|
||||
function trySubstituteReservedName(name: Identifier) {
|
||||
const token = name.originalKeywordKind || (nodeIsSynthesized(name) ? stringToToken(name.text) : undefined);
|
||||
const token = name.originalKeywordKind || (nodeIsSynthesized(name) ? stringToToken(unescapeLeadingUnderscores(name.escapedText)) : undefined);
|
||||
if (token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord) {
|
||||
return setTextRange(createLiteral(name), name);
|
||||
}
|
||||
|
||||
@@ -101,6 +101,8 @@ namespace ts {
|
||||
return visitExpressionStatement(node as ExpressionStatement);
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
return visitParenthesizedExpression(node as ParenthesizedExpression, noDestructuringValue);
|
||||
case SyntaxKind.CatchClause:
|
||||
return visitCatchClause(node as CatchClause);
|
||||
default:
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
@@ -156,7 +158,7 @@ namespace ts {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function chunkObjectLiteralElements(elements: ObjectLiteralElement[]): Expression[] {
|
||||
function chunkObjectLiteralElements(elements: ReadonlyArray<ObjectLiteralElement>): Expression[] {
|
||||
let chunkObject: (ShorthandPropertyAssignment | PropertyAssignment)[];
|
||||
const objects: Expression[] = [];
|
||||
for (const e of elements) {
|
||||
@@ -212,6 +214,17 @@ namespace ts {
|
||||
return visitEachChild(node, noDestructuringValue ? visitorNoDestructuringValue : visitor, context);
|
||||
}
|
||||
|
||||
function visitCatchClause(node: CatchClause): CatchClause {
|
||||
if (!node.variableDeclaration) {
|
||||
return updateCatchClause(
|
||||
node,
|
||||
createVariableDeclaration(createTempVariable(/*recordTempVariable*/ undefined)),
|
||||
visitNode(node.block, visitor, isBlock)
|
||||
);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a BinaryExpression that contains a destructuring assignment.
|
||||
*
|
||||
@@ -776,7 +789,7 @@ namespace ts {
|
||||
function substitutePropertyAccessExpression(node: PropertyAccessExpression) {
|
||||
if (node.expression.kind === SyntaxKind.SuperKeyword) {
|
||||
return createSuperAccessInAsyncMethod(
|
||||
createLiteral(node.name.text),
|
||||
createLiteral(unescapeLeadingUnderscores(node.name.escapedText)),
|
||||
node
|
||||
);
|
||||
}
|
||||
|
||||
@@ -164,12 +164,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
// A generated code block
|
||||
interface CodeBlock {
|
||||
kind: CodeBlockKind;
|
||||
}
|
||||
type CodeBlock = | ExceptionBlock | LabeledBlock | SwitchBlock | LoopBlock | WithBlock;
|
||||
|
||||
// a generated exception block, used for 'try' statements
|
||||
interface ExceptionBlock extends CodeBlock {
|
||||
interface ExceptionBlock {
|
||||
kind: CodeBlockKind.Exception;
|
||||
state: ExceptionBlockState;
|
||||
startLabel: Label;
|
||||
catchVariable?: Identifier;
|
||||
@@ -179,27 +178,31 @@ namespace ts {
|
||||
}
|
||||
|
||||
// A generated code that tracks the target for 'break' statements in a LabeledStatement.
|
||||
interface LabeledBlock extends CodeBlock {
|
||||
interface LabeledBlock {
|
||||
kind: CodeBlockKind.Labeled;
|
||||
labelText: string;
|
||||
isScript: boolean;
|
||||
breakLabel: Label;
|
||||
}
|
||||
|
||||
// a generated block that tracks the target for 'break' statements in a 'switch' statement
|
||||
interface SwitchBlock extends CodeBlock {
|
||||
interface SwitchBlock {
|
||||
kind: CodeBlockKind.Switch;
|
||||
isScript: boolean;
|
||||
breakLabel: Label;
|
||||
}
|
||||
|
||||
// a generated block that tracks the targets for 'break' and 'continue' statements, used for iteration statements
|
||||
interface LoopBlock extends CodeBlock {
|
||||
interface LoopBlock {
|
||||
kind: CodeBlockKind.Loop;
|
||||
continueLabel: Label;
|
||||
isScript: boolean;
|
||||
breakLabel: Label;
|
||||
}
|
||||
|
||||
// a generated block associated with a 'with' statement
|
||||
interface WithBlock extends CodeBlock {
|
||||
interface WithBlock {
|
||||
kind: CodeBlockKind.With;
|
||||
expression: Identifier;
|
||||
startLabel: Label;
|
||||
endLabel: Label;
|
||||
@@ -640,10 +643,13 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return createStatement(
|
||||
inlineExpressions(
|
||||
map(variables, transformInitializedVariable)
|
||||
)
|
||||
return setSourceMapRange(
|
||||
createStatement(
|
||||
inlineExpressions(
|
||||
map(variables, transformInitializedVariable)
|
||||
)
|
||||
),
|
||||
node
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1173,7 +1179,7 @@ namespace ts {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function transformAndEmitStatements(statements: Statement[], start = 0) {
|
||||
function transformAndEmitStatements(statements: ReadonlyArray<Statement>, start = 0) {
|
||||
const numStatements = statements.length;
|
||||
for (let i = start; i < numStatements; i++) {
|
||||
transformAndEmitStatement(statements[i]);
|
||||
@@ -1281,9 +1287,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
function transformInitializedVariable(node: VariableDeclaration) {
|
||||
return createAssignment(
|
||||
<Identifier>getSynthesizedClone(node.name),
|
||||
visitNode(node.initializer, visitor, isExpression)
|
||||
return setSourceMapRange(
|
||||
createAssignment(
|
||||
setSourceMapRange(<Identifier>getSynthesizedClone(node.name), node.name),
|
||||
visitNode(node.initializer, visitor, isExpression)
|
||||
),
|
||||
node
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1629,14 +1638,19 @@ namespace ts {
|
||||
}
|
||||
|
||||
function transformAndEmitContinueStatement(node: ContinueStatement): void {
|
||||
const label = findContinueTarget(node.label ? node.label.text : undefined);
|
||||
Debug.assert(label > 0, "Expected continue statment to point to a valid Label.");
|
||||
emitBreak(label, /*location*/ node);
|
||||
const label = findContinueTarget(node.label ? unescapeLeadingUnderscores(node.label.escapedText) : undefined);
|
||||
if (label > 0) {
|
||||
emitBreak(label, /*location*/ node);
|
||||
}
|
||||
else {
|
||||
// invalid continue without a containing loop. Leave the node as is, per #17875.
|
||||
emitStatement(node);
|
||||
}
|
||||
}
|
||||
|
||||
function visitContinueStatement(node: ContinueStatement): Statement {
|
||||
if (inStatementContainingYield) {
|
||||
const label = findContinueTarget(node.label && node.label.text);
|
||||
const label = findContinueTarget(node.label && unescapeLeadingUnderscores(node.label.escapedText));
|
||||
if (label > 0) {
|
||||
return createInlineBreak(label, /*location*/ node);
|
||||
}
|
||||
@@ -1646,14 +1660,19 @@ namespace ts {
|
||||
}
|
||||
|
||||
function transformAndEmitBreakStatement(node: BreakStatement): void {
|
||||
const label = findBreakTarget(node.label ? node.label.text : undefined);
|
||||
Debug.assert(label > 0, "Expected break statment to point to a valid Label.");
|
||||
emitBreak(label, /*location*/ node);
|
||||
const label = findBreakTarget(node.label ? unescapeLeadingUnderscores(node.label.escapedText) : undefined);
|
||||
if (label > 0) {
|
||||
emitBreak(label, /*location*/ node);
|
||||
}
|
||||
else {
|
||||
// invalid break without a containing loop, switch, or labeled statement. Leave the node as is, per #17875.
|
||||
emitStatement(node);
|
||||
}
|
||||
}
|
||||
|
||||
function visitBreakStatement(node: BreakStatement): Statement {
|
||||
if (inStatementContainingYield) {
|
||||
const label = findBreakTarget(node.label && node.label.text);
|
||||
const label = findBreakTarget(node.label && unescapeLeadingUnderscores(node.label.escapedText));
|
||||
if (label > 0) {
|
||||
return createInlineBreak(label, /*location*/ node);
|
||||
}
|
||||
@@ -1832,7 +1851,7 @@ namespace ts {
|
||||
// /*body*/
|
||||
// .endlabeled
|
||||
// .mark endLabel
|
||||
beginLabeledBlock(node.label.text);
|
||||
beginLabeledBlock(unescapeLeadingUnderscores(node.label.escapedText));
|
||||
transformAndEmitEmbeddedStatement(node.statement);
|
||||
endLabeledBlock();
|
||||
}
|
||||
@@ -1843,7 +1862,7 @@ namespace ts {
|
||||
|
||||
function visitLabeledStatement(node: LabeledStatement) {
|
||||
if (inStatementContainingYield) {
|
||||
beginScriptLabeledBlock(node.label.text);
|
||||
beginScriptLabeledBlock(unescapeLeadingUnderscores(node.label.escapedText));
|
||||
}
|
||||
|
||||
node = visitEachChild(node, visitor, context);
|
||||
@@ -1944,7 +1963,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function substituteExpressionIdentifier(node: Identifier) {
|
||||
if (!isGeneratedIdentifier(node) && renamedCatchVariables && renamedCatchVariables.has(node.text)) {
|
||||
if (!isGeneratedIdentifier(node) && renamedCatchVariables && renamedCatchVariables.has(unescapeLeadingUnderscores(node.escapedText))) {
|
||||
const original = getOriginalNode(node);
|
||||
if (isIdentifier(original) && original.parent) {
|
||||
const declaration = resolver.getReferencedValueDeclaration(original);
|
||||
@@ -2064,7 +2083,7 @@ namespace ts {
|
||||
const startLabel = defineLabel();
|
||||
const endLabel = defineLabel();
|
||||
markLabel(startLabel);
|
||||
beginBlock(<WithBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.With,
|
||||
expression,
|
||||
startLabel,
|
||||
@@ -2081,10 +2100,6 @@ namespace ts {
|
||||
markLabel(block.endLabel);
|
||||
}
|
||||
|
||||
function isWithBlock(block: CodeBlock): block is WithBlock {
|
||||
return block.kind === CodeBlockKind.With;
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins a code block for a generated `try` statement.
|
||||
*/
|
||||
@@ -2092,7 +2107,7 @@ namespace ts {
|
||||
const startLabel = defineLabel();
|
||||
const endLabel = defineLabel();
|
||||
markLabel(startLabel);
|
||||
beginBlock(<ExceptionBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Exception,
|
||||
state: ExceptionBlockState.Try,
|
||||
startLabel,
|
||||
@@ -2117,7 +2132,7 @@ namespace ts {
|
||||
hoistVariableDeclaration(variable.name);
|
||||
}
|
||||
else {
|
||||
const text = (<Identifier>variable.name).text;
|
||||
const text = unescapeLeadingUnderscores((<Identifier>variable.name).escapedText);
|
||||
name = declareLocal(text);
|
||||
if (!renamedCatchVariables) {
|
||||
renamedCatchVariables = createMap<boolean>();
|
||||
@@ -2182,10 +2197,6 @@ namespace ts {
|
||||
exception.state = ExceptionBlockState.Done;
|
||||
}
|
||||
|
||||
function isExceptionBlock(block: CodeBlock): block is ExceptionBlock {
|
||||
return block.kind === CodeBlockKind.Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins a code block that supports `break` or `continue` statements that are defined in
|
||||
* the source tree and not from generated code.
|
||||
@@ -2193,7 +2204,7 @@ namespace ts {
|
||||
* @param labelText Names from containing labeled statements.
|
||||
*/
|
||||
function beginScriptLoopBlock(): void {
|
||||
beginBlock(<LoopBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Loop,
|
||||
isScript: true,
|
||||
breakLabel: -1,
|
||||
@@ -2211,11 +2222,11 @@ namespace ts {
|
||||
*/
|
||||
function beginLoopBlock(continueLabel: Label): Label {
|
||||
const breakLabel = defineLabel();
|
||||
beginBlock(<LoopBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Loop,
|
||||
isScript: false,
|
||||
breakLabel: breakLabel,
|
||||
continueLabel: continueLabel
|
||||
breakLabel,
|
||||
continueLabel,
|
||||
});
|
||||
return breakLabel;
|
||||
}
|
||||
@@ -2239,7 +2250,7 @@ namespace ts {
|
||||
*
|
||||
*/
|
||||
function beginScriptSwitchBlock(): void {
|
||||
beginBlock(<SwitchBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Switch,
|
||||
isScript: true,
|
||||
breakLabel: -1
|
||||
@@ -2253,10 +2264,10 @@ namespace ts {
|
||||
*/
|
||||
function beginSwitchBlock(): Label {
|
||||
const breakLabel = defineLabel();
|
||||
beginBlock(<SwitchBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Switch,
|
||||
isScript: false,
|
||||
breakLabel: breakLabel
|
||||
breakLabel,
|
||||
});
|
||||
return breakLabel;
|
||||
}
|
||||
@@ -2274,7 +2285,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function beginScriptLabeledBlock(labelText: string) {
|
||||
beginBlock(<LabeledBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Labeled,
|
||||
isScript: true,
|
||||
labelText,
|
||||
@@ -2284,7 +2295,7 @@ namespace ts {
|
||||
|
||||
function beginLabeledBlock(labelText: string) {
|
||||
const breakLabel = defineLabel();
|
||||
beginBlock(<LabeledBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Labeled,
|
||||
isScript: false,
|
||||
labelText,
|
||||
@@ -2350,27 +2361,27 @@ namespace ts {
|
||||
* @param labelText An optional name of a containing labeled statement.
|
||||
*/
|
||||
function findBreakTarget(labelText?: string): Label {
|
||||
Debug.assert(blocks !== undefined);
|
||||
if (labelText) {
|
||||
for (let i = blockStack.length - 1; i >= 0; i--) {
|
||||
const block = blockStack[i];
|
||||
if (supportsLabeledBreakOrContinue(block) && block.labelText === labelText) {
|
||||
return block.breakLabel;
|
||||
if (blockStack) {
|
||||
if (labelText) {
|
||||
for (let i = blockStack.length - 1; i >= 0; i--) {
|
||||
const block = blockStack[i];
|
||||
if (supportsLabeledBreakOrContinue(block) && block.labelText === labelText) {
|
||||
return block.breakLabel;
|
||||
}
|
||||
else if (supportsUnlabeledBreak(block) && hasImmediateContainingLabeledBlock(labelText, i - 1)) {
|
||||
return block.breakLabel;
|
||||
}
|
||||
}
|
||||
else if (supportsUnlabeledBreak(block) && hasImmediateContainingLabeledBlock(labelText, i - 1)) {
|
||||
return block.breakLabel;
|
||||
}
|
||||
else {
|
||||
for (let i = blockStack.length - 1; i >= 0; i--) {
|
||||
const block = blockStack[i];
|
||||
if (supportsUnlabeledBreak(block)) {
|
||||
return block.breakLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (let i = blockStack.length - 1; i >= 0; i--) {
|
||||
const block = blockStack[i];
|
||||
if (supportsUnlabeledBreak(block)) {
|
||||
return block.breakLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2380,24 +2391,24 @@ namespace ts {
|
||||
* @param labelText An optional name of a containing labeled statement.
|
||||
*/
|
||||
function findContinueTarget(labelText?: string): Label {
|
||||
Debug.assert(blocks !== undefined);
|
||||
if (labelText) {
|
||||
for (let i = blockStack.length - 1; i >= 0; i--) {
|
||||
const block = blockStack[i];
|
||||
if (supportsUnlabeledContinue(block) && hasImmediateContainingLabeledBlock(labelText, i - 1)) {
|
||||
return block.continueLabel;
|
||||
if (blockStack) {
|
||||
if (labelText) {
|
||||
for (let i = blockStack.length - 1; i >= 0; i--) {
|
||||
const block = blockStack[i];
|
||||
if (supportsUnlabeledContinue(block) && hasImmediateContainingLabeledBlock(labelText, i - 1)) {
|
||||
return block.continueLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (let i = blockStack.length - 1; i >= 0; i--) {
|
||||
const block = blockStack[i];
|
||||
if (supportsUnlabeledContinue(block)) {
|
||||
return block.continueLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (let i = blockStack.length - 1; i >= 0; i--) {
|
||||
const block = blockStack[i];
|
||||
if (supportsUnlabeledContinue(block)) {
|
||||
return block.continueLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2442,7 +2453,7 @@ namespace ts {
|
||||
* @param location An optional source map location for the statement.
|
||||
*/
|
||||
function createInlineBreak(label: Label, location?: TextRange): ReturnStatement {
|
||||
Debug.assert(label > 0, `Invalid label: ${label}`);
|
||||
Debug.assertLessThan(0, label, "Invalid label");
|
||||
return setTextRange(
|
||||
createReturn(
|
||||
createArrayLiteral([
|
||||
@@ -2872,34 +2883,37 @@ namespace ts {
|
||||
for (; blockIndex < blockActions.length && blockOffsets[blockIndex] <= operationIndex; blockIndex++) {
|
||||
const block = blocks[blockIndex];
|
||||
const blockAction = blockActions[blockIndex];
|
||||
if (isExceptionBlock(block)) {
|
||||
if (blockAction === BlockAction.Open) {
|
||||
if (!exceptionBlockStack) {
|
||||
exceptionBlockStack = [];
|
||||
}
|
||||
switch (block.kind) {
|
||||
case CodeBlockKind.Exception:
|
||||
if (blockAction === BlockAction.Open) {
|
||||
if (!exceptionBlockStack) {
|
||||
exceptionBlockStack = [];
|
||||
}
|
||||
|
||||
if (!statements) {
|
||||
statements = [];
|
||||
}
|
||||
if (!statements) {
|
||||
statements = [];
|
||||
}
|
||||
|
||||
exceptionBlockStack.push(currentExceptionBlock);
|
||||
currentExceptionBlock = block;
|
||||
}
|
||||
else if (blockAction === BlockAction.Close) {
|
||||
currentExceptionBlock = exceptionBlockStack.pop();
|
||||
}
|
||||
}
|
||||
else if (isWithBlock(block)) {
|
||||
if (blockAction === BlockAction.Open) {
|
||||
if (!withBlockStack) {
|
||||
withBlockStack = [];
|
||||
exceptionBlockStack.push(currentExceptionBlock);
|
||||
currentExceptionBlock = block;
|
||||
}
|
||||
else if (blockAction === BlockAction.Close) {
|
||||
currentExceptionBlock = exceptionBlockStack.pop();
|
||||
}
|
||||
break;
|
||||
case CodeBlockKind.With:
|
||||
if (blockAction === BlockAction.Open) {
|
||||
if (!withBlockStack) {
|
||||
withBlockStack = [];
|
||||
}
|
||||
|
||||
withBlockStack.push(block);
|
||||
}
|
||||
else if (blockAction === BlockAction.Close) {
|
||||
withBlockStack.pop();
|
||||
}
|
||||
withBlockStack.push(block);
|
||||
}
|
||||
else if (blockAction === BlockAction.Close) {
|
||||
withBlockStack.pop();
|
||||
}
|
||||
break;
|
||||
// default: do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace ts {
|
||||
return visitJsxOpeningLikeElement(node, /*children*/ undefined, isChild, /*location*/ node);
|
||||
}
|
||||
|
||||
function visitJsxOpeningLikeElement(node: JsxOpeningLikeElement, children: JsxChild[], isChild: boolean, location: TextRange) {
|
||||
function visitJsxOpeningLikeElement(node: JsxOpeningLikeElement, children: ReadonlyArray<JsxChild>, isChild: boolean, location: TextRange) {
|
||||
const tagName = getTagName(node);
|
||||
let objectProperties: Expression;
|
||||
const attrs = node.attributes.properties;
|
||||
@@ -88,7 +88,7 @@ namespace ts {
|
||||
else {
|
||||
// Map spans of JsxAttribute nodes into object literals and spans
|
||||
// of JsxSpreadAttribute nodes into expressions.
|
||||
const segments = flatten(
|
||||
const segments = flatten<Expression | ObjectLiteralExpression>(
|
||||
spanMap(attrs, isJsxSpreadAttribute, (attrs, isSpread) => isSpread
|
||||
? map(attrs, transformJsxSpreadAttributeToExpression)
|
||||
: createObjectLiteral(map(attrs, transformJsxAttributeToObjectLiteralElement))
|
||||
@@ -114,7 +114,7 @@ namespace ts {
|
||||
compilerOptions.reactNamespace,
|
||||
tagName,
|
||||
objectProperties,
|
||||
filter(map(children, transformJsxChildToExpression), isDefined),
|
||||
mapDefined(children, transformJsxChildToExpression),
|
||||
node,
|
||||
location
|
||||
);
|
||||
@@ -252,8 +252,8 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
const name = (<JsxOpeningLikeElement>node).tagName;
|
||||
if (isIdentifier(name) && isIntrinsicJsxName(name.text)) {
|
||||
return createLiteral(name.text);
|
||||
if (isIdentifier(name) && isIntrinsicJsxName(name.escapedText)) {
|
||||
return createLiteral(unescapeLeadingUnderscores(name.escapedText));
|
||||
}
|
||||
else {
|
||||
return createExpressionFromEntityName(name);
|
||||
@@ -268,11 +268,11 @@ namespace ts {
|
||||
*/
|
||||
function getAttributeName(node: JsxAttribute): StringLiteral | Identifier {
|
||||
const name = node.name;
|
||||
if (/^[A-Za-z_]\w*$/.test(name.text)) {
|
||||
if (/^[A-Za-z_]\w*$/.test(unescapeLeadingUnderscores(name.escapedText))) {
|
||||
return name;
|
||||
}
|
||||
else {
|
||||
return createLiteral(name.text);
|
||||
return createLiteral(unescapeLeadingUnderscores(name.escapedText));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -514,14 +514,14 @@ namespace ts {
|
||||
|
||||
function visitImportCallExpression(node: ImportCall): Expression {
|
||||
switch (compilerOptions.module) {
|
||||
case ModuleKind.CommonJS:
|
||||
return transformImportCallExpressionCommonJS(node);
|
||||
case ModuleKind.AMD:
|
||||
return transformImportCallExpressionAMD(node);
|
||||
case ModuleKind.UMD:
|
||||
return transformImportCallExpressionUMD(node);
|
||||
case ModuleKind.CommonJS:
|
||||
default:
|
||||
return transformImportCallExpressionCommonJS(node);
|
||||
}
|
||||
Debug.fail("All supported module kind in this transformation step should have been handled");
|
||||
}
|
||||
|
||||
function transformImportCallExpressionUMD(node: ImportCall): Expression {
|
||||
@@ -924,7 +924,7 @@ namespace ts {
|
||||
getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true),
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.heritageClauses, importCallExpressionVisitor),
|
||||
node.members
|
||||
visitNodes(node.members, importCallExpressionVisitor)
|
||||
),
|
||||
node
|
||||
),
|
||||
@@ -1225,7 +1225,7 @@ namespace ts {
|
||||
*/
|
||||
function appendExportsOfDeclaration(statements: Statement[] | undefined, decl: Declaration): Statement[] | undefined {
|
||||
const name = getDeclarationName(decl);
|
||||
const exportSpecifiers = currentModuleInfo.exportSpecifiers.get(name.text);
|
||||
const exportSpecifiers = currentModuleInfo.exportSpecifiers.get(unescapeLeadingUnderscores(name.escapedText));
|
||||
if (exportSpecifiers) {
|
||||
for (const exportSpecifier of exportSpecifiers) {
|
||||
statements = appendExportStatement(statements, exportSpecifier.name, name, /*location*/ exportSpecifier.name);
|
||||
|
||||
@@ -324,7 +324,7 @@ namespace ts {
|
||||
const exportedNames: ObjectLiteralElementLike[] = [];
|
||||
if (moduleInfo.exportedNames) {
|
||||
for (const exportedLocalName of moduleInfo.exportedNames) {
|
||||
if (exportedLocalName.text === "default") {
|
||||
if (exportedLocalName.escapedText === "default") {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -353,7 +353,7 @@ namespace ts {
|
||||
// write name of indirectly exported entry, i.e. 'export {x} from ...'
|
||||
exportedNames.push(
|
||||
createPropertyAssignment(
|
||||
createLiteral((element.name || element.propertyName).text),
|
||||
createLiteral(unescapeLeadingUnderscores((element.name || element.propertyName).escapedText)),
|
||||
createTrue()
|
||||
)
|
||||
);
|
||||
@@ -504,10 +504,10 @@ namespace ts {
|
||||
for (const e of (<ExportDeclaration>entry).exportClause.elements) {
|
||||
properties.push(
|
||||
createPropertyAssignment(
|
||||
createLiteral(e.name.text),
|
||||
createLiteral(unescapeLeadingUnderscores(e.name.escapedText)),
|
||||
createElementAccess(
|
||||
parameterName,
|
||||
createLiteral((e.propertyName || e.name).text)
|
||||
createLiteral(unescapeLeadingUnderscores((e.propertyName || e.name).escapedText))
|
||||
)
|
||||
)
|
||||
);
|
||||
@@ -1028,7 +1028,7 @@ namespace ts {
|
||||
let excludeName: string;
|
||||
if (exportSelf) {
|
||||
statements = appendExportStatement(statements, decl.name, getLocalName(decl));
|
||||
excludeName = decl.name.text;
|
||||
excludeName = unescapeLeadingUnderscores(decl.name.escapedText);
|
||||
}
|
||||
|
||||
statements = appendExportsOfDeclaration(statements, decl, excludeName);
|
||||
@@ -1055,7 +1055,7 @@ namespace ts {
|
||||
if (hasModifier(decl, ModifierFlags.Export)) {
|
||||
const exportName = hasModifier(decl, ModifierFlags.Default) ? createLiteral("default") : decl.name;
|
||||
statements = appendExportStatement(statements, exportName, getLocalName(decl));
|
||||
excludeName = exportName.text;
|
||||
excludeName = getTextOfIdentifierOrLiteral(exportName);
|
||||
}
|
||||
|
||||
if (decl.name) {
|
||||
@@ -1080,10 +1080,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
const name = getDeclarationName(decl);
|
||||
const exportSpecifiers = moduleInfo.exportSpecifiers.get(name.text);
|
||||
const exportSpecifiers = moduleInfo.exportSpecifiers.get(unescapeLeadingUnderscores(name.escapedText));
|
||||
if (exportSpecifiers) {
|
||||
for (const exportSpecifier of exportSpecifiers) {
|
||||
if (exportSpecifier.name.text !== excludeName) {
|
||||
if (exportSpecifier.name.escapedText !== excludeName) {
|
||||
statements = appendExportStatement(statements, exportSpecifier.name, name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace ts {
|
||||
let currentNamespace: ModuleDeclaration;
|
||||
let currentNamespaceContainerName: Identifier;
|
||||
let currentScope: SourceFile | Block | ModuleBlock | CaseBlock;
|
||||
let currentScopeFirstDeclarationsOfName: Map<Node>;
|
||||
let currentScopeFirstDeclarationsOfName: UnderscoreEscapedMap<Node>;
|
||||
|
||||
/**
|
||||
* Keeps track of whether expression substitution has been enabled for specific edge cases.
|
||||
@@ -151,7 +151,17 @@ namespace ts {
|
||||
break;
|
||||
}
|
||||
|
||||
recordEmittedDeclarationInScope(node);
|
||||
// Record these declarations provided that they have a name.
|
||||
if ((node as ClassDeclaration | FunctionDeclaration).name) {
|
||||
recordEmittedDeclarationInScope(node as ClassDeclaration | FunctionDeclaration);
|
||||
}
|
||||
else {
|
||||
// These nodes should always have names unless they are default-exports;
|
||||
// however, class declaration parsing allows for undefined names, so syntactically invalid
|
||||
// programs may also have an undefined name.
|
||||
Debug.assert(node.kind === SyntaxKind.ClassDeclaration || hasModifier(node, ModifierFlags.Default));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -522,7 +532,7 @@ namespace ts {
|
||||
return parameter.decorators !== undefined && parameter.decorators.length > 0;
|
||||
}
|
||||
|
||||
function getClassFacts(node: ClassDeclaration, staticProperties: PropertyDeclaration[]) {
|
||||
function getClassFacts(node: ClassDeclaration, staticProperties: ReadonlyArray<PropertyDeclaration>) {
|
||||
let facts = ClassFacts.None;
|
||||
if (some(staticProperties)) facts |= ClassFacts.HasStaticInitializedProperties;
|
||||
if (getClassExtendsHeritageClauseElement(node)) facts |= ClassFacts.HasExtendsClause;
|
||||
@@ -1051,7 +1061,7 @@ namespace ts {
|
||||
*
|
||||
* @param node The constructor node.
|
||||
*/
|
||||
function getParametersWithPropertyAssignments(node: ConstructorDeclaration): ParameterDeclaration[] {
|
||||
function getParametersWithPropertyAssignments(node: ConstructorDeclaration): ReadonlyArray<ParameterDeclaration> {
|
||||
return filter(node.parameters, isParameterWithPropertyAssignment);
|
||||
}
|
||||
|
||||
@@ -1104,7 +1114,7 @@ namespace ts {
|
||||
* @param node The class node.
|
||||
* @param isStatic A value indicating whether to get properties from the static or instance side of the class.
|
||||
*/
|
||||
function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): PropertyDeclaration[] {
|
||||
function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): ReadonlyArray<PropertyDeclaration> {
|
||||
return filter(node.members, isStatic ? isStaticInitializedProperty : isInstanceInitializedProperty);
|
||||
}
|
||||
|
||||
@@ -1144,7 +1154,7 @@ namespace ts {
|
||||
* @param properties An array of property declarations to transform.
|
||||
* @param receiver The receiver on which each property should be assigned.
|
||||
*/
|
||||
function addInitializedPropertyStatements(statements: Statement[], properties: PropertyDeclaration[], receiver: LeftHandSideExpression) {
|
||||
function addInitializedPropertyStatements(statements: Statement[], properties: ReadonlyArray<PropertyDeclaration>, receiver: LeftHandSideExpression) {
|
||||
for (const property of properties) {
|
||||
const statement = createStatement(transformInitializedProperty(property, receiver));
|
||||
setSourceMapRange(statement, moveRangePastModifiers(property));
|
||||
@@ -1159,7 +1169,7 @@ namespace ts {
|
||||
* @param properties An array of property declarations to transform.
|
||||
* @param receiver The receiver on which each property should be assigned.
|
||||
*/
|
||||
function generateInitializedPropertyExpressions(properties: PropertyDeclaration[], receiver: LeftHandSideExpression) {
|
||||
function generateInitializedPropertyExpressions(properties: ReadonlyArray<PropertyDeclaration>, receiver: LeftHandSideExpression) {
|
||||
const expressions: Expression[] = [];
|
||||
for (const property of properties) {
|
||||
const expression = transformInitializedProperty(property, receiver);
|
||||
@@ -1194,7 +1204,7 @@ namespace ts {
|
||||
* @param isStatic A value indicating whether to retrieve static or instance members of
|
||||
* the class.
|
||||
*/
|
||||
function getDecoratedClassElements(node: ClassExpression | ClassDeclaration, isStatic: boolean): ClassElement[] {
|
||||
function getDecoratedClassElements(node: ClassExpression | ClassDeclaration, isStatic: boolean): ReadonlyArray<ClassElement> {
|
||||
return filter(node.members, isStatic ? isStaticDecoratedClassElement : isInstanceDecoratedClassElement);
|
||||
}
|
||||
|
||||
@@ -1233,8 +1243,8 @@ namespace ts {
|
||||
* A structure describing the decorators for a class element.
|
||||
*/
|
||||
interface AllDecorators {
|
||||
decorators: Decorator[];
|
||||
parameters?: Decorator[][];
|
||||
decorators: ReadonlyArray<Decorator>;
|
||||
parameters?: ReadonlyArray<ReadonlyArray<Decorator>>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1244,7 +1254,7 @@ namespace ts {
|
||||
* @param node The function-like node.
|
||||
*/
|
||||
function getDecoratorsOfParameters(node: FunctionLikeDeclaration) {
|
||||
let decorators: Decorator[][];
|
||||
let decorators: ReadonlyArray<Decorator>[];
|
||||
if (node) {
|
||||
const parameters = node.parameters;
|
||||
for (let i = 0; i < parameters.length; i++) {
|
||||
@@ -1682,7 +1692,7 @@ namespace ts {
|
||||
const valueDeclaration =
|
||||
isClassLike(node)
|
||||
? getFirstConstructorWithBody(node)
|
||||
: isFunctionLike(node) && nodeIsPresent(node.body)
|
||||
: isFunctionLike(node) && nodeIsPresent((node as FunctionLikeDeclaration).body)
|
||||
? node
|
||||
: undefined;
|
||||
|
||||
@@ -1692,7 +1702,7 @@ namespace ts {
|
||||
const numParameters = parameters.length;
|
||||
for (let i = 0; i < numParameters; i++) {
|
||||
const parameter = parameters[i];
|
||||
if (i === 0 && isIdentifier(parameter.name) && parameter.name.text === "this") {
|
||||
if (i === 0 && isIdentifier(parameter.name) && parameter.name.escapedText === "this") {
|
||||
continue;
|
||||
}
|
||||
if (parameter.dotDotDotToken) {
|
||||
@@ -1707,7 +1717,7 @@ namespace ts {
|
||||
return createArrayLiteral(expressions);
|
||||
}
|
||||
|
||||
function getParametersOfDecoratedDeclaration(node: FunctionLikeDeclaration, container: ClassLikeDeclaration) {
|
||||
function getParametersOfDecoratedDeclaration(node: FunctionLike, container: ClassLikeDeclaration) {
|
||||
if (container && node.kind === SyntaxKind.GetAccessor) {
|
||||
const { setAccessor } = getAllAccessorDeclarations(container.members, <AccessorDeclaration>node);
|
||||
if (setAccessor) {
|
||||
@@ -1841,7 +1851,7 @@ namespace ts {
|
||||
for (const typeNode of node.types) {
|
||||
const serializedIndividual = serializeTypeNode(typeNode);
|
||||
|
||||
if (isIdentifier(serializedIndividual) && serializedIndividual.text === "Object") {
|
||||
if (isIdentifier(serializedIndividual) && serializedIndividual.escapedText === "Object") {
|
||||
// One of the individual is global object, return immediately
|
||||
return serializedIndividual;
|
||||
}
|
||||
@@ -1851,7 +1861,7 @@ namespace ts {
|
||||
// Different types
|
||||
if (!isIdentifier(serializedUnion) ||
|
||||
!isIdentifier(serializedIndividual) ||
|
||||
serializedUnion.text !== serializedIndividual.text) {
|
||||
serializedUnion.escapedText !== serializedIndividual.escapedText) {
|
||||
return createIdentifier("Object");
|
||||
}
|
||||
}
|
||||
@@ -2007,7 +2017,7 @@ namespace ts {
|
||||
: (<ComputedPropertyName>name).expression;
|
||||
}
|
||||
else if (isIdentifier(name)) {
|
||||
return createLiteral(unescapeIdentifier(name.text));
|
||||
return createLiteral(unescapeLeadingUnderscores(name.escapedText));
|
||||
}
|
||||
else {
|
||||
return getSynthesizedClone(name);
|
||||
@@ -2639,36 +2649,33 @@ namespace ts {
|
||||
/**
|
||||
* Records that a declaration was emitted in the current scope, if it was the first
|
||||
* declaration for the provided symbol.
|
||||
*
|
||||
* NOTE: if there is ever a transformation above this one, we may not be able to rely
|
||||
* on symbol names.
|
||||
*/
|
||||
function recordEmittedDeclarationInScope(node: Node) {
|
||||
const name = node.symbol && node.symbol.name;
|
||||
if (name) {
|
||||
if (!currentScopeFirstDeclarationsOfName) {
|
||||
currentScopeFirstDeclarationsOfName = createMap<Node>();
|
||||
}
|
||||
function recordEmittedDeclarationInScope(node: FunctionDeclaration | ClassDeclaration | ModuleDeclaration | EnumDeclaration) {
|
||||
if (!currentScopeFirstDeclarationsOfName) {
|
||||
currentScopeFirstDeclarationsOfName = createUnderscoreEscapedMap<Node>();
|
||||
}
|
||||
|
||||
if (!currentScopeFirstDeclarationsOfName.has(name)) {
|
||||
currentScopeFirstDeclarationsOfName.set(name, node);
|
||||
}
|
||||
const name = declaredNameInScope(node);
|
||||
if (!currentScopeFirstDeclarationsOfName.has(name)) {
|
||||
currentScopeFirstDeclarationsOfName.set(name, node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a declaration is the first declaration with the same name emitted
|
||||
* in the current scope.
|
||||
* Determines whether a declaration is the first declaration with
|
||||
* the same name emitted in the current scope.
|
||||
*/
|
||||
function isFirstEmittedDeclarationInScope(node: Node) {
|
||||
function isFirstEmittedDeclarationInScope(node: ModuleDeclaration | EnumDeclaration) {
|
||||
if (currentScopeFirstDeclarationsOfName) {
|
||||
const name = node.symbol && node.symbol.name;
|
||||
if (name) {
|
||||
return currentScopeFirstDeclarationsOfName.get(name) === node;
|
||||
}
|
||||
const name = declaredNameInScope(node);
|
||||
return currentScopeFirstDeclarationsOfName.get(name) === node;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
function declaredNameInScope(node: FunctionDeclaration | ClassDeclaration | ModuleDeclaration | EnumDeclaration): __String {
|
||||
Debug.assertNode(node.name, isIdentifier);
|
||||
return (node.name as Identifier).escapedText;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2746,7 +2753,7 @@ namespace ts {
|
||||
return createNotEmittedStatement(node);
|
||||
}
|
||||
|
||||
Debug.assert(isIdentifier(node.name), "TypeScript module should have an Identifier name.");
|
||||
Debug.assertNode(node.name, isIdentifier, "A TypeScript namespace should have an Identifier name.");
|
||||
enableSubstitutionForNamespaceExports();
|
||||
|
||||
const statements: Statement[] = [];
|
||||
@@ -3158,7 +3165,7 @@ namespace ts {
|
||||
getExternalModuleOrNamespaceExportName(currentNamespaceContainerName, node, /*allowComments*/ false, /*allowSourceMaps*/ true),
|
||||
getLocalName(node)
|
||||
);
|
||||
setSourceMapRange(expression, createRange(node.name.pos, node.end));
|
||||
setSourceMapRange(expression, createRange(node.name ? node.name.pos : node.pos, node.end));
|
||||
|
||||
const statement = createStatement(expression);
|
||||
setSourceMapRange(statement, createRange(-1, node.end));
|
||||
@@ -3210,7 +3217,7 @@ namespace ts {
|
||||
function getClassAliasIfNeeded(node: ClassDeclaration) {
|
||||
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference) {
|
||||
enableSubstitutionForClassAliases();
|
||||
const classAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? unescapeIdentifier(node.name.text) : "default");
|
||||
const classAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? unescapeLeadingUnderscores(node.name.escapedText) : "default");
|
||||
classAliases[getOriginalNodeId(node)] = classAlias;
|
||||
hoistVariableDeclaration(classAlias);
|
||||
return classAlias;
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export function getOriginalNodeId(node: Node) {
|
||||
node = getOriginalNode(node);
|
||||
return node ? getNodeId(node) : 0;
|
||||
}
|
||||
|
||||
export interface ExternalModuleInfo {
|
||||
externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[]; // imports of other external modules
|
||||
externalHelpersImportDeclaration: ImportDeclaration | undefined; // import of external helpers
|
||||
exportSpecifiers: Map<ExportSpecifier[]>; // export specifiers by name
|
||||
exportedBindings: Identifier[][]; // exported names of local declarations
|
||||
exportedNames: Identifier[]; // all exported names local to module
|
||||
exportEquals: ExportAssignment | undefined; // an export= declaration if one was present
|
||||
hasExportStarsToExportValues: boolean; // whether this module contains export*
|
||||
}
|
||||
|
||||
export function collectExternalModuleInfo(sourceFile: SourceFile, resolver: EmitResolver, compilerOptions: CompilerOptions): ExternalModuleInfo {
|
||||
const externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[] = [];
|
||||
const exportSpecifiers = createMultiMap<ExportSpecifier>();
|
||||
const exportedBindings: Identifier[][] = [];
|
||||
const uniqueExports = createMap<boolean>();
|
||||
let exportedNames: Identifier[];
|
||||
let hasExportDefault = false;
|
||||
let exportEquals: ExportAssignment = undefined;
|
||||
let hasExportStarsToExportValues = false;
|
||||
|
||||
for (const node of sourceFile.statements) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
// import "mod"
|
||||
// import x from "mod"
|
||||
// import * as x from "mod"
|
||||
// import { x, y } from "mod"
|
||||
externalImports.push(<ImportDeclaration>node);
|
||||
break;
|
||||
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
if ((<ImportEqualsDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference) {
|
||||
// import x = require("mod")
|
||||
externalImports.push(<ImportEqualsDeclaration>node);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
if ((<ExportDeclaration>node).moduleSpecifier) {
|
||||
if (!(<ExportDeclaration>node).exportClause) {
|
||||
// export * from "mod"
|
||||
externalImports.push(<ExportDeclaration>node);
|
||||
hasExportStarsToExportValues = true;
|
||||
}
|
||||
else {
|
||||
// export { x, y } from "mod"
|
||||
externalImports.push(<ExportDeclaration>node);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// export { x, y }
|
||||
for (const specifier of (<ExportDeclaration>node).exportClause.elements) {
|
||||
if (!uniqueExports.get(unescapeLeadingUnderscores(specifier.name.escapedText))) {
|
||||
const name = specifier.propertyName || specifier.name;
|
||||
exportSpecifiers.add(unescapeLeadingUnderscores(name.escapedText), specifier);
|
||||
|
||||
const decl = resolver.getReferencedImportDeclaration(name)
|
||||
|| resolver.getReferencedValueDeclaration(name);
|
||||
|
||||
if (decl) {
|
||||
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(decl), specifier.name);
|
||||
}
|
||||
|
||||
uniqueExports.set(unescapeLeadingUnderscores(specifier.name.escapedText), true);
|
||||
exportedNames = append(exportedNames, specifier.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.ExportAssignment:
|
||||
if ((<ExportAssignment>node).isExportEquals && !exportEquals) {
|
||||
// export = x
|
||||
exportEquals = <ExportAssignment>node;
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.VariableStatement:
|
||||
if (hasModifier(node, ModifierFlags.Export)) {
|
||||
for (const decl of (<VariableStatement>node).declarationList.declarations) {
|
||||
exportedNames = collectExportedVariableInfo(decl, uniqueExports, exportedNames);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
if (hasModifier(node, ModifierFlags.Export)) {
|
||||
if (hasModifier(node, ModifierFlags.Default)) {
|
||||
// export default function() { }
|
||||
if (!hasExportDefault) {
|
||||
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), getDeclarationName(<FunctionDeclaration>node));
|
||||
hasExportDefault = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// export function x() { }
|
||||
const name = (<FunctionDeclaration>node).name;
|
||||
if (!uniqueExports.get(unescapeLeadingUnderscores(name.escapedText))) {
|
||||
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
|
||||
uniqueExports.set(unescapeLeadingUnderscores(name.escapedText), true);
|
||||
exportedNames = append(exportedNames, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
if (hasModifier(node, ModifierFlags.Export)) {
|
||||
if (hasModifier(node, ModifierFlags.Default)) {
|
||||
// export default class { }
|
||||
if (!hasExportDefault) {
|
||||
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), getDeclarationName(<ClassDeclaration>node));
|
||||
hasExportDefault = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// export class x { }
|
||||
const name = (<ClassDeclaration>node).name;
|
||||
if (!uniqueExports.get(unescapeLeadingUnderscores(name.escapedText))) {
|
||||
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
|
||||
uniqueExports.set(unescapeLeadingUnderscores(name.escapedText), true);
|
||||
exportedNames = append(exportedNames, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(sourceFile, compilerOptions, hasExportStarsToExportValues);
|
||||
const externalHelpersImportDeclaration = externalHelpersModuleName && createImportDeclaration(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
createImportClause(/*name*/ undefined, createNamespaceImport(externalHelpersModuleName)),
|
||||
createLiteral(externalHelpersModuleNameText));
|
||||
|
||||
if (externalHelpersImportDeclaration) {
|
||||
externalImports.unshift(externalHelpersImportDeclaration);
|
||||
}
|
||||
|
||||
return { externalImports, exportSpecifiers, exportEquals, hasExportStarsToExportValues, exportedBindings, exportedNames, externalHelpersImportDeclaration };
|
||||
}
|
||||
|
||||
function collectExportedVariableInfo(decl: VariableDeclaration | BindingElement, uniqueExports: Map<boolean>, exportedNames: Identifier[]) {
|
||||
if (isBindingPattern(decl.name)) {
|
||||
for (const element of decl.name.elements) {
|
||||
if (!isOmittedExpression(element)) {
|
||||
exportedNames = collectExportedVariableInfo(element, uniqueExports, exportedNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!isGeneratedIdentifier(decl.name)) {
|
||||
if (!uniqueExports.get(unescapeLeadingUnderscores(decl.name.escapedText))) {
|
||||
uniqueExports.set(unescapeLeadingUnderscores(decl.name.escapedText), true);
|
||||
exportedNames = append(exportedNames, decl.name);
|
||||
}
|
||||
}
|
||||
return exportedNames;
|
||||
}
|
||||
|
||||
/** Use a sparse array as a multi-map. */
|
||||
function multiMapSparseArrayAdd<V>(map: V[][], key: number, value: V): V[] {
|
||||
let values = map[key];
|
||||
if (values) {
|
||||
values.push(value);
|
||||
}
|
||||
else {
|
||||
map[key] = values = [value];
|
||||
}
|
||||
return values;
|
||||
}
|
||||
}
|
||||
+26
-17
@@ -61,7 +61,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function reportDiagnosticWithColorAndContext(diagnostic: Diagnostic, host: FormatDiagnosticsHost): void {
|
||||
sys.write(ts.formatDiagnosticsWithColorAndContext([diagnostic], host) + sys.newLine + sys.newLine);
|
||||
sys.write(ts.formatDiagnosticsWithColorAndContext([diagnostic], host) + sys.newLine);
|
||||
}
|
||||
|
||||
function reportWatchDiagnostic(diagnostic: Diagnostic) {
|
||||
@@ -223,20 +223,13 @@ namespace ts {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = parseConfigFileTextToJson(configFileName, cachedConfigFileText);
|
||||
const configObject = result.config;
|
||||
if (!configObject) {
|
||||
reportDiagnostics([result.error], /* compilerHost */ undefined);
|
||||
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
return;
|
||||
}
|
||||
const result = parseJsonText(configFileName, cachedConfigFileText);
|
||||
reportDiagnostics(result.parseDiagnostics, /* compilerHost */ undefined);
|
||||
|
||||
const cwd = sys.getCurrentDirectory();
|
||||
const configParseResult = parseJsonConfigFileContent(configObject, sys, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), commandLine.options, getNormalizedAbsolutePath(configFileName, cwd));
|
||||
if (configParseResult.errors.length > 0) {
|
||||
reportDiagnostics(configParseResult.errors, /* compilerHost */ undefined);
|
||||
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
return;
|
||||
}
|
||||
const configParseResult = parseJsonSourceFileConfigFileContent(result, sys, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), commandLine.options, getNormalizedAbsolutePath(configFileName, cwd));
|
||||
reportDiagnostics(configParseResult.errors, /* compilerHost */ undefined);
|
||||
|
||||
if (isWatchSet(configParseResult.options)) {
|
||||
if (!sys.watchFile) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"), /* host */ undefined);
|
||||
@@ -292,6 +285,16 @@ namespace ts {
|
||||
|
||||
setCachedProgram(compileResult.program);
|
||||
reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes));
|
||||
|
||||
const missingPaths = compileResult.program.getMissingFilePaths();
|
||||
missingPaths.forEach(path => {
|
||||
const fileWatcher = sys.watchFile(path, (_fileName, eventKind) => {
|
||||
if (eventKind === FileWatcherEventKind.Created) {
|
||||
fileWatcher.close();
|
||||
startTimerForRecompilation();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function cachedFileExists(fileName: string): boolean {
|
||||
@@ -315,7 +318,7 @@ namespace ts {
|
||||
const sourceFile = hostGetSourceFile(fileName, languageVersion, onError);
|
||||
if (sourceFile && isWatchSet(compilerOptions) && sys.watchFile) {
|
||||
// Attach a file watcher
|
||||
sourceFile.fileWatcher = sys.watchFile(sourceFile.fileName, (_fileName: string, removed?: boolean) => sourceFileChanged(sourceFile, removed));
|
||||
sourceFile.fileWatcher = sys.watchFile(sourceFile.fileName, (_fileName, eventKind) => sourceFileChanged(sourceFile, eventKind));
|
||||
}
|
||||
return sourceFile;
|
||||
}
|
||||
@@ -337,10 +340,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
// If a source file changes, mark it as unwatched and start the recompilation timer
|
||||
function sourceFileChanged(sourceFile: SourceFile, removed?: boolean) {
|
||||
function sourceFileChanged(sourceFile: SourceFile, eventKind: FileWatcherEventKind) {
|
||||
sourceFile.fileWatcher.close();
|
||||
sourceFile.fileWatcher = undefined;
|
||||
if (removed) {
|
||||
if (eventKind === FileWatcherEventKind.Deleted) {
|
||||
unorderedRemoveItem(rootFileNames, sourceFile.fileName);
|
||||
}
|
||||
startTimerForRecompilation();
|
||||
@@ -662,6 +665,12 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
ts.setStackTraceLimit();
|
||||
|
||||
if (ts.Debug.isDebugging) {
|
||||
ts.Debug.enableDebugInfo();
|
||||
}
|
||||
|
||||
if (ts.sys.tryEnableSourceMapsForHost && /^development$/i.test(ts.sys.getEnvironmentVariable("NODE_ENV"))) {
|
||||
ts.sys.tryEnableSourceMapsForHost();
|
||||
}
|
||||
|
||||
@@ -14,9 +14,11 @@
|
||||
"parser.ts",
|
||||
"utilities.ts",
|
||||
"binder.ts",
|
||||
"symbolWalker.ts",
|
||||
"checker.ts",
|
||||
"factory.ts",
|
||||
"visitor.ts",
|
||||
"transformers/utilities.ts",
|
||||
"transformers/ts.ts",
|
||||
"transformers/jsx.ts",
|
||||
"transformers/esnext.ts",
|
||||
@@ -25,7 +27,6 @@
|
||||
"transformers/es2015.ts",
|
||||
"transformers/es5.ts",
|
||||
"transformers/generators.ts",
|
||||
"transformers/es5.ts",
|
||||
"transformers/destructuring.ts",
|
||||
"transformers/module/module.ts",
|
||||
"transformers/module/system.ts",
|
||||
|
||||
+324
-207
File diff suppressed because it is too large
Load Diff
+494
-496
File diff suppressed because it is too large
Load Diff
+71
-56
@@ -86,7 +86,7 @@ namespace ts {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
let updated: NodeArray<T>;
|
||||
let updated: MutableNodeArray<T>;
|
||||
|
||||
// Ensure start and count have valid values
|
||||
const length = nodes.length;
|
||||
@@ -270,12 +270,13 @@ namespace ts {
|
||||
nodesVisitor((<PropertyDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<PropertyDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<PropertyDeclaration>node).name, visitor, isPropertyName),
|
||||
visitNode((<PropertyDeclaration>node).questionToken, tokenVisitor, isToken),
|
||||
visitNode((<PropertyDeclaration>node).type, visitor, isTypeNode),
|
||||
visitNode((<PropertyDeclaration>node).initializer, visitor, isExpression));
|
||||
|
||||
case SyntaxKind.MethodSignature:
|
||||
return updateMethodSignature(<MethodSignature>node,
|
||||
nodesVisitor((<MethodSignature>node).typeParameters, visitor, isTypeParameter),
|
||||
nodesVisitor((<MethodSignature>node).typeParameters, visitor, isTypeParameterDeclaration),
|
||||
nodesVisitor((<MethodSignature>node).parameters, visitor, isParameterDeclaration),
|
||||
visitNode((<MethodSignature>node).type, visitor, isTypeNode),
|
||||
visitNode((<MethodSignature>node).name, visitor, isPropertyName),
|
||||
@@ -288,7 +289,7 @@ namespace ts {
|
||||
visitNode((<MethodDeclaration>node).asteriskToken, tokenVisitor, isToken),
|
||||
visitNode((<MethodDeclaration>node).name, visitor, isPropertyName),
|
||||
visitNode((<MethodDeclaration>node).questionToken, tokenVisitor, isToken),
|
||||
nodesVisitor((<MethodDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
nodesVisitor((<MethodDeclaration>node).typeParameters, visitor, isTypeParameterDeclaration),
|
||||
visitParameterList((<MethodDeclaration>node).parameters, visitor, context, nodesVisitor),
|
||||
visitNode((<MethodDeclaration>node).type, visitor, isTypeNode),
|
||||
visitFunctionBody((<MethodDeclaration>node).body, visitor, context));
|
||||
@@ -319,13 +320,13 @@ namespace ts {
|
||||
|
||||
case SyntaxKind.CallSignature:
|
||||
return updateCallSignature(<CallSignatureDeclaration>node,
|
||||
nodesVisitor((<CallSignatureDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
nodesVisitor((<CallSignatureDeclaration>node).typeParameters, visitor, isTypeParameterDeclaration),
|
||||
nodesVisitor((<CallSignatureDeclaration>node).parameters, visitor, isParameterDeclaration),
|
||||
visitNode((<CallSignatureDeclaration>node).type, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.ConstructSignature:
|
||||
return updateConstructSignature(<ConstructSignatureDeclaration>node,
|
||||
nodesVisitor((<ConstructSignatureDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
nodesVisitor((<ConstructSignatureDeclaration>node).typeParameters, visitor, isTypeParameterDeclaration),
|
||||
nodesVisitor((<ConstructSignatureDeclaration>node).parameters, visitor, isParameterDeclaration),
|
||||
visitNode((<ConstructSignatureDeclaration>node).type, visitor, isTypeNode));
|
||||
|
||||
@@ -350,13 +351,13 @@ namespace ts {
|
||||
|
||||
case SyntaxKind.FunctionType:
|
||||
return updateFunctionTypeNode(<FunctionTypeNode>node,
|
||||
nodesVisitor((<FunctionTypeNode>node).typeParameters, visitor, isTypeParameter),
|
||||
nodesVisitor((<FunctionTypeNode>node).typeParameters, visitor, isTypeParameterDeclaration),
|
||||
nodesVisitor((<FunctionTypeNode>node).parameters, visitor, isParameterDeclaration),
|
||||
visitNode((<FunctionTypeNode>node).type, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.ConstructorType:
|
||||
return updateConstructorTypeNode(<ConstructorTypeNode>node,
|
||||
nodesVisitor((<ConstructorTypeNode>node).typeParameters, visitor, isTypeParameter),
|
||||
nodesVisitor((<ConstructorTypeNode>node).typeParameters, visitor, isTypeParameterDeclaration),
|
||||
nodesVisitor((<ConstructorTypeNode>node).parameters, visitor, isParameterDeclaration),
|
||||
visitNode((<ConstructorTypeNode>node).type, visitor, isTypeNode));
|
||||
|
||||
@@ -400,7 +401,7 @@ namespace ts {
|
||||
case SyntaxKind.MappedType:
|
||||
return updateMappedTypeNode((<MappedTypeNode>node),
|
||||
visitNode((<MappedTypeNode>node).readonlyToken, tokenVisitor, isToken),
|
||||
visitNode((<MappedTypeNode>node).typeParameter, visitor, isTypeParameter),
|
||||
visitNode((<MappedTypeNode>node).typeParameter, visitor, isTypeParameterDeclaration),
|
||||
visitNode((<MappedTypeNode>node).questionToken, tokenVisitor, isToken),
|
||||
visitNode((<MappedTypeNode>node).type, visitor, isTypeNode));
|
||||
|
||||
@@ -476,7 +477,7 @@ namespace ts {
|
||||
nodesVisitor((<FunctionExpression>node).modifiers, visitor, isModifier),
|
||||
visitNode((<FunctionExpression>node).asteriskToken, tokenVisitor, isToken),
|
||||
visitNode((<FunctionExpression>node).name, visitor, isIdentifier),
|
||||
nodesVisitor((<FunctionExpression>node).typeParameters, visitor, isTypeParameter),
|
||||
nodesVisitor((<FunctionExpression>node).typeParameters, visitor, isTypeParameterDeclaration),
|
||||
visitParameterList((<FunctionExpression>node).parameters, visitor, context, nodesVisitor),
|
||||
visitNode((<FunctionExpression>node).type, visitor, isTypeNode),
|
||||
visitFunctionBody((<FunctionExpression>node).body, visitor, context));
|
||||
@@ -484,7 +485,7 @@ namespace ts {
|
||||
case SyntaxKind.ArrowFunction:
|
||||
return updateArrowFunction(<ArrowFunction>node,
|
||||
nodesVisitor((<ArrowFunction>node).modifiers, visitor, isModifier),
|
||||
nodesVisitor((<ArrowFunction>node).typeParameters, visitor, isTypeParameter),
|
||||
nodesVisitor((<ArrowFunction>node).typeParameters, visitor, isTypeParameterDeclaration),
|
||||
visitParameterList((<ArrowFunction>node).parameters, visitor, context, nodesVisitor),
|
||||
visitNode((<ArrowFunction>node).type, visitor, isTypeNode),
|
||||
visitFunctionBody((<ArrowFunction>node).body, visitor, context));
|
||||
@@ -543,7 +544,7 @@ namespace ts {
|
||||
return updateClassExpression(<ClassExpression>node,
|
||||
nodesVisitor((<ClassExpression>node).modifiers, visitor, isModifier),
|
||||
visitNode((<ClassExpression>node).name, visitor, isIdentifier),
|
||||
nodesVisitor((<ClassExpression>node).typeParameters, visitor, isTypeParameter),
|
||||
nodesVisitor((<ClassExpression>node).typeParameters, visitor, isTypeParameterDeclaration),
|
||||
nodesVisitor((<ClassExpression>node).heritageClauses, visitor, isHeritageClause),
|
||||
nodesVisitor((<ClassExpression>node).members, visitor, isClassElement));
|
||||
|
||||
@@ -676,7 +677,7 @@ namespace ts {
|
||||
nodesVisitor((<FunctionDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<FunctionDeclaration>node).asteriskToken, tokenVisitor, isToken),
|
||||
visitNode((<FunctionDeclaration>node).name, visitor, isIdentifier),
|
||||
nodesVisitor((<FunctionDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
nodesVisitor((<FunctionDeclaration>node).typeParameters, visitor, isTypeParameterDeclaration),
|
||||
visitParameterList((<FunctionDeclaration>node).parameters, visitor, context, nodesVisitor),
|
||||
visitNode((<FunctionDeclaration>node).type, visitor, isTypeNode),
|
||||
visitFunctionBody((<FunctionExpression>node).body, visitor, context));
|
||||
@@ -686,7 +687,7 @@ namespace ts {
|
||||
nodesVisitor((<ClassDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<ClassDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<ClassDeclaration>node).name, visitor, isIdentifier),
|
||||
nodesVisitor((<ClassDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
nodesVisitor((<ClassDeclaration>node).typeParameters, visitor, isTypeParameterDeclaration),
|
||||
nodesVisitor((<ClassDeclaration>node).heritageClauses, visitor, isHeritageClause),
|
||||
nodesVisitor((<ClassDeclaration>node).members, visitor, isClassElement));
|
||||
|
||||
@@ -695,7 +696,7 @@ namespace ts {
|
||||
nodesVisitor((<InterfaceDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<InterfaceDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<InterfaceDeclaration>node).name, visitor, isIdentifier),
|
||||
nodesVisitor((<InterfaceDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
nodesVisitor((<InterfaceDeclaration>node).typeParameters, visitor, isTypeParameterDeclaration),
|
||||
nodesVisitor((<InterfaceDeclaration>node).heritageClauses, visitor, isHeritageClause),
|
||||
nodesVisitor((<InterfaceDeclaration>node).members, visitor, isTypeElement));
|
||||
|
||||
@@ -704,7 +705,7 @@ namespace ts {
|
||||
nodesVisitor((<TypeAliasDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<TypeAliasDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitNode((<TypeAliasDeclaration>node).name, visitor, isIdentifier),
|
||||
nodesVisitor((<TypeAliasDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
nodesVisitor((<TypeAliasDeclaration>node).typeParameters, visitor, isTypeParameterDeclaration),
|
||||
visitNode((<TypeAliasDeclaration>node).type, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
@@ -900,7 +901,7 @@ namespace ts {
|
||||
*
|
||||
* @param nodes The NodeArray.
|
||||
*/
|
||||
function extractSingleNode(nodes: Node[]): Node {
|
||||
function extractSingleNode(nodes: ReadonlyArray<Node>): Node {
|
||||
Debug.assert(nodes.length <= 1, "Too many nodes written to output.");
|
||||
return singleOrUndefined(nodes);
|
||||
}
|
||||
@@ -1148,10 +1149,6 @@ namespace ts {
|
||||
result = reduceNode((<AsExpression>node).type, cbNode, result);
|
||||
break;
|
||||
|
||||
case SyntaxKind.NonNullExpression:
|
||||
result = reduceNode((<NonNullExpression>node).expression, cbNode, result);
|
||||
break;
|
||||
|
||||
// Misc
|
||||
case SyntaxKind.TemplateSpan:
|
||||
result = reduceNode((<TemplateSpan>node).expression, cbNode, result);
|
||||
@@ -1198,9 +1195,9 @@ namespace ts {
|
||||
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.ForOfStatement:
|
||||
result = reduceNode((<ForInStatement | ForOfStatement>node).initializer, cbNode, result);
|
||||
result = reduceNode((<ForInStatement | ForOfStatement>node).expression, cbNode, result);
|
||||
result = reduceNode((<ForInStatement | ForOfStatement>node).statement, cbNode, result);
|
||||
result = reduceNode((<ForInOrOfStatement>node).initializer, cbNode, result);
|
||||
result = reduceNode((<ForInOrOfStatement>node).expression, cbNode, result);
|
||||
result = reduceNode((<ForInOrOfStatement>node).statement, cbNode, result);
|
||||
break;
|
||||
|
||||
case SyntaxKind.ReturnStatement:
|
||||
@@ -1424,13 +1421,13 @@ namespace ts {
|
||||
/**
|
||||
* Merges generated lexical declarations into a new statement list.
|
||||
*/
|
||||
export function mergeLexicalEnvironment(statements: NodeArray<Statement>, declarations: Statement[]): NodeArray<Statement>;
|
||||
export function mergeLexicalEnvironment(statements: NodeArray<Statement>, declarations: ReadonlyArray<Statement>): NodeArray<Statement>;
|
||||
|
||||
/**
|
||||
* Appends generated lexical declarations to an array of statements.
|
||||
*/
|
||||
export function mergeLexicalEnvironment(statements: Statement[], declarations: Statement[]): Statement[];
|
||||
export function mergeLexicalEnvironment(statements: Statement[], declarations: Statement[]) {
|
||||
export function mergeLexicalEnvironment(statements: Statement[], declarations: ReadonlyArray<Statement>): Statement[];
|
||||
export function mergeLexicalEnvironment(statements: Statement[] | NodeArray<Statement>, declarations: ReadonlyArray<Statement>) {
|
||||
if (!some(declarations)) {
|
||||
return statements;
|
||||
}
|
||||
@@ -1445,7 +1442,7 @@ namespace ts {
|
||||
*
|
||||
* @param nodes The NodeArray.
|
||||
*/
|
||||
export function liftToBlock(nodes: Node[]): Statement {
|
||||
export function liftToBlock(nodes: ReadonlyArray<Node>): Statement {
|
||||
Debug.assert(every(nodes, isStatement), "Cannot lift nodes to a Block.");
|
||||
return <Statement>singleOrUndefined(nodes) || createBlock(<NodeArray<Statement>>nodes);
|
||||
}
|
||||
@@ -1517,35 +1514,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export namespace Debug {
|
||||
if (isDebugging) {
|
||||
// Add additional properties in debug mode to assist with debugging.
|
||||
Object.defineProperties(objectAllocator.getSymbolConstructor().prototype, {
|
||||
"__debugFlags": { get(this: Symbol) { return formatSymbolFlags(this.flags); } }
|
||||
});
|
||||
|
||||
Object.defineProperties(objectAllocator.getTypeConstructor().prototype, {
|
||||
"__debugFlags": { get(this: Type) { return formatTypeFlags(this.flags); } },
|
||||
"__debugObjectFlags": { get(this: Type) { return this.flags & TypeFlags.Object ? formatObjectFlags((<ObjectType>this).objectFlags) : ""; } },
|
||||
"__debugTypeToString": { value(this: Type) { return this.checker.typeToString(this); } },
|
||||
});
|
||||
|
||||
for (const ctor of [objectAllocator.getNodeConstructor(), objectAllocator.getIdentifierConstructor(), objectAllocator.getTokenConstructor(), objectAllocator.getSourceFileConstructor()]) {
|
||||
if (!ctor.prototype.hasOwnProperty("__debugKind")) {
|
||||
Object.defineProperties(ctor.prototype, {
|
||||
"__debugKind": { get(this: Node) { return formatSyntaxKind(this.kind); } },
|
||||
"__debugModifierFlags": { get(this: Node) { return formatModifierFlags(getModifierFlagsNoCache(this)); } },
|
||||
"__debugTransformFlags": { get(this: Node) { return formatTransformFlags(this.transformFlags); } },
|
||||
"__debugEmitFlags": { get(this: Node) { return formatEmitFlags(getEmitFlags(this)); } },
|
||||
"__debugGetText": { value(this: Node, includeTrivia?: boolean) {
|
||||
if (nodeIsSynthesized(this)) return "";
|
||||
const parseNode = getParseTreeNode(this);
|
||||
const sourceFile = parseNode && getSourceFileOfNode(parseNode);
|
||||
return sourceFile ? getSourceTextOfNodeFromSourceFile(sourceFile, parseNode, includeTrivia) : "";
|
||||
} }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
let isDebugInfoEnabled = false;
|
||||
|
||||
export const failBadSyntaxKind = shouldAssert(AssertionLevel.Normal)
|
||||
? (node: Node, message?: string): void => fail(
|
||||
@@ -1592,5 +1561,51 @@ namespace ts {
|
||||
() => `Node ${formatSyntaxKind(node.kind)} was unexpected'.`,
|
||||
assertMissingNode)
|
||||
: noop;
|
||||
|
||||
/**
|
||||
* Injects debug information into frequently used types.
|
||||
*/
|
||||
export function enableDebugInfo() {
|
||||
if (isDebugInfoEnabled) return;
|
||||
|
||||
// Add additional properties in debug mode to assist with debugging.
|
||||
Object.defineProperties(objectAllocator.getSymbolConstructor().prototype, {
|
||||
"__debugFlags": { get(this: Symbol) { return formatSymbolFlags(this.flags); } }
|
||||
});
|
||||
|
||||
Object.defineProperties(objectAllocator.getTypeConstructor().prototype, {
|
||||
"__debugFlags": { get(this: Type) { return formatTypeFlags(this.flags); } },
|
||||
"__debugObjectFlags": { get(this: Type) { return this.flags & TypeFlags.Object ? formatObjectFlags((<ObjectType>this).objectFlags) : ""; } },
|
||||
"__debugTypeToString": { value(this: Type) { return this.checker.typeToString(this); } },
|
||||
});
|
||||
|
||||
const nodeConstructors = [
|
||||
objectAllocator.getNodeConstructor(),
|
||||
objectAllocator.getIdentifierConstructor(),
|
||||
objectAllocator.getTokenConstructor(),
|
||||
objectAllocator.getSourceFileConstructor()
|
||||
];
|
||||
|
||||
for (const ctor of nodeConstructors) {
|
||||
if (!ctor.prototype.hasOwnProperty("__debugKind")) {
|
||||
Object.defineProperties(ctor.prototype, {
|
||||
"__debugKind": { get(this: Node) { return formatSyntaxKind(this.kind); } },
|
||||
"__debugModifierFlags": { get(this: Node) { return formatModifierFlags(getModifierFlagsNoCache(this)); } },
|
||||
"__debugTransformFlags": { get(this: Node) { return formatTransformFlags(this.transformFlags); } },
|
||||
"__debugEmitFlags": { get(this: Node) { return formatEmitFlags(getEmitFlags(this)); } },
|
||||
"__debugGetText": {
|
||||
value(this: Node, includeTrivia?: boolean) {
|
||||
if (nodeIsSynthesized(this)) return "";
|
||||
const parseNode = getParseTreeNode(this);
|
||||
const sourceFile = parseNode && getSourceFileOfNode(parseNode);
|
||||
return sourceFile ? getSourceTextOfNodeFromSourceFile(sourceFile, parseNode, includeTrivia) : "";
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
isDebugInfoEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
|
||||
let result: Harness.Compiler.CompilerResult;
|
||||
let options: ts.CompilerOptions;
|
||||
let tsConfigFiles: Harness.Compiler.TestFile[];
|
||||
// equivalent to the files that will be passed on the command line
|
||||
let toBeCompiled: Harness.Compiler.TestFile[];
|
||||
// equivalent to other files on the file system not directly passed to the compiler (ie things that are referenced by other files)
|
||||
@@ -77,10 +78,12 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
const units = testCaseContent.testUnitData;
|
||||
harnessSettings = testCaseContent.settings;
|
||||
let tsConfigOptions: ts.CompilerOptions;
|
||||
tsConfigFiles = [];
|
||||
if (testCaseContent.tsConfig) {
|
||||
assert.equal(testCaseContent.tsConfig.fileNames.length, 0, `list of files in tsconfig is not currently supported`);
|
||||
|
||||
tsConfigOptions = ts.clone(testCaseContent.tsConfig.options);
|
||||
tsConfigOptions = ts.cloneCompilerOptions(testCaseContent.tsConfig.options);
|
||||
tsConfigFiles.push(this.createHarnessTestFile(testCaseContent.tsConfigFileUnitData, rootDir, ts.combinePaths(rootDir, tsConfigOptions.configFilePath)));
|
||||
}
|
||||
else {
|
||||
const baseUrl = harnessSettings["baseUrl"];
|
||||
@@ -90,7 +93,7 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
}
|
||||
|
||||
lastUnit = units[units.length - 1];
|
||||
hasNonDtsFiles = ts.forEach(units, unit => !ts.fileExtensionIs(unit.name, ".d.ts"));
|
||||
hasNonDtsFiles = ts.forEach(units, unit => !ts.fileExtensionIs(unit.name, ts.Extension.Dts));
|
||||
// We need to assemble the list of input files for the compiler and other related files on the 'filesystem' (ie in a multi-file test)
|
||||
// If the last file in a test uses require or a triple slash reference we'll assume all other files will be brought in via references,
|
||||
// otherwise, assume all files are just meant to be in the same compilation session without explicit references to one another.
|
||||
@@ -98,21 +101,22 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
otherFiles = [];
|
||||
|
||||
if (testCaseContent.settings["noImplicitReferences"] || /require\(/.test(lastUnit.content) || /reference\spath/.test(lastUnit.content)) {
|
||||
toBeCompiled.push({ unitName: this.makeUnitName(lastUnit.name, rootDir), content: lastUnit.content, fileOptions: lastUnit.fileOptions });
|
||||
toBeCompiled.push(this.createHarnessTestFile(lastUnit, rootDir));
|
||||
units.forEach(unit => {
|
||||
if (unit.name !== lastUnit.name) {
|
||||
otherFiles.push({ unitName: this.makeUnitName(unit.name, rootDir), content: unit.content, fileOptions: unit.fileOptions });
|
||||
otherFiles.push(this.createHarnessTestFile(unit, rootDir));
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
toBeCompiled = units.map(unit => {
|
||||
return { unitName: this.makeUnitName(unit.name, rootDir), content: unit.content, fileOptions: unit.fileOptions };
|
||||
return this.createHarnessTestFile(unit, rootDir);
|
||||
});
|
||||
}
|
||||
|
||||
if (tsConfigOptions && tsConfigOptions.configFilePath !== undefined) {
|
||||
tsConfigOptions.configFilePath = ts.combinePaths(rootDir, tsConfigOptions.configFilePath);
|
||||
tsConfigOptions.configFile.fileName = tsConfigOptions.configFilePath;
|
||||
}
|
||||
|
||||
const output = Harness.Compiler.compileFiles(
|
||||
@@ -132,11 +136,12 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
options = undefined;
|
||||
toBeCompiled = undefined;
|
||||
otherFiles = undefined;
|
||||
tsConfigFiles = undefined;
|
||||
});
|
||||
|
||||
// check errors
|
||||
it("Correct errors for " + fileName, () => {
|
||||
Harness.Compiler.doErrorBaseline(justName, toBeCompiled.concat(otherFiles), result.errors);
|
||||
Harness.Compiler.doErrorBaseline(justName, tsConfigFiles.concat(toBeCompiled, otherFiles), result.errors);
|
||||
});
|
||||
|
||||
it (`Correct module resolution tracing for ${fileName}`, () => {
|
||||
@@ -165,7 +170,7 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
|
||||
it("Correct JS output for " + fileName, () => {
|
||||
if (hasNonDtsFiles && this.emit) {
|
||||
Harness.Compiler.doJsEmitBaseline(justName, fileName, options, result, toBeCompiled, otherFiles, harnessSettings);
|
||||
Harness.Compiler.doJsEmitBaseline(justName, fileName, options, result, tsConfigFiles, toBeCompiled, otherFiles, harnessSettings);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -183,6 +188,10 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
});
|
||||
}
|
||||
|
||||
private createHarnessTestFile(lastUnit: Harness.TestCaseParser.TestUnitData, rootDir: string, unitName?: string): Harness.Compiler.TestFile {
|
||||
return { unitName: unitName || this.makeUnitName(lastUnit.name, rootDir), content: lastUnit.content, fileOptions: lastUnit.fileOptions };
|
||||
}
|
||||
|
||||
public initializeTests() {
|
||||
describe(this.testSuiteName + " tests", () => {
|
||||
describe("Setup compiler for compiler baselines", () => {
|
||||
|
||||
+247
-153
@@ -130,7 +130,7 @@ namespace FourSlash {
|
||||
// 0 - cancelled
|
||||
// >0 - not cancelled
|
||||
// <0 - not cancelled and value denotes number of isCancellationRequested after which token become cancelled
|
||||
private static NotCanceled: number = -1;
|
||||
private static readonly NotCanceled: number = -1;
|
||||
private numberOfCallsBeforeCancellation: number = TestCancellationToken.NotCanceled;
|
||||
|
||||
public isCancellationRequested(): boolean {
|
||||
@@ -187,6 +187,9 @@ namespace FourSlash {
|
||||
|
||||
// The current caret position in the active file
|
||||
public currentCaretPosition = 0;
|
||||
// The position of the end of the current selection, or -1 if nothing is selected
|
||||
public selectionEnd = -1;
|
||||
|
||||
public lastKnownMarker = "";
|
||||
|
||||
// The file that's currently 'opened'
|
||||
@@ -219,7 +222,7 @@ namespace FourSlash {
|
||||
|
||||
// Add input file which has matched file name with the given reference-file path.
|
||||
// This is necessary when resolveReference flag is specified
|
||||
private addMatchedInputFile(referenceFilePath: string, extensions: string[]) {
|
||||
private addMatchedInputFile(referenceFilePath: string, extensions: ReadonlyArray<string>) {
|
||||
const inputFiles = this.inputFiles;
|
||||
const languageServiceAdapterHost = this.languageServiceAdapterHost;
|
||||
if (!extensions) {
|
||||
@@ -433,11 +436,19 @@ namespace FourSlash {
|
||||
|
||||
public goToPosition(pos: number) {
|
||||
this.currentCaretPosition = pos;
|
||||
this.selectionEnd = -1;
|
||||
}
|
||||
|
||||
public select(startMarker: string, endMarker: string) {
|
||||
const start = this.getMarkerByName(startMarker), end = this.getMarkerByName(endMarker);
|
||||
this.goToPosition(start.position);
|
||||
this.selectionEnd = end.position;
|
||||
}
|
||||
|
||||
public moveCaretRight(count = 1) {
|
||||
this.currentCaretPosition += count;
|
||||
this.currentCaretPosition = Math.min(this.currentCaretPosition, this.getFileContent(this.activeFile.fileName).length);
|
||||
this.selectionEnd = -1;
|
||||
}
|
||||
|
||||
// Opens a file given its 0-based index or fileName
|
||||
@@ -451,7 +462,7 @@ namespace FourSlash {
|
||||
this.languageServiceAdapterHost.openFile(fileToOpen.fileName, content, scriptKindName);
|
||||
}
|
||||
|
||||
public verifyErrorExistsBetweenMarkers(startMarkerName: string, endMarkerName: string, negative: boolean) {
|
||||
public verifyErrorExistsBetweenMarkers(startMarkerName: string, endMarkerName: string, shouldExist: boolean) {
|
||||
const startMarker = this.getMarkerByName(startMarkerName);
|
||||
const endMarker = this.getMarkerByName(endMarkerName);
|
||||
const predicate = (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) =>
|
||||
@@ -459,9 +470,9 @@ namespace FourSlash {
|
||||
|
||||
const exists = this.anyErrorInRange(predicate, startMarker, endMarker);
|
||||
|
||||
if (exists !== negative) {
|
||||
this.printErrorLog(negative, this.getAllDiagnostics());
|
||||
throw new Error(`Failure between markers: '${startMarkerName}', '${endMarkerName}'`);
|
||||
if (exists !== shouldExist) {
|
||||
this.printErrorLog(shouldExist, this.getAllDiagnostics());
|
||||
throw new Error(`${shouldExist ? "Expected" : "Did not expect"} failure between markers: '${startMarkerName}', '${endMarkerName}'`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,10 +494,11 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
private getAllDiagnostics(): ts.Diagnostic[] {
|
||||
return ts.flatMap(this.languageServiceAdapterHost.getFilenames(), fileName => this.getDiagnostics(fileName));
|
||||
return ts.flatMap(this.languageServiceAdapterHost.getFilenames(), fileName =>
|
||||
ts.isAnySupportedFileExtension(fileName) ? this.getDiagnostics(fileName) : []);
|
||||
}
|
||||
|
||||
public verifyErrorExistsAfterMarker(markerName: string, negative: boolean, after: boolean) {
|
||||
public verifyErrorExistsAfterMarker(markerName: string, shouldExist: boolean, after: boolean) {
|
||||
const marker: Marker = this.getMarkerByName(markerName);
|
||||
let predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean;
|
||||
|
||||
@@ -502,30 +514,15 @@ namespace FourSlash {
|
||||
const exists = this.anyErrorInRange(predicate, marker);
|
||||
const diagnostics = this.getAllDiagnostics();
|
||||
|
||||
if (exists !== negative) {
|
||||
this.printErrorLog(negative, diagnostics);
|
||||
throw new Error("Failure at marker: " + markerName);
|
||||
if (exists !== shouldExist) {
|
||||
this.printErrorLog(shouldExist, diagnostics);
|
||||
throw new Error(`${shouldExist ? "Expected" : "Did not expect"} failure at marker '${markerName}'`);
|
||||
}
|
||||
}
|
||||
|
||||
private anyErrorInRange(predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean, startMarker: Marker, endMarker?: Marker) {
|
||||
|
||||
const errors = this.getDiagnostics(startMarker.fileName);
|
||||
let exists = false;
|
||||
|
||||
const startPos = startMarker.position;
|
||||
let endPos: number = undefined;
|
||||
if (endMarker !== undefined) {
|
||||
endPos = endMarker.position;
|
||||
}
|
||||
|
||||
errors.forEach(function (error: ts.Diagnostic) {
|
||||
if (predicate(error.start, error.start + error.length, startPos, endPos)) {
|
||||
exists = true;
|
||||
}
|
||||
});
|
||||
|
||||
return exists;
|
||||
private anyErrorInRange(predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean, startMarker: Marker, endMarker?: Marker): boolean {
|
||||
return this.getDiagnostics(startMarker.fileName).some(({ start, length }) =>
|
||||
predicate(start, start + length, startMarker.position, endMarker === undefined ? undefined : endMarker.position));
|
||||
}
|
||||
|
||||
private printErrorLog(expectErrors: boolean, errors: ts.Diagnostic[]) {
|
||||
@@ -536,15 +533,21 @@ namespace FourSlash {
|
||||
Harness.IO.log("Unexpected error(s) found. Error list is:");
|
||||
}
|
||||
|
||||
for (const { start, length, messageText } of errors) {
|
||||
Harness.IO.log(" minChar: " + start +
|
||||
", limChar: " + (start + length) +
|
||||
for (const { start, length, messageText, file } of errors) {
|
||||
Harness.IO.log(" from: " + showPosition(file, start) +
|
||||
", to: " + showPosition(file, start + length) +
|
||||
", message: " + ts.flattenDiagnosticMessageText(messageText, Harness.IO.newLine()) + "\n");
|
||||
}
|
||||
|
||||
function showPosition(file: ts.SourceFile, pos: number) {
|
||||
const { line, character } = ts.getLineAndCharacterOfPosition(file, pos);
|
||||
return `${line}:${character}`;
|
||||
}
|
||||
}
|
||||
|
||||
public verifyNoErrors() {
|
||||
ts.forEachKey(this.inputFiles, fileName => {
|
||||
if (!ts.isAnySupportedFileExtension(fileName)) return;
|
||||
const errors = this.getDiagnostics(fileName);
|
||||
if (errors.length) {
|
||||
this.printErrorLog(/*expectErrors*/ false, errors);
|
||||
@@ -600,7 +603,7 @@ namespace FourSlash {
|
||||
this.verifyGoToXPlain(arg0, endMarkerNames, getDefs);
|
||||
}
|
||||
else if (ts.isArray(arg0)) {
|
||||
const pairs: [string | string[], string | string[]][] = arg0;
|
||||
const pairs: ReadonlyArray<[string | string[], string | string[]]> = arg0;
|
||||
for (const [start, end] of pairs) {
|
||||
this.verifyGoToXPlain(start, end, getDefs);
|
||||
}
|
||||
@@ -689,7 +692,7 @@ namespace FourSlash {
|
||||
|
||||
public verifyCompletionListItemsCountIsGreaterThan(count: number, negative: boolean) {
|
||||
const completions = this.getCompletionListAtCaret();
|
||||
const itemsCount = completions.entries.length;
|
||||
const itemsCount = completions ? completions.entries.length : 0;
|
||||
|
||||
if (negative) {
|
||||
if (itemsCount > count) {
|
||||
@@ -809,8 +812,8 @@ namespace FourSlash {
|
||||
|
||||
function filterByTextOrDocumentation(entry: ts.CompletionEntry) {
|
||||
const details = that.getCompletionEntryDetails(entry.name);
|
||||
const documentation = ts.displayPartsToString(details.documentation);
|
||||
const text = ts.displayPartsToString(details.displayParts);
|
||||
const documentation = details && ts.displayPartsToString(details.documentation);
|
||||
const text = details && ts.displayPartsToString(details.displayParts);
|
||||
|
||||
// If any of the expected values are undefined, assume that users don't
|
||||
// care about them.
|
||||
@@ -847,6 +850,9 @@ namespace FourSlash {
|
||||
if (expectedKind) {
|
||||
error += "Expected kind: " + expectedKind + " to equal: " + filterCompletions[0].kind + ".";
|
||||
}
|
||||
else {
|
||||
error += "kind: " + filterCompletions[0].kind + ".";
|
||||
}
|
||||
if (replacementSpan) {
|
||||
const spanText = filterCompletions[0].replacementSpan ? stringify(filterCompletions[0].replacementSpan) : undefined;
|
||||
error += "Expected replacement span: " + stringify(replacementSpan) + " to equal: " + spanText + ".";
|
||||
@@ -941,6 +947,22 @@ namespace FourSlash {
|
||||
this.verifySymbol(symbol, declarationRanges);
|
||||
}
|
||||
|
||||
public symbolsInScope(range: Range): ts.Symbol[] {
|
||||
const node = this.goToAndGetNode(range);
|
||||
return this.getChecker().getSymbolsInScope(node, ts.SymbolFlags.Value | ts.SymbolFlags.Type | ts.SymbolFlags.Namespace);
|
||||
}
|
||||
|
||||
public verifyTypeOfSymbolAtLocation(range: Range, symbol: ts.Symbol, expected: string): void {
|
||||
const node = this.goToAndGetNode(range);
|
||||
const checker = this.getChecker();
|
||||
const type = checker.getTypeOfSymbolAtLocation(symbol, node);
|
||||
|
||||
const actual = checker.typeToString(type);
|
||||
if (actual !== expected) {
|
||||
this.raiseError(`Expected: '${expected}', actual: '${actual}'`);
|
||||
}
|
||||
}
|
||||
|
||||
private verifyReferencesAre(expectedReferences: Range[]) {
|
||||
const actualReferences = this.getReferencesAtCaret() || [];
|
||||
|
||||
@@ -956,9 +978,9 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
for (const reference of expectedReferences) {
|
||||
const {fileName, start, end} = reference;
|
||||
const { fileName, start, end } = reference;
|
||||
if (reference.marker && reference.marker.data) {
|
||||
const {isWriteAccess, isDefinition} = reference.marker.data;
|
||||
const { isWriteAccess, isDefinition } = reference.marker.data;
|
||||
this.verifyReferencesWorker(actualReferences, fileName, start, end, isWriteAccess, isDefinition);
|
||||
}
|
||||
else {
|
||||
@@ -1169,7 +1191,7 @@ namespace FourSlash {
|
||||
displayParts: ts.SymbolDisplayPart[],
|
||||
documentation: ts.SymbolDisplayPart[],
|
||||
tags: ts.JSDocTagInfo[]
|
||||
) {
|
||||
) {
|
||||
|
||||
const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition);
|
||||
assert.equal(actualQuickInfo.kind, kind, this.messageAtLastKnownMarker("QuickInfo kind"));
|
||||
@@ -1459,7 +1481,7 @@ namespace FourSlash {
|
||||
let baselineFile = this.testData.globalOptions[metadataOptionNames.baselineFile];
|
||||
if (!baselineFile) {
|
||||
baselineFile = this.activeFile.fileName.replace(this.basePath + "/breakpointValidation", "bpSpan");
|
||||
baselineFile = baselineFile.replace(".ts", ".baseline");
|
||||
baselineFile = baselineFile.replace(ts.Extension.Ts, ".baseline");
|
||||
|
||||
}
|
||||
Harness.Baseline.runBaseline(
|
||||
@@ -1529,7 +1551,7 @@ namespace FourSlash {
|
||||
public baselineQuickInfo() {
|
||||
let baselineFile = this.testData.globalOptions[metadataOptionNames.baselineFile];
|
||||
if (!baselineFile) {
|
||||
baselineFile = ts.getBaseFileName(this.activeFile.fileName).replace(".ts", ".baseline");
|
||||
baselineFile = ts.getBaseFileName(this.activeFile.fileName).replace(ts.Extension.Ts, ".baseline");
|
||||
}
|
||||
|
||||
Harness.Baseline.runBaseline(
|
||||
@@ -1576,7 +1598,7 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public printCurrentFileState(makeWhitespaceVisible = false, makeCaretVisible = true) {
|
||||
public printCurrentFileState(makeWhitespaceVisible: boolean, makeCaretVisible: boolean) {
|
||||
for (const file of this.testData.files) {
|
||||
const active = (this.activeFile === file);
|
||||
Harness.IO.log(`=== Script (${file.fileName}) ${(active ? "(active, cursor at |)" : "")} ===`);
|
||||
@@ -1629,9 +1651,7 @@ namespace FourSlash {
|
||||
const checkCadence = (count >> 2) + 1;
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
// Make the edit
|
||||
this.languageServiceAdapterHost.editScript(this.activeFile.fileName, offset, offset + 1, ch);
|
||||
this.updateMarkersForEdit(this.activeFile.fileName, offset, offset + 1, ch);
|
||||
this.editScriptAndUpdateMarkers(this.activeFile.fileName, offset, offset + 1, ch);
|
||||
|
||||
if (i % checkCadence === 0) {
|
||||
this.checkPostEditInvariants();
|
||||
@@ -1642,21 +1662,15 @@ namespace FourSlash {
|
||||
const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, offset, ch, this.formatCodeSettings);
|
||||
if (edits.length) {
|
||||
offset += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true);
|
||||
// this.checkPostEditInvariants();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Move the caret to wherever we ended up
|
||||
this.currentCaretPosition = offset;
|
||||
|
||||
this.fixCaretPosition();
|
||||
this.checkPostEditInvariants();
|
||||
}
|
||||
|
||||
public replace(start: number, length: number, text: string) {
|
||||
this.languageServiceAdapterHost.editScript(this.activeFile.fileName, start, start + length, text);
|
||||
this.updateMarkersForEdit(this.activeFile.fileName, start, start + length, text);
|
||||
this.editScriptAndUpdateMarkers(this.activeFile.fileName, start, start + length, text);
|
||||
this.checkPostEditInvariants();
|
||||
}
|
||||
|
||||
@@ -1666,28 +1680,17 @@ namespace FourSlash {
|
||||
const checkCadence = (count >> 2) + 1;
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
this.currentCaretPosition--;
|
||||
offset--;
|
||||
// Make the edit
|
||||
this.languageServiceAdapterHost.editScript(this.activeFile.fileName, offset, offset + 1, ch);
|
||||
this.updateMarkersForEdit(this.activeFile.fileName, offset, offset + 1, ch);
|
||||
this.editScriptAndUpdateMarkers(this.activeFile.fileName, offset, offset + 1, ch);
|
||||
|
||||
if (i % checkCadence === 0) {
|
||||
this.checkPostEditInvariants();
|
||||
}
|
||||
|
||||
// Handle post-keystroke formatting
|
||||
if (this.enableFormatting) {
|
||||
const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, offset, ch, this.formatCodeSettings);
|
||||
if (edits.length) {
|
||||
offset += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true);
|
||||
}
|
||||
}
|
||||
// Don't need to examine formatting because there are no formatting changes on backspace.
|
||||
}
|
||||
|
||||
// Move the caret to wherever we ended up
|
||||
this.currentCaretPosition = offset;
|
||||
|
||||
this.fixCaretPosition();
|
||||
this.checkPostEditInvariants();
|
||||
}
|
||||
|
||||
@@ -1698,14 +1701,13 @@ namespace FourSlash {
|
||||
const checkCadence = (text.length >> 2) + 1;
|
||||
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
// Make the edit
|
||||
const ch = text.charAt(i);
|
||||
this.languageServiceAdapterHost.editScript(this.activeFile.fileName, offset, offset, ch);
|
||||
this.editScriptAndUpdateMarkers(this.activeFile.fileName, offset, offset, ch);
|
||||
if (highFidelity) {
|
||||
this.languageService.getBraceMatchingAtPosition(this.activeFile.fileName, offset);
|
||||
}
|
||||
|
||||
this.updateMarkersForEdit(this.activeFile.fileName, offset, offset, ch);
|
||||
this.currentCaretPosition++;
|
||||
offset++;
|
||||
|
||||
if (highFidelity) {
|
||||
@@ -1732,32 +1734,24 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
// Move the caret to wherever we ended up
|
||||
this.currentCaretPosition = offset;
|
||||
this.fixCaretPosition();
|
||||
this.checkPostEditInvariants();
|
||||
}
|
||||
|
||||
// Enters text as if the user had pasted it
|
||||
public paste(text: string) {
|
||||
const start = this.currentCaretPosition;
|
||||
let offset = this.currentCaretPosition;
|
||||
this.languageServiceAdapterHost.editScript(this.activeFile.fileName, offset, offset, text);
|
||||
this.updateMarkersForEdit(this.activeFile.fileName, offset, offset, text);
|
||||
this.editScriptAndUpdateMarkers(this.activeFile.fileName, this.currentCaretPosition, this.currentCaretPosition, text);
|
||||
this.checkPostEditInvariants();
|
||||
offset += text.length;
|
||||
const offset = this.currentCaretPosition += text.length;
|
||||
|
||||
// Handle formatting
|
||||
if (this.enableFormatting) {
|
||||
const edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, offset, this.formatCodeSettings);
|
||||
if (edits.length) {
|
||||
offset += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true);
|
||||
this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
// Move the caret to wherever we ended up
|
||||
this.currentCaretPosition = offset;
|
||||
this.fixCaretPosition();
|
||||
|
||||
this.checkPostEditInvariants();
|
||||
}
|
||||
@@ -1785,32 +1779,45 @@ namespace FourSlash {
|
||||
Utils.assertStructuralEquals(incrementalSourceFile, referenceSourceFile);
|
||||
}
|
||||
|
||||
private fixCaretPosition() {
|
||||
// The caret can potentially end up between the \r and \n, which is confusing. If
|
||||
// that happens, move it back one character
|
||||
if (this.currentCaretPosition > 0) {
|
||||
const ch = this.getFileContent(this.activeFile.fileName).substring(this.currentCaretPosition - 1, this.currentCaretPosition);
|
||||
if (ch === "\r") {
|
||||
this.currentCaretPosition--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private applyEdits(fileName: string, edits: ts.TextChange[], isFormattingEdit = false): number {
|
||||
/**
|
||||
* @returns The number of characters added to the file as a result of the edits.
|
||||
* May be negative.
|
||||
*/
|
||||
private applyEdits(fileName: string, edits: ts.TextChange[], isFormattingEdit: boolean): number {
|
||||
// We get back a set of edits, but langSvc.editScript only accepts one at a time. Use this to keep track
|
||||
// of the incremental offset from each edit to the next. Assumption is that these edit ranges don't overlap
|
||||
let runningOffset = 0;
|
||||
edits = edits.sort((a, b) => a.span.start - b.span.start);
|
||||
// of the incremental offset from each edit to the next. We assume these edit ranges don't overlap
|
||||
|
||||
// Copy this so we don't ruin someone else's copy
|
||||
edits = JSON.parse(JSON.stringify(edits));
|
||||
|
||||
// Get a snapshot of the content of the file so we can make sure any formatting edits didn't destroy non-whitespace characters
|
||||
const oldContent = this.getFileContent(fileName);
|
||||
let runningOffset = 0;
|
||||
|
||||
for (const edit of edits) {
|
||||
this.languageServiceAdapterHost.editScript(fileName, edit.span.start + runningOffset, ts.textSpanEnd(edit.span) + runningOffset, edit.newText);
|
||||
this.updateMarkersForEdit(fileName, edit.span.start + runningOffset, ts.textSpanEnd(edit.span) + runningOffset, edit.newText);
|
||||
const change = (edit.span.start - ts.textSpanEnd(edit.span)) + edit.newText.length;
|
||||
runningOffset += change;
|
||||
// TODO: Consider doing this at least some of the time for higher fidelity. Currently causes a failure (bug 707150)
|
||||
// this.languageService.getScriptLexicalStructure(fileName);
|
||||
for (let i = 0; i < edits.length; i++) {
|
||||
const edit = edits[i];
|
||||
const offsetStart = edit.span.start;
|
||||
const offsetEnd = offsetStart + edit.span.length;
|
||||
this.editScriptAndUpdateMarkers(fileName, offsetStart, offsetEnd, edit.newText);
|
||||
const editDelta = edit.newText.length - edit.span.length;
|
||||
if (offsetStart <= this.currentCaretPosition) {
|
||||
if (offsetEnd <= this.currentCaretPosition) {
|
||||
// The entirety of the edit span falls before the caret position, shift the caret accordingly
|
||||
this.currentCaretPosition += editDelta;
|
||||
}
|
||||
else {
|
||||
// The span being replaced includes the caret position, place the caret at the beginning of the span
|
||||
this.currentCaretPosition = offsetStart;
|
||||
}
|
||||
}
|
||||
runningOffset += editDelta;
|
||||
|
||||
// Update positions of any future edits affected by this change
|
||||
for (let j = i + 1; j < edits.length; j++) {
|
||||
if (edits[j].span.start >= edits[i].span.start) {
|
||||
edits[j].span.start += editDelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isFormattingEdit) {
|
||||
@@ -1820,6 +1827,7 @@ namespace FourSlash {
|
||||
this.raiseError("Formatting operation destroyed non-whitespace content");
|
||||
}
|
||||
}
|
||||
|
||||
return runningOffset;
|
||||
}
|
||||
|
||||
@@ -1835,23 +1843,21 @@ namespace FourSlash {
|
||||
|
||||
public formatDocument() {
|
||||
const edits = this.languageService.getFormattingEditsForDocument(this.activeFile.fileName, this.formatCodeSettings);
|
||||
this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true);
|
||||
this.fixCaretPosition();
|
||||
this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true);
|
||||
}
|
||||
|
||||
public formatSelection(start: number, end: number) {
|
||||
const edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, end, this.formatCodeSettings);
|
||||
this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true);
|
||||
this.fixCaretPosition();
|
||||
this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true);
|
||||
}
|
||||
|
||||
public formatOnType(pos: number, key: string) {
|
||||
const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, pos, key, this.formatCodeSettings);
|
||||
this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true);
|
||||
this.fixCaretPosition();
|
||||
this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true);
|
||||
}
|
||||
|
||||
private updateMarkersForEdit(fileName: string, minChar: number, limChar: number, text: string) {
|
||||
private editScriptAndUpdateMarkers(fileName: string, editStart: number, editEnd: number, newText: string) {
|
||||
this.languageServiceAdapterHost.editScript(fileName, editStart, editEnd, newText);
|
||||
for (const marker of this.testData.markers) {
|
||||
if (marker.fileName === fileName) {
|
||||
marker.position = updatePosition(marker.position);
|
||||
@@ -1866,14 +1872,14 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
function updatePosition(position: number) {
|
||||
if (position > minChar) {
|
||||
if (position < limChar) {
|
||||
if (position > editStart) {
|
||||
if (position < editEnd) {
|
||||
// Inside the edit - mark it as invalidated (?)
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
// Move marker back/forward by the appropriate amount
|
||||
return position + (minChar - limChar) + text.length;
|
||||
return position + (editStart - editEnd) + newText.length;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1895,7 +1901,7 @@ namespace FourSlash {
|
||||
this.goToPosition(len);
|
||||
}
|
||||
|
||||
public goToRangeStart({fileName, start}: Range) {
|
||||
public goToRangeStart({ fileName, start }: Range) {
|
||||
this.openFile(fileName);
|
||||
this.goToPosition(start);
|
||||
}
|
||||
@@ -2069,7 +2075,7 @@ namespace FourSlash {
|
||||
return result;
|
||||
}
|
||||
|
||||
private rangeText({fileName, start, end}: Range): string {
|
||||
private rangeText({ fileName, start, end }: Range): string {
|
||||
return this.getFileContent(fileName).slice(start, end);
|
||||
}
|
||||
|
||||
@@ -2119,8 +2125,8 @@ namespace FourSlash {
|
||||
const actual = this.getFileContent(this.activeFile.fileName);
|
||||
if (normalizeNewLines(actual) !== normalizeNewLines(text)) {
|
||||
throw new Error("verifyCurrentFileContent\n" +
|
||||
"\tExpected: \"" + text + "\"\n" +
|
||||
"\t Actual: \"" + actual + "\"");
|
||||
"\tExpected: \"" + TestState.makeWhitespaceVisible(text) + "\"\n" +
|
||||
"\t Actual: \"" + TestState.makeWhitespaceVisible(actual) + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2337,35 +2343,25 @@ namespace FourSlash {
|
||||
* @param fileName Path to file where error should be retrieved from.
|
||||
*/
|
||||
private getCodeFixActions(fileName: string, errorCode?: number): ts.CodeAction[] {
|
||||
const diagnosticsForCodeFix = this.getDiagnostics(fileName).map(diagnostic => {
|
||||
return {
|
||||
start: diagnostic.start,
|
||||
length: diagnostic.length,
|
||||
code: diagnostic.code
|
||||
};
|
||||
});
|
||||
const dedupedDiagnositcs = ts.deduplicate(diagnosticsForCodeFix, ts.equalOwnProperties);
|
||||
|
||||
let actions: ts.CodeAction[] = undefined;
|
||||
|
||||
for (const diagnostic of dedupedDiagnositcs) {
|
||||
const diagnosticsForCodeFix = this.getDiagnostics(fileName).map(diagnostic => ({
|
||||
start: diagnostic.start,
|
||||
length: diagnostic.length,
|
||||
code: diagnostic.code
|
||||
}));
|
||||
|
||||
return ts.flatMap(ts.deduplicate(diagnosticsForCodeFix, ts.equalOwnProperties), diagnostic => {
|
||||
if (errorCode && errorCode !== diagnostic.code) {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
const newActions = this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start, diagnostic.length, [diagnostic.code], this.formatCodeSettings);
|
||||
if (newActions && newActions.length) {
|
||||
actions = actions ? actions.concat(newActions) : newActions;
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
return this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start, diagnostic.start + diagnostic.length, [diagnostic.code], this.formatCodeSettings);
|
||||
});
|
||||
}
|
||||
|
||||
private applyCodeActions(actions: ts.CodeAction[], index?: number): void {
|
||||
if (index === undefined) {
|
||||
if (!(actions && actions.length === 1)) {
|
||||
this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found.`);
|
||||
this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found. ${actions ? actions.map(a => `${Harness.IO.newLine()} "${a.description}"`) : ""}`);
|
||||
}
|
||||
index = 0;
|
||||
}
|
||||
@@ -2390,7 +2386,7 @@ namespace FourSlash {
|
||||
|
||||
const codeFixes = this.getCodeFixActions(this.activeFile.fileName, errorCode);
|
||||
|
||||
if (!codeFixes || codeFixes.length === 0) {
|
||||
if (codeFixes.length === 0) {
|
||||
if (expectedTextArray.length !== 0) {
|
||||
this.raiseError("No codefixes returned.");
|
||||
}
|
||||
@@ -2409,7 +2405,7 @@ namespace FourSlash {
|
||||
const sortedActualArray = actualTextArray.sort();
|
||||
if (!ts.arrayIsEqualTo(sortedExpectedArray, sortedActualArray)) {
|
||||
this.raiseError(
|
||||
`Actual text array doesn't match expected text array. \nActual: \n"${sortedActualArray.join("\n\n")}"\n---\nExpected: \n'${sortedExpectedArray.join("\n\n")}'`);
|
||||
`Actual text array doesn't match expected text array. \nActual: \n'${sortedActualArray.join("\n\n")}'\n---\nExpected: \n'${sortedExpectedArray.join("\n\n")}'`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2512,6 +2508,23 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public verifySpanOfEnclosingComment(negative: boolean, onlyMultiLineDiverges?: boolean) {
|
||||
const expected = !negative;
|
||||
const position = this.currentCaretPosition;
|
||||
const fileName = this.activeFile.fileName;
|
||||
const actual = !!this.languageService.getSpanOfEnclosingComment(fileName, position, /*onlyMultiLine*/ false);
|
||||
const actualOnlyMultiLine = !!this.languageService.getSpanOfEnclosingComment(fileName, position, /*onlyMultiLine*/ true);
|
||||
if (expected !== actual || onlyMultiLineDiverges === (actual === actualOnlyMultiLine)) {
|
||||
this.raiseError(`verifySpanOfEnclosingComment failed:
|
||||
position: '${position}'
|
||||
fileName: '${fileName}'
|
||||
onlyMultiLineDiverges: '${onlyMultiLineDiverges}'
|
||||
actual: '${actual}'
|
||||
actualOnlyMultiLine: '${actualOnlyMultiLine}'
|
||||
expected: '${expected}'.`);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Check number of navigationItems which match both searchValue and matchKind,
|
||||
if a filename is passed in, limit the results to that file.
|
||||
@@ -2561,7 +2574,7 @@ namespace FourSlash {
|
||||
|
||||
// if there was an explicit match kind specified, then it should be validated.
|
||||
if (matchKind !== undefined) {
|
||||
const missingItem = { name: name, kind: kind, searchValue: searchValue, matchKind: matchKind, fileName: fileName, parentName: parentName };
|
||||
const missingItem = { name, kind, searchValue, matchKind, fileName, parentName };
|
||||
this.raiseError(`verifyNavigationItemsListContains failed - could not find the item: ${stringify(missingItem)} in the returned list: (${stringify(items)})`);
|
||||
}
|
||||
}
|
||||
@@ -2635,7 +2648,7 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
const missingItem = { fileName: fileName, start: start, end: end, isWriteAccess: isWriteAccess };
|
||||
const missingItem = { fileName, start, end, isWriteAccess };
|
||||
this.raiseError(`verifyOccurrencesAtPositionListContains failed - could not find the item: ${stringify(missingItem)} in the returned list: (${stringify(occurrences)})`);
|
||||
}
|
||||
|
||||
@@ -2671,6 +2684,13 @@ namespace FourSlash {
|
||||
this.rangesByText().forEach(ranges => this.verifyRangesAreDocumentHighlights(ranges));
|
||||
}
|
||||
|
||||
public verifyDocumentHighlightsOf(startRange: Range, ranges: Range[]) {
|
||||
ts.Debug.assert(ts.contains(ranges, startRange));
|
||||
const fileNames = unique(ranges, range => range.fileName);
|
||||
this.goToRangeStart(startRange);
|
||||
this.verifyDocumentHighlights(ranges, fileNames);
|
||||
}
|
||||
|
||||
public verifyRangesAreDocumentHighlights(ranges?: Range[]) {
|
||||
ranges = ranges || this.getRanges();
|
||||
const fileNames = unique(ranges, range => range.fileName);
|
||||
@@ -2712,11 +2732,11 @@ namespace FourSlash {
|
||||
public verifyCodeFixAvailable(negative: boolean) {
|
||||
const codeFix = this.getCodeFixActions(this.activeFile.fileName);
|
||||
|
||||
if (negative && codeFix) {
|
||||
if (negative && codeFix.length) {
|
||||
this.raiseError(`verifyCodeFixAvailable failed - expected no fixes but found one.`);
|
||||
}
|
||||
|
||||
if (!(negative || codeFix)) {
|
||||
if (!(negative || codeFix.length)) {
|
||||
this.raiseError(`verifyCodeFixAvailable failed - expected code fixes but none found.`);
|
||||
}
|
||||
}
|
||||
@@ -2733,6 +2753,30 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
private getSelection() {
|
||||
return ({
|
||||
pos: this.currentCaretPosition,
|
||||
end: this.selectionEnd === -1 ? this.currentCaretPosition : this.selectionEnd
|
||||
});
|
||||
}
|
||||
|
||||
public verifyRefactorAvailable(negative: boolean, name?: string, subName?: string) {
|
||||
const selection = this.getSelection();
|
||||
|
||||
let refactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, selection) || [];
|
||||
if (name) {
|
||||
refactors = refactors.filter(r => r.name === name && (subName === undefined || r.actions.some(a => a.name === subName)));
|
||||
}
|
||||
const isAvailable = refactors.length > 0;
|
||||
|
||||
if (negative && isAvailable) {
|
||||
this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected no refactor but found some: ${refactors.map(r => r.name).join(", ")}`);
|
||||
}
|
||||
else if (!negative && !isAvailable) {
|
||||
this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected a refactor but found none.`);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyApplicableRefactorAvailableForRange(negative: boolean) {
|
||||
const ranges = this.getRanges();
|
||||
if (!(ranges && ranges.length === 1)) {
|
||||
@@ -2749,6 +2793,20 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public applyRefactor(refactorName: string, actionName: string) {
|
||||
const range = this.getSelection();
|
||||
const refactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, range);
|
||||
const refactor = ts.find(refactors, r => r.name === refactorName);
|
||||
if (!refactor) {
|
||||
this.raiseError(`The expected refactor: ${refactorName} is not available at the marker location.`);
|
||||
}
|
||||
|
||||
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactorName, actionName);
|
||||
for (const edit of editInfo.edits) {
|
||||
this.applyEdits(edit.fileName, edit.textChanges, /*isFormattingEdit*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyFileAfterApplyingRefactorAtMarker(
|
||||
markerName: string,
|
||||
expectedContent: string,
|
||||
@@ -2769,7 +2827,7 @@ namespace FourSlash {
|
||||
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, formattingOptions, markerPos, refactorNameToApply, actionName);
|
||||
|
||||
for (const edit of editInfo.edits) {
|
||||
this.applyEdits(edit.fileName, edit.textChanges);
|
||||
this.applyEdits(edit.fileName, edit.textChanges, /*isFormattingEdit*/ false);
|
||||
}
|
||||
const actualContent = this.getFileContent(this.activeFile.fileName);
|
||||
|
||||
@@ -2964,7 +3022,6 @@ ${code}
|
||||
f(test, goTo, verify, edit, debug, format, cancellation, FourSlashInterface.Classification, FourSlash.verifyOperationIsCancelled);
|
||||
}
|
||||
catch (err) {
|
||||
// Debugging: FourSlash.currentTestState.printCurrentFileState();
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@@ -3250,7 +3307,7 @@ ${code}
|
||||
}
|
||||
|
||||
const range: Range = {
|
||||
fileName: fileName,
|
||||
fileName,
|
||||
start: rangeStart.position,
|
||||
end: (i - 1) - difference,
|
||||
marker: rangeStart.marker
|
||||
@@ -3378,7 +3435,7 @@ ${code}
|
||||
content: output,
|
||||
fileOptions: {},
|
||||
version: 0,
|
||||
fileName: fileName
|
||||
fileName,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3437,6 +3494,10 @@ namespace FourSlashInterface {
|
||||
public markerByName(s: string): FourSlash.Marker {
|
||||
return this.state.getMarkerByName(s);
|
||||
}
|
||||
|
||||
public symbolsInScope(range: FourSlash.Range): ts.Symbol[] {
|
||||
return this.state.symbolsInScope(range);
|
||||
}
|
||||
}
|
||||
|
||||
export class GoTo {
|
||||
@@ -3490,6 +3551,10 @@ namespace FourSlashInterface {
|
||||
public file(indexOrName: any, content?: string, scriptKindName?: string): void {
|
||||
this.state.openFile(indexOrName, content, scriptKindName);
|
||||
}
|
||||
|
||||
public select(startMarker: string, endMarker: string) {
|
||||
this.state.select(startMarker, endMarker);
|
||||
}
|
||||
}
|
||||
|
||||
export class VerifyNegatable {
|
||||
@@ -3506,6 +3571,12 @@ namespace FourSlashInterface {
|
||||
"constructor",
|
||||
"async"
|
||||
];
|
||||
public allowedConstructorParameterKeywords = [
|
||||
"public",
|
||||
"private",
|
||||
"protected",
|
||||
"readonly",
|
||||
];
|
||||
|
||||
constructor(protected state: FourSlash.TestState, private negative = false) {
|
||||
if (!negative) {
|
||||
@@ -3548,6 +3619,12 @@ namespace FourSlashInterface {
|
||||
}
|
||||
}
|
||||
|
||||
public completionListContainsConstructorParameterKeywords() {
|
||||
for (const keyword of this.allowedConstructorParameterKeywords) {
|
||||
this.completionListContains(keyword, keyword, /*documentation*/ undefined, "keyword");
|
||||
}
|
||||
}
|
||||
|
||||
public completionListIsGlobal(expected: boolean) {
|
||||
this.state.verifyCompletionListIsGlobal(expected);
|
||||
}
|
||||
@@ -3588,6 +3665,10 @@ namespace FourSlashInterface {
|
||||
this.state.verifyBraceCompletionAtPosition(this.negative, openingBrace);
|
||||
}
|
||||
|
||||
public isInCommentAtPosition(onlyMultiLineDiverges?: boolean) {
|
||||
this.state.verifySpanOfEnclosingComment(this.negative, onlyMultiLineDiverges);
|
||||
}
|
||||
|
||||
public codeFixAvailable() {
|
||||
this.state.verifyCodeFixAvailable(this.negative);
|
||||
}
|
||||
@@ -3599,6 +3680,10 @@ namespace FourSlashInterface {
|
||||
public applicableRefactorAvailableForRange() {
|
||||
this.state.verifyApplicableRefactorAvailableForRange(this.negative);
|
||||
}
|
||||
|
||||
public refactorAvailable(name?: string, subName?: string) {
|
||||
this.state.verifyRefactorAvailable(this.negative, name, subName);
|
||||
}
|
||||
}
|
||||
|
||||
export class Verify extends VerifyNegatable {
|
||||
@@ -3693,6 +3778,10 @@ namespace FourSlashInterface {
|
||||
this.state.verifySymbolAtLocation(startRange, declarationRanges);
|
||||
}
|
||||
|
||||
public typeOfSymbolAtLocation(range: FourSlash.Range, symbol: ts.Symbol, expected: string) {
|
||||
this.state.verifyTypeOfSymbolAtLocation(range, symbol, expected);
|
||||
}
|
||||
|
||||
public referencesOf(start: FourSlash.Range, references: FourSlash.Range[]) {
|
||||
this.state.verifyReferencesOf(start, references);
|
||||
}
|
||||
@@ -3885,6 +3974,10 @@ namespace FourSlashInterface {
|
||||
this.state.verifyRangesWithSameTextAreDocumentHighlights();
|
||||
}
|
||||
|
||||
public documentHighlightsOf(startRange: FourSlash.Range, ranges: FourSlash.Range[]) {
|
||||
this.state.verifyDocumentHighlightsOf(startRange, ranges);
|
||||
}
|
||||
|
||||
public completionEntryDetailIs(entryName: string, text: string, documentation?: string, kind?: string, tags?: ts.JSDocTagInfo[]) {
|
||||
this.state.verifyCompletionEntryDetails(entryName, text, documentation, kind, tags);
|
||||
}
|
||||
@@ -3986,6 +4079,10 @@ namespace FourSlashInterface {
|
||||
public disableFormatting() {
|
||||
this.state.enableFormatting = false;
|
||||
}
|
||||
|
||||
public applyRefactor(refactorName: string, actionName: string) {
|
||||
this.state.applyRefactor(refactorName, actionName);
|
||||
}
|
||||
}
|
||||
|
||||
export class Debug {
|
||||
@@ -3997,11 +4094,11 @@ namespace FourSlashInterface {
|
||||
}
|
||||
|
||||
public printCurrentFileState() {
|
||||
this.state.printCurrentFileState();
|
||||
this.state.printCurrentFileState(/*makeWhitespaceVisible*/ false, /*makeCaretVisible*/ true);
|
||||
}
|
||||
|
||||
public printCurrentFileStateWithWhitespace() {
|
||||
this.state.printCurrentFileState(/*makeWhitespaceVisible*/ true);
|
||||
this.state.printCurrentFileState(/*makeWhitespaceVisible*/ true, /*makeCaretVisible*/ true);
|
||||
}
|
||||
|
||||
public printCurrentFileStateWithoutCaret() {
|
||||
@@ -4193,11 +4290,8 @@ namespace FourSlashInterface {
|
||||
}
|
||||
|
||||
function getClassification(classificationType: ts.ClassificationTypeNames, text: string, position?: number): Classification {
|
||||
return {
|
||||
classificationType,
|
||||
text: text,
|
||||
textSpan: position === undefined ? undefined : { start: position, end: position + text.length }
|
||||
};
|
||||
const textSpan = position === undefined ? undefined : { start: position, end: position + text.length };
|
||||
return { classificationType, text, textSpan };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+101
-67
@@ -67,17 +67,16 @@ namespace Utils {
|
||||
|
||||
export let currentExecutionEnvironment = getExecutionEnvironment();
|
||||
|
||||
const Buffer: typeof global.Buffer = currentExecutionEnvironment !== ExecutionEnvironment.Browser
|
||||
? require("buffer").Buffer
|
||||
: undefined;
|
||||
// Thanks to browserify, Buffer is always available nowadays
|
||||
const Buffer: typeof global.Buffer = require("buffer").Buffer;
|
||||
|
||||
export function encodeString(s: string): string {
|
||||
return Buffer ? (new Buffer(s)).toString("utf8") : s;
|
||||
return Buffer.from(s).toString("utf8");
|
||||
}
|
||||
|
||||
export function byteLength(s: string, encoding?: string): number {
|
||||
// stub implementation if Buffer is not available (in-browser case)
|
||||
return Buffer ? Buffer.byteLength(s, encoding) : s.length;
|
||||
return Buffer.byteLength(s, encoding);
|
||||
}
|
||||
|
||||
export function evalFile(fileContents: string, fileName: string, nodeContext?: any) {
|
||||
@@ -133,17 +132,18 @@ namespace Utils {
|
||||
return content;
|
||||
}
|
||||
|
||||
export function memoize<T extends Function>(f: T): T {
|
||||
const cache: { [idx: string]: any } = {};
|
||||
export function memoize<T extends Function>(f: T, memoKey: (...anything: any[]) => string): T {
|
||||
const cache = ts.createMap<any>();
|
||||
|
||||
return <any>(function(this: any) {
|
||||
const key = Array.prototype.join.call(arguments);
|
||||
const cachedResult = cache[key];
|
||||
if (cachedResult) {
|
||||
return cachedResult;
|
||||
return <any>(function(this: any, ...args: any[]) {
|
||||
const key = memoKey(...args);
|
||||
if (cache.has(key)) {
|
||||
return cache.get(key);
|
||||
}
|
||||
else {
|
||||
return cache[key] = f.apply(this, arguments);
|
||||
const value = f.apply(this, args);
|
||||
cache.set(key, value);
|
||||
return value;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -420,7 +420,7 @@ namespace Utils {
|
||||
|
||||
const maxHarnessFrames = 1;
|
||||
|
||||
export function filterStack(error: Error, stackTraceLimit: number = Infinity) {
|
||||
export function filterStack(error: Error, stackTraceLimit = Infinity) {
|
||||
const stack = <string>(<any>error).stack;
|
||||
if (stack) {
|
||||
const lines = stack.split(/\r\n?|\n/g);
|
||||
@@ -479,7 +479,7 @@ namespace Harness {
|
||||
getCurrentDirectory(): string;
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
resolvePath(path: string): string;
|
||||
readFile(path: string): string;
|
||||
readFile(path: string): string | undefined;
|
||||
writeFile(path: string, contents: string): void;
|
||||
directoryName(path: string): string;
|
||||
getDirectories(path: string): string[];
|
||||
@@ -493,7 +493,7 @@ namespace Harness {
|
||||
args(): string[];
|
||||
getExecutingFilePath(): string;
|
||||
exit(exitCode?: number): void;
|
||||
readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[]): string[];
|
||||
readDirectory(path: string, extension?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
|
||||
tryEnableSourceMapsForHost?(): void;
|
||||
getEnvironmentVariable?(name: string): string;
|
||||
}
|
||||
@@ -537,7 +537,7 @@ namespace Harness {
|
||||
ts.sys.tryEnableSourceMapsForHost();
|
||||
}
|
||||
}
|
||||
export const readDirectory: typeof IO.readDirectory = (path, extension, exclude, include) => ts.sys.readDirectory(path, extension, exclude, include);
|
||||
export const readDirectory: typeof IO.readDirectory = (path, extension, exclude, include, depth) => ts.sys.readDirectory(path, extension, exclude, include, depth);
|
||||
|
||||
export function createDirectory(path: string) {
|
||||
if (!directoryExists(path)) {
|
||||
@@ -564,7 +564,7 @@ namespace Harness {
|
||||
}
|
||||
|
||||
export let listFiles: typeof IO.listFiles = (path, spec?, options?) => {
|
||||
options = options || <{ recursive?: boolean; }>{};
|
||||
options = options || {};
|
||||
|
||||
function filesInFolder(folder: string): string[] {
|
||||
let paths: string[] = [];
|
||||
@@ -686,7 +686,7 @@ namespace Harness {
|
||||
|
||||
return dirPath;
|
||||
}
|
||||
export let directoryName: typeof IO.directoryName = Utils.memoize(directoryNameImpl);
|
||||
export let directoryName: typeof IO.directoryName = Utils.memoize(directoryNameImpl, path => path);
|
||||
|
||||
export function resolvePath(path: string) {
|
||||
const response = Http.getFileFromServerSync(serverRoot + path + "?resolve=true");
|
||||
@@ -703,23 +703,24 @@ namespace Harness {
|
||||
return response.status === 200;
|
||||
}
|
||||
|
||||
export let listFiles = Utils.memoize((path: string, spec?: RegExp): string[] => {
|
||||
export const listFiles = Utils.memoize((path: string, spec?: RegExp, options?: { recursive?: boolean }): string[] => {
|
||||
const response = Http.getFileFromServerSync(serverRoot + path);
|
||||
if (response.status === 200) {
|
||||
const results = response.responseText.split(",");
|
||||
let results = response.responseText.split(",");
|
||||
if (spec) {
|
||||
return results.filter(file => spec.test(file));
|
||||
results = results.filter(file => spec.test(file));
|
||||
}
|
||||
else {
|
||||
return results;
|
||||
if (options && !options.recursive) {
|
||||
results = results.filter(file => (ts.getDirectoryPath(ts.normalizeSlashes(file)) === path));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
else {
|
||||
return [""];
|
||||
}
|
||||
});
|
||||
}, (path: string, spec?: RegExp, options?: { recursive?: boolean }) => `${path}|${spec}|${options ? options.recursive : undefined}`);
|
||||
|
||||
export function readFile(file: string) {
|
||||
export function readFile(file: string): string | undefined {
|
||||
const response = Http.getFileFromServerSync(serverRoot + file);
|
||||
if (response.status === 200) {
|
||||
return response.responseText;
|
||||
@@ -733,12 +734,12 @@ namespace Harness {
|
||||
Http.writeToServerSync(serverRoot + path, "WRITE", contents);
|
||||
}
|
||||
|
||||
export function readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[]) {
|
||||
export function readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[], depth?: number) {
|
||||
const fs = new Utils.VirtualFileSystem(path, useCaseSensitiveFileNames());
|
||||
for (const file of listFiles(path)) {
|
||||
fs.addFile(file);
|
||||
}
|
||||
return ts.matchFiles(path, extension, exclude, include, useCaseSensitiveFileNames(), getCurrentDirectory(), path => {
|
||||
return ts.matchFiles(path, extension, exclude, include, useCaseSensitiveFileNames(), getCurrentDirectory(), depth, path => {
|
||||
const entry = fs.traversePath(path);
|
||||
if (entry && entry.isDirectory()) {
|
||||
const directory = <Utils.VirtualDirectory>entry;
|
||||
@@ -893,13 +894,13 @@ namespace Harness {
|
||||
const getCanonicalFileName = ts.createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
|
||||
/** Maps a symlink name to a realpath. Used only for exposing `realpath`. */
|
||||
const realPathMap = ts.createFileMap<string>();
|
||||
const realPathMap = ts.createMap<string>();
|
||||
/**
|
||||
* Maps a file name to a source file.
|
||||
* This will have a different SourceFile for every symlink pointing to that file;
|
||||
* if the program resolves realpaths then symlink entries will be ignored.
|
||||
*/
|
||||
const fileMap = ts.createFileMap<ts.SourceFile>();
|
||||
const fileMap = ts.createMap<ts.SourceFile>();
|
||||
for (const file of inputFiles) {
|
||||
if (file.content !== undefined) {
|
||||
const fileName = ts.normalizePath(file.unitName);
|
||||
@@ -975,8 +976,8 @@ namespace Harness {
|
||||
getCanonicalFileName,
|
||||
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
|
||||
getNewLine: () => newLine,
|
||||
fileExists: fileName => fileMap.contains(toPath(fileName)),
|
||||
readFile: (fileName: string): string => {
|
||||
fileExists: fileName => fileMap.has(toPath(fileName)),
|
||||
readFile(fileName: string): string | undefined {
|
||||
const file = fileMap.get(toPath(fileName));
|
||||
if (ts.endsWith(fileName, "json")) {
|
||||
// strip comments
|
||||
@@ -999,7 +1000,7 @@ namespace Harness {
|
||||
getDirectories: d => {
|
||||
const path = ts.toPath(d, currentDirectory, getCanonicalFileName);
|
||||
const result: string[] = [];
|
||||
fileMap.forEachValue(key => {
|
||||
ts.forEachKey(fileMap, key => {
|
||||
if (key.indexOf(path) === 0 && key.lastIndexOf("/") > path.length) {
|
||||
let dirName = key.substr(path.length, key.indexOf("/", path.length + 1) - path.length);
|
||||
if (dirName[0] === "/") {
|
||||
@@ -1015,12 +1016,12 @@ namespace Harness {
|
||||
};
|
||||
}
|
||||
|
||||
function mapHasFileInDirectory(directoryPath: ts.Path, map: ts.FileMap<any>): boolean {
|
||||
function mapHasFileInDirectory(directoryPath: ts.Path, map: ts.Map<{}>): boolean {
|
||||
if (!map) {
|
||||
return false;
|
||||
}
|
||||
let exists = false;
|
||||
map.forEachValue(fileName => {
|
||||
ts.forEachKey(map, fileName => {
|
||||
if (!exists && ts.startsWith(fileName, directoryPath) && fileName[directoryPath.length] === "/") {
|
||||
exists = true;
|
||||
}
|
||||
@@ -1053,7 +1054,7 @@ namespace Harness {
|
||||
];
|
||||
|
||||
let optionsIndex: ts.Map<ts.CommandLineOption>;
|
||||
function getCommandLineOption(name: string): ts.CommandLineOption {
|
||||
function getCommandLineOption(name: string): ts.CommandLineOption | undefined {
|
||||
if (!optionsIndex) {
|
||||
optionsIndex = ts.createMap<ts.CommandLineOption>();
|
||||
const optionDeclarations = harnessOptionDeclarations.concat(ts.optionDeclarations);
|
||||
@@ -1125,7 +1126,7 @@ namespace Harness {
|
||||
compilerOptions: ts.CompilerOptions,
|
||||
// Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file
|
||||
currentDirectory: string): CompilationOutput {
|
||||
const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.clone(compilerOptions) : { noResolve: false };
|
||||
const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.cloneCompilerOptions(compilerOptions) : { noResolve: false };
|
||||
options.target = options.target || ts.ScriptTarget.ES3;
|
||||
options.newLine = options.newLine || ts.NewLineKind.CarriageReturnLineFeed;
|
||||
options.noErrorTruncation = true;
|
||||
@@ -1194,13 +1195,21 @@ namespace Harness {
|
||||
return { result, options };
|
||||
}
|
||||
|
||||
export function compileDeclarationFiles(inputFiles: TestFile[],
|
||||
export interface DeclarationCompilationContext {
|
||||
declInputFiles: TestFile[];
|
||||
declOtherFiles: TestFile[];
|
||||
harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions;
|
||||
options: ts.CompilerOptions;
|
||||
currentDirectory: string;
|
||||
}
|
||||
|
||||
export function prepareDeclarationCompilationContext(inputFiles: TestFile[],
|
||||
otherFiles: TestFile[],
|
||||
result: CompilerResult,
|
||||
harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions,
|
||||
options: ts.CompilerOptions,
|
||||
// Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file
|
||||
currentDirectory: string) {
|
||||
currentDirectory: string): DeclarationCompilationContext | undefined {
|
||||
if (options.declaration && result.errors.length === 0 && result.declFilesCode.length !== result.files.length) {
|
||||
throw new Error("There were no errors and declFiles generated did not match number of js files generated");
|
||||
}
|
||||
@@ -1212,8 +1221,7 @@ namespace Harness {
|
||||
if (options.declaration && result.errors.length === 0 && result.declFilesCode.length > 0) {
|
||||
ts.forEach(inputFiles, file => addDtsFile(file, declInputFiles));
|
||||
ts.forEach(otherFiles, file => addDtsFile(file, declOtherFiles));
|
||||
const output = compileFiles(declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory || harnessSettings["currentDirectory"]);
|
||||
return { declInputFiles, declOtherFiles, declResult: output.result };
|
||||
return { declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory: currentDirectory || harnessSettings["currentDirectory"] };
|
||||
}
|
||||
|
||||
function addDtsFile(file: TestFile, dtsFiles: TestFile[]) {
|
||||
@@ -1249,7 +1257,7 @@ namespace Harness {
|
||||
sourceFileName = outFile;
|
||||
}
|
||||
|
||||
const dTsFileName = ts.removeFileExtension(sourceFileName) + ".d.ts";
|
||||
const dTsFileName = ts.removeFileExtension(sourceFileName) + ts.Extension.Dts;
|
||||
|
||||
return ts.forEach(result.declFilesCode, declFile => declFile.fileName === dTsFileName ? declFile : undefined);
|
||||
}
|
||||
@@ -1259,6 +1267,15 @@ namespace Harness {
|
||||
}
|
||||
}
|
||||
|
||||
export function compileDeclarationFiles(context: DeclarationCompilationContext | undefined) {
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
const { declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory } = context;
|
||||
const output = compileFiles(declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory);
|
||||
return { declInputFiles, declOtherFiles, declResult: output.result };
|
||||
}
|
||||
|
||||
function normalizeLineEndings(text: string, lineEnding: string): string {
|
||||
let normalized = text.replace(/\r\n?/g, "\n");
|
||||
if (lineEnding !== "\n") {
|
||||
@@ -1273,10 +1290,19 @@ namespace Harness {
|
||||
|
||||
export function getErrorBaseline(inputFiles: TestFile[], diagnostics: ts.Diagnostic[]) {
|
||||
diagnostics.sort(ts.compareDiagnostics);
|
||||
const outputLines: string[] = [];
|
||||
let outputLines = "";
|
||||
// Count up all errors that were found in files other than lib.d.ts so we don't miss any
|
||||
let totalErrorsReportedInNonLibraryFiles = 0;
|
||||
|
||||
let firstLine = true;
|
||||
function newLine() {
|
||||
if (firstLine) {
|
||||
firstLine = false;
|
||||
return "";
|
||||
}
|
||||
return "\r\n";
|
||||
}
|
||||
|
||||
function outputErrorText(error: ts.Diagnostic) {
|
||||
const message = ts.flattenDiagnosticMessageText(error.messageText, Harness.IO.newLine());
|
||||
|
||||
@@ -1285,7 +1311,7 @@ namespace Harness {
|
||||
.map(s => s.length > 0 && s.charAt(s.length - 1) === "\r" ? s.substr(0, s.length - 1) : s)
|
||||
.filter(s => s.length > 0)
|
||||
.map(s => "!!! " + ts.DiagnosticCategory[error.category].toLowerCase() + " TS" + error.code + ": " + s);
|
||||
errLines.forEach(e => outputLines.push(e));
|
||||
errLines.forEach(e => outputLines += (newLine() + e));
|
||||
|
||||
// do not count errors from lib.d.ts here, they are computed separately as numLibraryDiagnostics
|
||||
// if lib.d.ts is explicitly included in input files and there are some errors in it (i.e. because of duplicate identifiers)
|
||||
@@ -1311,7 +1337,7 @@ namespace Harness {
|
||||
|
||||
|
||||
// Header
|
||||
outputLines.push("==== " + inputFile.unitName + " (" + fileErrors.length + " errors) ====");
|
||||
outputLines += (newLine() + "==== " + inputFile.unitName + " (" + fileErrors.length + " errors) ====");
|
||||
|
||||
// Make sure we emit something for every error
|
||||
let markedErrorCount = 0;
|
||||
@@ -1340,7 +1366,7 @@ namespace Harness {
|
||||
nextLineStart = lineStarts[lineIndex + 1];
|
||||
}
|
||||
// Emit this line from the original file
|
||||
outputLines.push(" " + line);
|
||||
outputLines += (newLine() + " " + line);
|
||||
fileErrors.forEach(err => {
|
||||
// Does any error start or continue on to this line? Emit squiggles
|
||||
const end = ts.textSpanEnd(err);
|
||||
@@ -1352,7 +1378,7 @@ namespace Harness {
|
||||
// Calculate the start of the squiggle
|
||||
const squiggleStart = Math.max(0, relativeOffset);
|
||||
// TODO/REVIEW: this doesn't work quite right in the browser if a multi file test has files whose names are just the right length relative to one another
|
||||
outputLines.push(" " + line.substr(0, squiggleStart).replace(/[^\s]/g, " ") + new Array(Math.min(length, line.length - squiggleStart) + 1).join("~"));
|
||||
outputLines += (newLine() + " " + line.substr(0, squiggleStart).replace(/[^\s]/g, " ") + new Array(Math.min(length, line.length - squiggleStart) + 1).join("~"));
|
||||
|
||||
// If the error ended here, or we're at the end of the file, emit its message
|
||||
if ((lineIndex === lines.length - 1) || nextLineStart > end) {
|
||||
@@ -1383,7 +1409,7 @@ namespace Harness {
|
||||
assert.equal(totalErrorsReportedInNonLibraryFiles + numLibraryDiagnostics + numTest262HarnessDiagnostics, diagnostics.length, "total number of errors");
|
||||
|
||||
return minimalDiagnosticsToString(diagnostics) +
|
||||
Harness.IO.newLine() + Harness.IO.newLine() + outputLines.join("\r\n");
|
||||
Harness.IO.newLine() + Harness.IO.newLine() + outputLines;
|
||||
}
|
||||
|
||||
export function doErrorBaseline(baselinePath: string, inputFiles: TestFile[], errors: ts.Diagnostic[]) {
|
||||
@@ -1465,7 +1491,7 @@ namespace Harness {
|
||||
// When calling this function from rwc-runner, the baselinePath will have no extension.
|
||||
// As rwc test- file is stored in json which ".json" will get stripped off.
|
||||
// When calling this function from compiler-runner, the baselinePath will then has either ".ts" or ".tsx" extension
|
||||
const outputFileName = ts.endsWith(baselinePath, ".ts") || ts.endsWith(baselinePath, ".tsx") ?
|
||||
const outputFileName = ts.endsWith(baselinePath, ts.Extension.Ts) || ts.endsWith(baselinePath, ts.Extension.Tsx) ?
|
||||
baselinePath.replace(/\.tsx?/, fullExtension) : baselinePath.concat(fullExtension);
|
||||
Harness.Baseline.runBaseline(outputFileName, () => fullBaseLine, opts);
|
||||
}
|
||||
@@ -1557,13 +1583,13 @@ namespace Harness {
|
||||
}
|
||||
}
|
||||
|
||||
export function doJsEmitBaseline(baselinePath: string, header: string, options: ts.CompilerOptions, result: CompilerResult, toBeCompiled: Harness.Compiler.TestFile[], otherFiles: Harness.Compiler.TestFile[], harnessSettings: Harness.TestCaseParser.CompilerSettings) {
|
||||
export function doJsEmitBaseline(baselinePath: string, header: string, options: ts.CompilerOptions, result: CompilerResult, tsConfigFiles: Harness.Compiler.TestFile[], toBeCompiled: Harness.Compiler.TestFile[], otherFiles: Harness.Compiler.TestFile[], harnessSettings: Harness.TestCaseParser.CompilerSettings) {
|
||||
if (!options.noEmit && result.files.length === 0 && result.errors.length === 0) {
|
||||
throw new Error("Expected at least one js file to be emitted or at least one error to be created.");
|
||||
}
|
||||
|
||||
// check js output
|
||||
Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ".js"), () => {
|
||||
Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ts.Extension.Js), () => {
|
||||
let tsCode = "";
|
||||
const tsSources = otherFiles.concat(toBeCompiled);
|
||||
if (tsSources.length > 1) {
|
||||
@@ -1586,14 +1612,15 @@ namespace Harness {
|
||||
}
|
||||
}
|
||||
|
||||
const declFileCompilationResult =
|
||||
Harness.Compiler.compileDeclarationFiles(
|
||||
toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined);
|
||||
const declFileContext = Harness.Compiler.prepareDeclarationCompilationContext(
|
||||
toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined
|
||||
);
|
||||
const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(declFileContext);
|
||||
|
||||
if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) {
|
||||
jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n";
|
||||
jsCode += "\r\n\r\n";
|
||||
jsCode += Harness.Compiler.getErrorBaseline(declFileCompilationResult.declInputFiles.concat(declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
|
||||
jsCode += Harness.Compiler.getErrorBaseline(tsConfigFiles.concat(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
|
||||
}
|
||||
|
||||
if (jsCode.length > 0) {
|
||||
@@ -1651,22 +1678,22 @@ namespace Harness {
|
||||
}
|
||||
|
||||
export function isTS(fileName: string) {
|
||||
return ts.endsWith(fileName, ".ts");
|
||||
return ts.endsWith(fileName, ts.Extension.Ts);
|
||||
}
|
||||
|
||||
export function isTSX(fileName: string) {
|
||||
return ts.endsWith(fileName, ".tsx");
|
||||
return ts.endsWith(fileName, ts.Extension.Tsx);
|
||||
}
|
||||
|
||||
export function isDTS(fileName: string) {
|
||||
return ts.endsWith(fileName, ".d.ts");
|
||||
return ts.endsWith(fileName, ts.Extension.Dts);
|
||||
}
|
||||
|
||||
export function isJS(fileName: string) {
|
||||
return ts.endsWith(fileName, ".js");
|
||||
return ts.endsWith(fileName, ts.Extension.Js);
|
||||
}
|
||||
export function isJSX(fileName: string) {
|
||||
return ts.endsWith(fileName, ".jsx");
|
||||
return ts.endsWith(fileName, ts.Extension.Jsx);
|
||||
}
|
||||
|
||||
export function isJSMap(fileName: string) {
|
||||
@@ -1744,7 +1771,12 @@ namespace Harness {
|
||||
}
|
||||
|
||||
/** Given a test file containing // @FileName directives, return an array of named units of code to be added to an existing compiler instance */
|
||||
export function makeUnitsFromTest(code: string, fileName: string, rootDir?: string): { settings: CompilerSettings; testUnitData: TestUnitData[]; tsConfig: ts.ParsedCommandLine } {
|
||||
export function makeUnitsFromTest(code: string, fileName: string, rootDir?: string): {
|
||||
settings: CompilerSettings;
|
||||
testUnitData: TestUnitData[];
|
||||
tsConfig: ts.ParsedCommandLine;
|
||||
tsConfigFileUnitData: TestUnitData;
|
||||
} {
|
||||
const settings = extractCompilerSettings(code);
|
||||
|
||||
// List of all the subfiles we've parsed out
|
||||
@@ -1830,17 +1862,19 @@ namespace Harness {
|
||||
|
||||
// check if project has tsconfig.json in the list of files
|
||||
let tsConfig: ts.ParsedCommandLine;
|
||||
let tsConfigFileUnitData: TestUnitData;
|
||||
for (let i = 0; i < testUnitData.length; i++) {
|
||||
const data = testUnitData[i];
|
||||
if (ts.getBaseFileName(data.name).toLowerCase() === "tsconfig.json") {
|
||||
const configJson = ts.parseConfigFileTextToJson(data.name, data.content);
|
||||
assert.isTrue(configJson.config !== undefined);
|
||||
const configJson = ts.parseJsonText(data.name, data.content);
|
||||
assert.isTrue(configJson.endOfFileToken !== undefined);
|
||||
let baseDir = ts.normalizePath(ts.getDirectoryPath(data.name));
|
||||
if (rootDir) {
|
||||
baseDir = ts.getNormalizedAbsolutePath(baseDir, rootDir);
|
||||
}
|
||||
tsConfig = ts.parseJsonConfigFileContent(configJson.config, parseConfigHost, baseDir);
|
||||
tsConfig = ts.parseJsonSourceFileConfigFileContent(configJson, parseConfigHost, baseDir);
|
||||
tsConfig.options.configFilePath = data.name;
|
||||
tsConfigFileUnitData = data;
|
||||
|
||||
// delete entry from the list
|
||||
ts.orderedRemoveItemAt(testUnitData, i);
|
||||
@@ -1848,7 +1882,7 @@ namespace Harness {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { settings, testUnitData, tsConfig };
|
||||
return { settings, testUnitData, tsConfig, tsConfigFileUnitData };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1956,7 +1990,7 @@ namespace Harness {
|
||||
IO.writeFile(actualFileName + ".delete", "");
|
||||
}
|
||||
else {
|
||||
IO.writeFile(actualFileName, actual);
|
||||
IO.writeFile(actualFileName, encoded_actual);
|
||||
}
|
||||
throw new Error(`The baseline file ${relativeFileName} has changed.`);
|
||||
}
|
||||
@@ -1973,7 +2007,7 @@ namespace Harness {
|
||||
export function isDefaultLibraryFile(filePath: string): boolean {
|
||||
// We need to make sure that the filePath is prefixed with "lib." not just containing "lib." and end with ".d.ts"
|
||||
const fileName = ts.getBaseFileName(ts.normalizeSlashes(filePath));
|
||||
return ts.startsWith(fileName, "lib.") && ts.endsWith(fileName, ".d.ts");
|
||||
return ts.startsWith(fileName, "lib.") && ts.endsWith(fileName, ts.Extension.Dts);
|
||||
}
|
||||
|
||||
export function isBuiltFile(filePath: string): boolean {
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace Harness.LanguageService {
|
||||
}
|
||||
|
||||
class DefaultHostCancellationToken implements ts.HostCancellationToken {
|
||||
public static Instance = new DefaultHostCancellationToken();
|
||||
public static readonly Instance = new DefaultHostCancellationToken();
|
||||
|
||||
public isCancellationRequested() {
|
||||
return false;
|
||||
@@ -193,7 +193,9 @@ namespace Harness.LanguageService {
|
||||
}
|
||||
getCurrentDirectory(): string { return virtualFileSystemRoot; }
|
||||
getDefaultLibFileName(): string { return Harness.Compiler.defaultLibFileName; }
|
||||
getScriptFileNames(): string[] { return this.getFilenames(); }
|
||||
getScriptFileNames(): string[] {
|
||||
return this.getFilenames().filter(ts.isAnySupportedFileExtension);
|
||||
}
|
||||
getScriptSnapshot(fileName: string): ts.IScriptSnapshot {
|
||||
const script = this.getScriptInfo(fileName);
|
||||
return script ? new ScriptSnapshot(script) : undefined;
|
||||
@@ -208,13 +210,14 @@ namespace Harness.LanguageService {
|
||||
const script = this.getScriptSnapshot(fileName);
|
||||
return script !== undefined;
|
||||
}
|
||||
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[] {
|
||||
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[] {
|
||||
return ts.matchFiles(path, extensions, exclude, include,
|
||||
/*useCaseSensitiveFileNames*/ false,
|
||||
this.getCurrentDirectory(),
|
||||
depth,
|
||||
(p) => this.virtualFileSystem.getAccessibleFileSystemEntries(p));
|
||||
}
|
||||
readFile(path: string): string {
|
||||
readFile(path: string): string | undefined {
|
||||
const snapshot = this.getScriptSnapshot(path);
|
||||
return snapshot.getText(0, snapshot.getLength());
|
||||
}
|
||||
@@ -312,9 +315,7 @@ namespace Harness.LanguageService {
|
||||
getScriptVersion(fileName: string): string { return this.nativeHost.getScriptVersion(fileName); }
|
||||
getLocalizedDiagnosticMessages(): string { return JSON.stringify({}); }
|
||||
|
||||
readDirectory(_rootDir: string, _extension: string): string {
|
||||
return ts.notImplemented();
|
||||
}
|
||||
readDirectory = ts.notImplemented;
|
||||
readDirectoryNames = ts.notImplemented;
|
||||
readFileNames = ts.notImplemented;
|
||||
fileExists(fileName: string) { return this.getScriptInfo(fileName) !== undefined; }
|
||||
@@ -486,6 +487,9 @@ namespace Harness.LanguageService {
|
||||
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean {
|
||||
return unwrapJSONCallResult(this.shim.isValidBraceCompletionAtPosition(fileName, position, openingBrace));
|
||||
}
|
||||
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): ts.TextSpan {
|
||||
return unwrapJSONCallResult(this.shim.getSpanOfEnclosingComment(fileName, position, onlyMultiLine));
|
||||
}
|
||||
getCodeFixesAtPosition(): ts.CodeAction[] {
|
||||
throw new Error("Not supported on the shim.");
|
||||
}
|
||||
@@ -620,7 +624,7 @@ namespace Harness.LanguageService {
|
||||
this.writeMessage(message);
|
||||
}
|
||||
|
||||
readFile(fileName: string): string {
|
||||
readFile(fileName: string): string | undefined {
|
||||
if (fileName.indexOf(Harness.Compiler.defaultLibFileName) >= 0) {
|
||||
fileName = Harness.Compiler.defaultLibFileName;
|
||||
}
|
||||
@@ -668,9 +672,7 @@ namespace Harness.LanguageService {
|
||||
return ts.sys.getEnvironmentVariable(name);
|
||||
}
|
||||
|
||||
readDirectory(_path: string, _extension?: string[], _exclude?: string[], _include?: string[]): string[] {
|
||||
return ts.notImplemented();
|
||||
}
|
||||
readDirectory() { return ts.notImplemented(); }
|
||||
|
||||
watchFile(): ts.FileWatcher {
|
||||
return { close: ts.noop };
|
||||
@@ -684,11 +686,11 @@ namespace Harness.LanguageService {
|
||||
}
|
||||
|
||||
info(message: string): void {
|
||||
return this.host.log(message);
|
||||
this.host.log(message);
|
||||
}
|
||||
|
||||
msg(message: string) {
|
||||
return this.host.log(message);
|
||||
msg(message: string): void {
|
||||
this.host.log(message);
|
||||
}
|
||||
|
||||
loggingEnabled() {
|
||||
@@ -703,17 +705,13 @@ namespace Harness.LanguageService {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
endGroup(): void {
|
||||
}
|
||||
startGroup() { throw ts.notImplemented(); }
|
||||
endGroup() { throw ts.notImplemented(); }
|
||||
|
||||
perftrc(message: string): void {
|
||||
return this.host.log(message);
|
||||
}
|
||||
|
||||
startGroup(): void {
|
||||
}
|
||||
|
||||
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any {
|
||||
return setTimeout(callback, ms, args);
|
||||
}
|
||||
@@ -731,7 +729,7 @@ namespace Harness.LanguageService {
|
||||
}
|
||||
|
||||
createHash(s: string) {
|
||||
return s;
|
||||
return mockHash(s);
|
||||
}
|
||||
|
||||
require(_initialDir: string, _moduleName: string): ts.server.RequireResult {
|
||||
@@ -798,7 +796,7 @@ namespace Harness.LanguageService {
|
||||
default:
|
||||
return {
|
||||
module: undefined,
|
||||
error: "Could not resolve module"
|
||||
error: new Error("Could not resolve module")
|
||||
};
|
||||
}
|
||||
|
||||
@@ -831,6 +829,7 @@ namespace Harness.LanguageService {
|
||||
host: serverHost,
|
||||
cancellationToken: ts.server.nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined,
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
@@ -856,4 +855,8 @@ namespace Harness.LanguageService {
|
||||
getClassifier(): ts.Classifier { throw new Error("getClassifier is not available using the server interface."); }
|
||||
getPreProcessedFileInfo(): ts.PreProcessedFileInfo { throw new Error("getPreProcessedFileInfo is not available using the server interface."); }
|
||||
}
|
||||
|
||||
export function mockHash(s: string): string {
|
||||
return `hash-${s}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const fs: any = require("fs");
|
||||
const path: any = require("path");
|
||||
import fs = require("fs");
|
||||
import path = require("path");
|
||||
|
||||
function instrumentForRecording(fn: string, tscPath: string) {
|
||||
instrument(tscPath, `
|
||||
@@ -38,7 +38,9 @@ function instrument(tscPath: string, prepareCode: string, cleanupCode = "") {
|
||||
|
||||
const index2 = index1 + invocationLine.length;
|
||||
const newContent = tscContent.substr(0, index1) + loggerContent + prepareCode + invocationLine + cleanupCode + tscContent.substr(index2) + "\r\n";
|
||||
fs.writeFile(tscPath, newContent);
|
||||
fs.writeFile(tscPath, newContent, err => {
|
||||
if (err) throw err;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -64,10 +64,11 @@ interface IOLog {
|
||||
}[];
|
||||
directoriesRead: {
|
||||
path: string,
|
||||
extensions: string[],
|
||||
exclude: string[],
|
||||
include: string[],
|
||||
result: string[]
|
||||
extensions: ReadonlyArray<string>,
|
||||
exclude: ReadonlyArray<string>,
|
||||
include: ReadonlyArray<string>,
|
||||
depth: number,
|
||||
result: ReadonlyArray<string>,
|
||||
}[];
|
||||
}
|
||||
|
||||
@@ -220,10 +221,9 @@ namespace Playback {
|
||||
memoize(path => findFileByPath(replayLog.filesRead, path, /*throwFileNotFoundError*/ true).contents));
|
||||
|
||||
wrapper.readDirectory = recordReplay(wrapper.readDirectory, underlying)(
|
||||
(path, extensions, exclude, include) => {
|
||||
const result = (<ts.System>underlying).readDirectory(path, extensions, exclude, include);
|
||||
const logEntry = { path, extensions, exclude, include, result };
|
||||
recordLog.directoriesRead.push(logEntry);
|
||||
(path, extensions, exclude, include, depth) => {
|
||||
const result = (<ts.System>underlying).readDirectory(path, extensions, exclude, include, depth);
|
||||
recordLog.directoriesRead.push({ path, extensions, exclude, include, depth, result });
|
||||
return result;
|
||||
},
|
||||
path => {
|
||||
|
||||
@@ -24,6 +24,7 @@ interface BatchCompileProjectTestCaseEmittedFile extends Harness.Compiler.Genera
|
||||
}
|
||||
|
||||
interface CompileProjectFilesResult {
|
||||
configFileSourceFiles: ts.SourceFile[];
|
||||
moduleKind: ts.ModuleKind;
|
||||
program?: ts.Program;
|
||||
compilerOptions?: ts.CompilerOptions;
|
||||
@@ -124,7 +125,8 @@ class ProjectRunner extends RunnerBase {
|
||||
return Harness.IO.resolvePath(testCase.projectRoot);
|
||||
}
|
||||
|
||||
function compileProjectFiles(moduleKind: ts.ModuleKind, getInputFiles: () => string[],
|
||||
function compileProjectFiles(moduleKind: ts.ModuleKind, configFileSourceFiles: ts.SourceFile[],
|
||||
getInputFiles: () => string[],
|
||||
getSourceFileTextImpl: (fileName: string) => string,
|
||||
writeFile: (fileName: string, data: string, writeByteOrderMark: boolean) => void,
|
||||
compilerOptions: ts.CompilerOptions): CompileProjectFilesResult {
|
||||
@@ -148,6 +150,7 @@ class ProjectRunner extends RunnerBase {
|
||||
}
|
||||
|
||||
return {
|
||||
configFileSourceFiles,
|
||||
moduleKind,
|
||||
program,
|
||||
errors,
|
||||
@@ -196,6 +199,7 @@ class ProjectRunner extends RunnerBase {
|
||||
const outputFiles: BatchCompileProjectTestCaseEmittedFile[] = [];
|
||||
let inputFiles = testCase.inputFiles;
|
||||
let compilerOptions = createCompilerOptions();
|
||||
const configFileSourceFiles: ts.SourceFile[] = [];
|
||||
|
||||
let configFileName: string;
|
||||
if (compilerOptions.project) {
|
||||
@@ -207,41 +211,31 @@ class ProjectRunner extends RunnerBase {
|
||||
configFileName = ts.findConfigFile("", fileExists);
|
||||
}
|
||||
|
||||
let errors: ts.Diagnostic[];
|
||||
if (configFileName) {
|
||||
const result = ts.readConfigFile(configFileName, getSourceFileText);
|
||||
if (result.error) {
|
||||
return {
|
||||
moduleKind,
|
||||
errors: [result.error]
|
||||
};
|
||||
}
|
||||
|
||||
const configObject = result.config;
|
||||
const result = ts.readJsonConfigFile(configFileName, getSourceFileText);
|
||||
configFileSourceFiles.push(result);
|
||||
const configParseHost: ts.ParseConfigHost = {
|
||||
useCaseSensitiveFileNames: Harness.IO.useCaseSensitiveFileNames(),
|
||||
fileExists,
|
||||
readDirectory,
|
||||
readFile
|
||||
};
|
||||
const configParseResult = ts.parseJsonConfigFileContent(configObject, configParseHost, ts.getDirectoryPath(configFileName), compilerOptions);
|
||||
if (configParseResult.errors.length > 0) {
|
||||
return {
|
||||
moduleKind,
|
||||
errors: configParseResult.errors
|
||||
};
|
||||
}
|
||||
const configParseResult = ts.parseJsonSourceFileConfigFileContent(result, configParseHost, ts.getDirectoryPath(configFileName), compilerOptions);
|
||||
inputFiles = configParseResult.fileNames;
|
||||
compilerOptions = configParseResult.options;
|
||||
errors = result.parseDiagnostics.concat(configParseResult.errors);
|
||||
}
|
||||
|
||||
const projectCompilerResult = compileProjectFiles(moduleKind, () => inputFiles, getSourceFileText, writeFile, compilerOptions);
|
||||
const projectCompilerResult = compileProjectFiles(moduleKind, configFileSourceFiles, () => inputFiles, getSourceFileText, writeFile, compilerOptions);
|
||||
return {
|
||||
configFileSourceFiles,
|
||||
moduleKind,
|
||||
program: projectCompilerResult.program,
|
||||
compilerOptions,
|
||||
sourceMapData: projectCompilerResult.sourceMapData,
|
||||
outputFiles,
|
||||
errors: projectCompilerResult.errors,
|
||||
errors: errors ? errors.concat(projectCompilerResult.errors) : projectCompilerResult.errors,
|
||||
};
|
||||
|
||||
function createCompilerOptions() {
|
||||
@@ -281,8 +275,8 @@ class ProjectRunner extends RunnerBase {
|
||||
: ts.normalizeSlashes(testCase.projectRoot) + "/" + ts.normalizeSlashes(fileName);
|
||||
}
|
||||
|
||||
function readDirectory(rootDir: string, extension: string[], exclude: string[], include: string[]): string[] {
|
||||
const harnessReadDirectoryResult = Harness.IO.readDirectory(getFileNameInTheProjectTest(rootDir), extension, exclude, include);
|
||||
function readDirectory(rootDir: string, extension: string[], exclude: string[], include: string[], depth: number): string[] {
|
||||
const harnessReadDirectoryResult = Harness.IO.readDirectory(getFileNameInTheProjectTest(rootDir), extension, exclude, include, depth);
|
||||
const result: string[] = [];
|
||||
for (let i = 0; i < harnessReadDirectoryResult.length; i++) {
|
||||
result[i] = ts.getRelativePathToDirectoryOrUrl(testCase.projectRoot, harnessReadDirectoryResult[i],
|
||||
@@ -295,7 +289,7 @@ class ProjectRunner extends RunnerBase {
|
||||
return Harness.IO.fileExists(getFileNameInTheProjectTest(fileName));
|
||||
}
|
||||
|
||||
function readFile(fileName: string): string {
|
||||
function readFile(fileName: string): string | undefined {
|
||||
return Harness.IO.readFile(getFileNameInTheProjectTest(fileName));
|
||||
}
|
||||
|
||||
@@ -325,8 +319,8 @@ class ProjectRunner extends RunnerBase {
|
||||
// we need to instead create files that can live in the project reference folder
|
||||
// but make sure extension of these files matches with the fileName the compiler asked to write
|
||||
diskRelativeName = "diskFile" + nonSubfolderDiskFiles +
|
||||
(Harness.Compiler.isDTS(fileName) ? ".d.ts" :
|
||||
Harness.Compiler.isJS(fileName) ? ".js" : ".js.map");
|
||||
(Harness.Compiler.isDTS(fileName) ? ts.Extension.Dts :
|
||||
Harness.Compiler.isJS(fileName) ? ts.Extension.Js : ".js.map");
|
||||
nonSubfolderDiskFiles++;
|
||||
}
|
||||
|
||||
@@ -360,7 +354,7 @@ class ProjectRunner extends RunnerBase {
|
||||
ensureDirectoryStructure(ts.getDirectoryPath(ts.normalizePath(outputFilePath)));
|
||||
Harness.IO.writeFile(outputFilePath, data);
|
||||
|
||||
outputFiles.push({ emittedFileName: fileName, code: data, fileName: diskRelativeName, writeByteOrderMark: writeByteOrderMark });
|
||||
outputFiles.push({ emittedFileName: fileName, code: data, fileName: diskRelativeName, writeByteOrderMark });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,14 +380,14 @@ class ProjectRunner extends RunnerBase {
|
||||
emitOutputFilePathWithoutExtension = ts.removeFileExtension(sourceFile.fileName);
|
||||
}
|
||||
|
||||
const outputDtsFileName = emitOutputFilePathWithoutExtension + ".d.ts";
|
||||
const outputDtsFileName = emitOutputFilePathWithoutExtension + ts.Extension.Dts;
|
||||
const file = findOutputDtsFile(outputDtsFileName);
|
||||
if (file) {
|
||||
allInputFiles.unshift(file);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const outputDtsFileName = ts.removeFileExtension(compilerOptions.outFile || compilerOptions.out) + ".d.ts";
|
||||
const outputDtsFileName = ts.removeFileExtension(compilerOptions.outFile || compilerOptions.out) + ts.Extension.Dts;
|
||||
const outputDtsFile = findOutputDtsFile(outputDtsFileName);
|
||||
if (!ts.contains(allInputFiles, outputDtsFile)) {
|
||||
allInputFiles.unshift(outputDtsFile);
|
||||
@@ -402,7 +396,7 @@ class ProjectRunner extends RunnerBase {
|
||||
});
|
||||
|
||||
// Dont allow config files since we are compiling existing source options
|
||||
return compileProjectFiles(compilerResult.moduleKind, getInputFiles, getSourceFileText, writeFile, compilerResult.compilerOptions);
|
||||
return compileProjectFiles(compilerResult.moduleKind, compilerResult.configFileSourceFiles, getInputFiles, getSourceFileText, writeFile, compilerResult.compilerOptions);
|
||||
|
||||
function findOutputDtsFile(fileName: string) {
|
||||
return ts.forEach(compilerResult.outputFiles, outputFile => outputFile.emittedFileName === fileName ? outputFile : undefined);
|
||||
@@ -428,16 +422,16 @@ class ProjectRunner extends RunnerBase {
|
||||
}
|
||||
|
||||
function getErrorsBaseline(compilerResult: CompileProjectFilesResult) {
|
||||
const inputFiles = compilerResult.program ? ts.map(ts.filter(compilerResult.program.getSourceFiles(),
|
||||
sourceFile => !Harness.isDefaultLibraryFile(sourceFile.fileName)),
|
||||
sourceFile => {
|
||||
return {
|
||||
unitName: ts.isRootedDiskPath(sourceFile.fileName) ?
|
||||
RunnerBase.removeFullPaths(sourceFile.fileName) :
|
||||
sourceFile.fileName,
|
||||
content: sourceFile.text
|
||||
};
|
||||
}) : [];
|
||||
const inputFiles = ts.map(compilerResult.configFileSourceFiles.concat(
|
||||
compilerResult.program ?
|
||||
ts.filter(compilerResult.program.getSourceFiles(), sourceFile => !Harness.isDefaultLibraryFile(sourceFile.fileName)) :
|
||||
[]),
|
||||
(sourceFile): Harness.Compiler.TestFile => ({
|
||||
unitName: ts.isRootedDiskPath(sourceFile.fileName) ?
|
||||
RunnerBase.removeFullPaths(sourceFile.fileName) :
|
||||
sourceFile.fileName,
|
||||
content: sourceFile.text
|
||||
}));
|
||||
|
||||
return Harness.Compiler.getErrorBaseline(inputFiles, compilerResult.errors);
|
||||
}
|
||||
|
||||
@@ -222,6 +222,10 @@ if (taskConfigsFolder) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ts.Debug.isDebugging) {
|
||||
ts.Debug.enableDebugInfo();
|
||||
}
|
||||
|
||||
runTests(runners);
|
||||
}
|
||||
if (!runUnitTests) {
|
||||
|
||||
+45
-32
@@ -22,14 +22,14 @@ namespace RWC {
|
||||
}
|
||||
|
||||
function isTsConfigFile(file: { path: string }): boolean {
|
||||
const tsConfigFileName = "tsconfig.json";
|
||||
return file.path.substr(file.path.length - tsConfigFileName.length).toLowerCase() === tsConfigFileName;
|
||||
return file.path.indexOf("tsconfig") !== -1 && file.path.indexOf("json") !== -1;
|
||||
}
|
||||
|
||||
export function runRWCTest(jsonPath: string) {
|
||||
describe("Testing a RWC project: " + jsonPath, () => {
|
||||
let inputFiles: Harness.Compiler.TestFile[] = [];
|
||||
let otherFiles: Harness.Compiler.TestFile[] = [];
|
||||
let tsconfigFiles: Harness.Compiler.TestFile[] = [];
|
||||
let compilerResult: Harness.Compiler.CompilerResult;
|
||||
let compilerOptions: ts.CompilerOptions;
|
||||
const baselineOpts: Harness.Baseline.BaselineOptions = {
|
||||
@@ -44,6 +44,7 @@ namespace RWC {
|
||||
// Therefore we have to clean out large objects after the test is done.
|
||||
inputFiles = [];
|
||||
otherFiles = [];
|
||||
tsconfigFiles = [];
|
||||
compilerResult = undefined;
|
||||
compilerOptions = undefined;
|
||||
currentDirectory = undefined;
|
||||
@@ -53,7 +54,8 @@ namespace RWC {
|
||||
useCustomLibraryFile = undefined;
|
||||
});
|
||||
|
||||
it("can compile", () => {
|
||||
it("can compile", function(this: Mocha.ITestCallbackContext) {
|
||||
this.timeout(800000); // Allow long timeouts for RWC compilations
|
||||
let opts: ts.ParsedCommandLine;
|
||||
|
||||
const ioLog: IOLog = JSON.parse(Harness.IO.readFile(jsonPath));
|
||||
@@ -74,21 +76,30 @@ namespace RWC {
|
||||
const tsconfigFile = ts.forEach(ioLog.filesRead, f => isTsConfigFile(f) ? f : undefined);
|
||||
if (tsconfigFile) {
|
||||
const tsconfigFileContents = getHarnessCompilerInputUnit(tsconfigFile.path);
|
||||
const parsedTsconfigFileContents = ts.parseConfigFileTextToJson(tsconfigFile.path, tsconfigFileContents.content);
|
||||
tsconfigFiles.push({ unitName: tsconfigFile.path, content: tsconfigFileContents.content });
|
||||
const parsedTsconfigFileContents = ts.parseJsonText(tsconfigFile.path, tsconfigFileContents.content);
|
||||
const configParseHost: ts.ParseConfigHost = {
|
||||
useCaseSensitiveFileNames: Harness.IO.useCaseSensitiveFileNames(),
|
||||
fileExists: Harness.IO.fileExists,
|
||||
readDirectory: Harness.IO.readDirectory,
|
||||
readFile: Harness.IO.readFile
|
||||
};
|
||||
const configParseResult = ts.parseJsonConfigFileContent(parsedTsconfigFileContents.config, configParseHost, ts.getDirectoryPath(tsconfigFile.path));
|
||||
const configParseResult = ts.parseJsonSourceFileConfigFileContent(parsedTsconfigFileContents, configParseHost, ts.getDirectoryPath(tsconfigFile.path));
|
||||
fileNames = configParseResult.fileNames;
|
||||
opts.options = ts.extend(opts.options, configParseResult.options);
|
||||
ts.setConfigFileInOptions(opts.options, configParseResult.options.configFile);
|
||||
}
|
||||
|
||||
// Load the files
|
||||
// Deduplicate files so they are only printed once in baselines (they are deduplicated within the compiler already)
|
||||
const uniqueNames = ts.createMap<true>();
|
||||
for (const fileName of fileNames) {
|
||||
inputFiles.push(getHarnessCompilerInputUnit(fileName));
|
||||
// Must maintain order, build result list while checking map
|
||||
const normalized = ts.normalizeSlashes(fileName);
|
||||
if (!uniqueNames.has(normalized)) {
|
||||
uniqueNames.set(normalized, true);
|
||||
// Load the file
|
||||
inputFiles.push(getHarnessCompilerInputUnit(fileName));
|
||||
}
|
||||
}
|
||||
|
||||
// Add files to compilation
|
||||
@@ -198,31 +209,12 @@ namespace RWC {
|
||||
return null;
|
||||
}
|
||||
// Do not include the library in the baselines to avoid noise
|
||||
const baselineFiles = inputFiles.concat(otherFiles).filter(f => !Harness.isDefaultLibraryFile(f.unitName));
|
||||
const errors = compilerResult.errors.filter(e => e.file && !Harness.isDefaultLibraryFile(e.file.fileName));
|
||||
const baselineFiles = tsconfigFiles.concat(inputFiles, otherFiles).filter(f => !Harness.isDefaultLibraryFile(f.unitName));
|
||||
const errors = compilerResult.errors.filter(e => !e.file || !Harness.isDefaultLibraryFile(e.file.fileName));
|
||||
return Harness.Compiler.getErrorBaseline(baselineFiles, errors);
|
||||
}, baselineOpts);
|
||||
});
|
||||
|
||||
// Ideally, a generated declaration file will have no errors. But we allow generated
|
||||
// declaration file errors as part of the baseline.
|
||||
it("has the expected errors in generated declaration files", () => {
|
||||
if (compilerOptions.declaration && !compilerResult.errors.length) {
|
||||
Harness.Baseline.runBaseline(`${baseName}.dts.errors.txt`, () => {
|
||||
const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(
|
||||
inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined, compilerOptions, currentDirectory);
|
||||
|
||||
if (declFileCompilationResult.declResult.errors.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Harness.Compiler.minimalDiagnosticsToString(declFileCompilationResult.declResult.errors) +
|
||||
Harness.IO.newLine() + Harness.IO.newLine() +
|
||||
Harness.Compiler.getErrorBaseline(declFileCompilationResult.declInputFiles.concat(declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
|
||||
}, baselineOpts);
|
||||
}
|
||||
});
|
||||
|
||||
it("has the expected types", () => {
|
||||
// We don't need to pass the extension here because "doTypeAndSymbolBaseline" will append appropriate extension of ".types" or ".symbols"
|
||||
Harness.Compiler.doTypeAndSymbolBaseline(baseName, compilerResult, inputFiles
|
||||
@@ -230,15 +222,36 @@ namespace RWC {
|
||||
.filter(file => !!compilerResult.program.getSourceFile(file.unitName))
|
||||
.filter(e => !Harness.isDefaultLibraryFile(e.unitName)), baselineOpts);
|
||||
});
|
||||
|
||||
// Ideally, a generated declaration file will have no errors. But we allow generated
|
||||
// declaration file errors as part of the baseline.
|
||||
it("has the expected errors in generated declaration files", () => {
|
||||
if (compilerOptions.declaration && !compilerResult.errors.length) {
|
||||
Harness.Baseline.runBaseline(`${baseName}.dts.errors.txt`, () => {
|
||||
if (compilerResult.errors.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const declContext = Harness.Compiler.prepareDeclarationCompilationContext(
|
||||
inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined, compilerOptions, currentDirectory
|
||||
);
|
||||
// Reset compilerResult before calling into `compileDeclarationFiles` so the memory from the original compilation can be freed
|
||||
compilerResult = undefined;
|
||||
const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(declContext);
|
||||
|
||||
return Harness.Compiler.minimalDiagnosticsToString(declFileCompilationResult.declResult.errors) +
|
||||
Harness.IO.newLine() + Harness.IO.newLine() +
|
||||
Harness.Compiler.getErrorBaseline(tsconfigFiles.concat(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
|
||||
}, baselineOpts);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class RWCRunner extends RunnerBase {
|
||||
private static sourcePath = "internal/cases/rwc/";
|
||||
|
||||
public enumerateTestFiles() {
|
||||
return Harness.IO.listFiles(RWCRunner.sourcePath, /.+\.json$/);
|
||||
return Harness.IO.listFiles("internal/cases/rwc/", /.+\.json$/);
|
||||
}
|
||||
|
||||
public kind(): TestRunnerKind {
|
||||
@@ -259,4 +272,4 @@ class RWCRunner extends RunnerBase {
|
||||
private runTest(jsonFileName: string) {
|
||||
RWC.runRWCTest(jsonFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ namespace Harness.SourceMapRecorder {
|
||||
export function recordSourceMapSpan(sourceMapSpan: ts.SourceMapSpan) {
|
||||
// verify the decoded span is same as the new span
|
||||
const decodeResult = SourceMapDecoder.decodeNextEncodedSourceMapSpan();
|
||||
let decodedErrors: string[];
|
||||
let decodeErrors: string[];
|
||||
if (decodeResult.error
|
||||
|| decodeResult.sourceMapSpan.emittedLine !== sourceMapSpan.emittedLine
|
||||
|| decodeResult.sourceMapSpan.emittedColumn !== sourceMapSpan.emittedColumn
|
||||
@@ -268,22 +268,20 @@ namespace Harness.SourceMapRecorder {
|
||||
|| decodeResult.sourceMapSpan.sourceIndex !== sourceMapSpan.sourceIndex
|
||||
|| decodeResult.sourceMapSpan.nameIndex !== sourceMapSpan.nameIndex) {
|
||||
if (decodeResult.error) {
|
||||
decodedErrors = ["!!^^ !!^^ There was decoding error in the sourcemap at this location: " + decodeResult.error];
|
||||
decodeErrors = ["!!^^ !!^^ There was decoding error in the sourcemap at this location: " + decodeResult.error];
|
||||
}
|
||||
else {
|
||||
decodedErrors = ["!!^^ !!^^ The decoded span from sourcemap's mapping entry does not match what was encoded for this span:"];
|
||||
decodeErrors = ["!!^^ !!^^ The decoded span from sourcemap's mapping entry does not match what was encoded for this span:"];
|
||||
}
|
||||
decodedErrors.push("!!^^ !!^^ Decoded span from sourcemap's mappings entry: " + getSourceMapSpanString(decodeResult.sourceMapSpan, /*getAbsentNameIndex*/ true) + " Span encoded by the emitter:" + getSourceMapSpanString(sourceMapSpan, /*getAbsentNameIndex*/ true));
|
||||
decodeErrors.push("!!^^ !!^^ Decoded span from sourcemap's mappings entry: " + getSourceMapSpanString(decodeResult.sourceMapSpan, /*getAbsentNameIndex*/ true) + " Span encoded by the emitter:" + getSourceMapSpanString(sourceMapSpan, /*getAbsentNameIndex*/ true));
|
||||
}
|
||||
|
||||
if (spansOnSingleLine.length && spansOnSingleLine[0].sourceMapSpan.emittedLine !== sourceMapSpan.emittedLine) {
|
||||
// On different line from the one that we have been recording till now,
|
||||
writeRecordedSpans();
|
||||
spansOnSingleLine = [{ sourceMapSpan: sourceMapSpan, decodeErrors: decodedErrors }];
|
||||
}
|
||||
else {
|
||||
spansOnSingleLine.push({ sourceMapSpan: sourceMapSpan, decodeErrors: decodedErrors });
|
||||
spansOnSingleLine = [];
|
||||
}
|
||||
spansOnSingleLine.push({ sourceMapSpan, decodeErrors });
|
||||
}
|
||||
|
||||
export function recordNewSourceFileSpan(sourceMapSpan: ts.SourceMapSpan, newSourceFileCode: string) {
|
||||
|
||||
@@ -4,19 +4,19 @@
|
||||
/* tslint:disable:no-null-keyword */
|
||||
|
||||
class Test262BaselineRunner extends RunnerBase {
|
||||
private static basePath = "internal/cases/test262";
|
||||
private static helpersFilePath = "tests/cases/test262-harness/helpers.d.ts";
|
||||
private static helperFile: Harness.Compiler.TestFile = {
|
||||
private static readonly basePath = "internal/cases/test262";
|
||||
private static readonly helpersFilePath = "tests/cases/test262-harness/helpers.d.ts";
|
||||
private static readonly helperFile: Harness.Compiler.TestFile = {
|
||||
unitName: Test262BaselineRunner.helpersFilePath,
|
||||
content: Harness.IO.readFile(Test262BaselineRunner.helpersFilePath),
|
||||
};
|
||||
private static testFileExtensionRegex = /\.js$/;
|
||||
private static options: ts.CompilerOptions = {
|
||||
private static readonly testFileExtensionRegex = /\.js$/;
|
||||
private static readonly options: ts.CompilerOptions = {
|
||||
allowNonTsExtensions: true,
|
||||
target: ts.ScriptTarget.Latest,
|
||||
module: ts.ModuleKind.CommonJS
|
||||
};
|
||||
private static baselineOptions: Harness.Baseline.BaselineOptions = {
|
||||
private static readonly baselineOptions: Harness.Baseline.BaselineOptions = {
|
||||
Subfolder: "test262",
|
||||
Baselinefolder: "internal/baselines"
|
||||
};
|
||||
@@ -48,7 +48,7 @@ class Test262BaselineRunner extends RunnerBase {
|
||||
// Emit the results
|
||||
testState = {
|
||||
filename: testFilename,
|
||||
inputFiles: inputFiles,
|
||||
inputFiles,
|
||||
compilerResult: undefined,
|
||||
};
|
||||
|
||||
|
||||
@@ -21,9 +21,11 @@
|
||||
"../compiler/parser.ts",
|
||||
"../compiler/utilities.ts",
|
||||
"../compiler/binder.ts",
|
||||
"../compiler/symbolWalker.ts",
|
||||
"../compiler/checker.ts",
|
||||
"../compiler/factory.ts",
|
||||
"../compiler/visitor.ts",
|
||||
"../compiler/transformers/utilities.ts",
|
||||
"../compiler/transformers/ts.ts",
|
||||
"../compiler/transformers/jsx.ts",
|
||||
"../compiler/transformers/esnext.ts",
|
||||
@@ -73,14 +75,9 @@
|
||||
"../services/formatting/tokenRange.ts",
|
||||
"../services/codeFixProvider.ts",
|
||||
"../services/codefixes/fixes.ts",
|
||||
"../services/codefixes/fixExtendsInterfaceBecomesImplements.ts",
|
||||
"../services/codefixes/fixClassIncorrectlyImplementsInterface.ts",
|
||||
"../services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts",
|
||||
"../services/codefixes/fixClassSuperMustPrecedeThisAccess.ts",
|
||||
"../services/codefixes/fixConstructorForDerivedNeedSuperCall.ts",
|
||||
"../services/codefixes/helpers.ts",
|
||||
"../services/codefixes/importFixes.ts",
|
||||
"../services/codefixes/unusedIdentifierFixes.ts",
|
||||
"../services/codefixes/fixUnusedIdentifier.ts",
|
||||
"../services/codefixes/disableJsDiagnostics.ts",
|
||||
|
||||
"harness.ts",
|
||||
@@ -107,6 +104,7 @@
|
||||
"./unittests/services/preProcessFile.ts",
|
||||
"./unittests/services/patternMatcher.ts",
|
||||
"./unittests/session.ts",
|
||||
"./unittests/symbolWalker.ts",
|
||||
"./unittests/versionCache.ts",
|
||||
"./unittests/convertToBase64.ts",
|
||||
"./unittests/transpile.ts",
|
||||
@@ -128,6 +126,7 @@
|
||||
"./unittests/transform.ts",
|
||||
"./unittests/customTransforms.ts",
|
||||
"./unittests/textChanges.ts",
|
||||
"./unittests/telemetry.ts"
|
||||
"./unittests/telemetry.ts",
|
||||
"./unittests/programMissingFiles.ts"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ class TypeWriterWalker {
|
||||
this.results.push({
|
||||
line: lineAndCharacter.line,
|
||||
syntaxKind: node.kind,
|
||||
sourceText: sourceText,
|
||||
sourceText,
|
||||
type: typeString,
|
||||
symbol: symbolString
|
||||
});
|
||||
|
||||
@@ -47,35 +47,24 @@ namespace ts {
|
||||
clearTimeout,
|
||||
setImmediate: typeof setImmediate !== "undefined" ? setImmediate : action => setTimeout(action, 0),
|
||||
clearImmediate: typeof clearImmediate !== "undefined" ? clearImmediate : clearTimeout,
|
||||
createHash: s => s
|
||||
createHash: Harness.LanguageService.mockHash,
|
||||
};
|
||||
}
|
||||
|
||||
function createProject(rootFile: string, serverHost: server.ServerHost): { project: server.Project, rootScriptInfo: server.ScriptInfo } {
|
||||
const logger: server.Logger = {
|
||||
close: noop,
|
||||
hasLevel: () => false,
|
||||
loggingEnabled: () => false,
|
||||
perftrc: noop,
|
||||
info: noop,
|
||||
startGroup: noop,
|
||||
endGroup: noop,
|
||||
msg: noop,
|
||||
getLogFileName: (): string => undefined
|
||||
};
|
||||
|
||||
const svcOpts: server.ProjectServiceOptions = {
|
||||
host: serverHost,
|
||||
logger,
|
||||
logger: projectSystem.nullLogger,
|
||||
cancellationToken: { isCancellationRequested: () => false },
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined
|
||||
};
|
||||
const projectService = new server.ProjectService(svcOpts);
|
||||
const rootScriptInfo = projectService.getOrCreateScriptInfo(rootFile, /* openedByClient */ true, /*containingProject*/ undefined);
|
||||
|
||||
const project = projectService.createInferredProjectWithRootFileIfNecessary(rootScriptInfo);
|
||||
project.setCompilerOptions({ module: ts.ModuleKind.AMD } );
|
||||
project.setCompilerOptions({ module: ts.ModuleKind.AMD, noLib: true } );
|
||||
return {
|
||||
project,
|
||||
rootScriptInfo
|
||||
@@ -158,7 +147,7 @@ namespace ts {
|
||||
// setting compiler options discards module resolution cache
|
||||
fileExistsCalled = false;
|
||||
|
||||
const compilerOptions = ts.clone(project.getCompilerOptions());
|
||||
const compilerOptions = ts.cloneCompilerOptions(project.getCompilerOptions());
|
||||
compilerOptions.target = ts.ScriptTarget.ES5;
|
||||
project.setCompilerOptions(compilerOptions);
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace ts.projectSystem {
|
||||
host,
|
||||
cancellationToken: nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: typingsInstaller || server.nullTypingsInstaller,
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
@@ -208,7 +209,7 @@ namespace ts.projectSystem {
|
||||
|
||||
file1Consumer1.content = `let y = 10;`;
|
||||
host.reloadFS([moduleFile1, file1Consumer1, file1Consumer2, configFile, libFile]);
|
||||
host.triggerFileWatcherCallback(file1Consumer1.path, /*removed*/ false);
|
||||
host.triggerFileWatcherCallback(file1Consumer1.path, FileWatcherEventKind.Changed);
|
||||
|
||||
session.executeCommand(changeModuleFile1ShapeRequest1);
|
||||
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer2] }]);
|
||||
@@ -225,7 +226,7 @@ namespace ts.projectSystem {
|
||||
session.executeCommand(changeModuleFile1ShapeRequest1);
|
||||
// Delete file1Consumer2
|
||||
host.reloadFS([moduleFile1, file1Consumer1, configFile, libFile]);
|
||||
host.triggerFileWatcherCallback(file1Consumer2.path, /*removed*/ true);
|
||||
host.triggerFileWatcherCallback(file1Consumer2.path, FileWatcherEventKind.Deleted);
|
||||
sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1] }]);
|
||||
});
|
||||
|
||||
@@ -475,7 +476,7 @@ namespace ts.projectSystem {
|
||||
|
||||
openFilesForSession([referenceFile1], session);
|
||||
host.reloadFS([referenceFile1, configFile]);
|
||||
host.triggerFileWatcherCallback(moduleFile1.path, /*removed*/ true);
|
||||
host.triggerFileWatcherCallback(moduleFile1.path, FileWatcherEventKind.Deleted);
|
||||
|
||||
const request = makeSessionRequest<server.protocol.FileRequestArgs>(CommandNames.CompileOnSaveAffectedFileList, { file: referenceFile1.path });
|
||||
sendAffectedFileRequestAndCheckResult(session, request, [
|
||||
@@ -513,24 +514,26 @@ namespace ts.projectSystem {
|
||||
const lines = ["var x = 1;", "var y = 2;"];
|
||||
const path = "/a/app";
|
||||
const f = {
|
||||
path: path + ".ts",
|
||||
path: path + ts.Extension.Ts,
|
||||
content: lines.join(newLine)
|
||||
};
|
||||
const host = createServerHost([f], { newLine });
|
||||
const session = createSession(host);
|
||||
session.executeCommand(<server.protocol.OpenRequest>{
|
||||
const openRequest: server.protocol.OpenRequest = {
|
||||
seq: 1,
|
||||
type: "request",
|
||||
command: "open",
|
||||
command: server.protocol.CommandTypes.Open,
|
||||
arguments: { file: f.path }
|
||||
});
|
||||
session.executeCommand(<server.protocol.CompileOnSaveEmitFileRequest>{
|
||||
};
|
||||
session.executeCommand(openRequest);
|
||||
const emitFileRequest: server.protocol.CompileOnSaveEmitFileRequest = {
|
||||
seq: 2,
|
||||
type: "request",
|
||||
command: "compileOnSaveEmitFile",
|
||||
command: server.protocol.CommandTypes.CompileOnSaveEmitFile,
|
||||
arguments: { file: f.path }
|
||||
});
|
||||
const emitOutput = host.readFile(path + ".js");
|
||||
};
|
||||
session.executeCommand(emitFileRequest);
|
||||
const emitOutput = host.readFile(path + ts.Extension.Js);
|
||||
assert.equal(emitOutput, f.content + newLine, "content of emit output should be identical with the input + newline");
|
||||
}
|
||||
});
|
||||
@@ -550,7 +553,7 @@ namespace ts.projectSystem {
|
||||
};
|
||||
const host = createServerHost([file1, file2, configFile, libFile], { newLine: "\r\n" });
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = createSession(host, typingsInstaller);
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
|
||||
openFilesForSession([file1, file2], session);
|
||||
const compileFileRequest = makeSessionRequest<server.protocol.CompileOnSaveEmitFileRequestArgs>(CommandNames.CompileOnSaveEmitFile, { file: file1.path, projectFileName: configFile.path });
|
||||
|
||||
@@ -111,23 +111,47 @@ namespace ts {
|
||||
["under a case insensitive host", caseInsensitiveBasePath, caseInsensitiveHost],
|
||||
["under a case sensitive host", caseSensitiveBasePath, caseSensitiveHost]
|
||||
], ([testName, basePath, host]) => {
|
||||
function getParseCommandLine(entry: string) {
|
||||
const {config, error} = ts.readConfigFile(entry, name => host.readFile(name));
|
||||
assert(config && !error, flattenDiagnosticMessageText(error && error.messageText, "\n"));
|
||||
return ts.parseJsonConfigFileContent(config, host, basePath, {}, entry);
|
||||
}
|
||||
|
||||
function getParseCommandLineJsonSourceFile(entry: string) {
|
||||
const jsonSourceFile = ts.readJsonConfigFile(entry, name => host.readFile(name));
|
||||
assert(jsonSourceFile.endOfFileToken && !jsonSourceFile.parseDiagnostics.length, flattenDiagnosticMessageText(jsonSourceFile.parseDiagnostics[0] && jsonSourceFile.parseDiagnostics[0].messageText, "\n"));
|
||||
return {
|
||||
jsonSourceFile,
|
||||
parsed: ts.parseJsonSourceFileConfigFileContent(jsonSourceFile, host, basePath, {}, entry)
|
||||
};
|
||||
}
|
||||
|
||||
function testSuccess(name: string, entry: string, expected: CompilerOptions, expectedFiles: string[]) {
|
||||
expected.configFilePath = entry;
|
||||
it(name, () => {
|
||||
const {config, error} = ts.readConfigFile(entry, name => host.readFile(name));
|
||||
assert(config && !error, flattenDiagnosticMessageText(error && error.messageText, "\n"));
|
||||
const parsed = ts.parseJsonConfigFileContent(config, host, basePath, {}, entry);
|
||||
const parsed = getParseCommandLine(entry);
|
||||
assert(!parsed.errors.length, flattenDiagnosticMessageText(parsed.errors[0] && parsed.errors[0].messageText, "\n"));
|
||||
expected.configFilePath = entry;
|
||||
assert.deepEqual(parsed.options, expected);
|
||||
assert.deepEqual(parsed.fileNames, expectedFiles);
|
||||
});
|
||||
|
||||
it(name + " with jsonSourceFile", () => {
|
||||
const { parsed, jsonSourceFile } = getParseCommandLineJsonSourceFile(entry);
|
||||
assert(!parsed.errors.length, flattenDiagnosticMessageText(parsed.errors[0] && parsed.errors[0].messageText, "\n"));
|
||||
assert.deepEqual(parsed.options, expected);
|
||||
assert.equal(parsed.options.configFile, jsonSourceFile);
|
||||
assert.deepEqual(parsed.fileNames, expectedFiles);
|
||||
});
|
||||
}
|
||||
|
||||
function testFailure(name: string, entry: string, expectedDiagnostics: {code: number, category: DiagnosticCategory, messageText: string}[]) {
|
||||
function testFailure(name: string, entry: string, expectedDiagnostics: { code: number, category: DiagnosticCategory, messageText: string }[]) {
|
||||
it(name, () => {
|
||||
const {config, error} = ts.readConfigFile(entry, name => host.readFile(name));
|
||||
assert(config && !error, flattenDiagnosticMessageText(error && error.messageText, "\n"));
|
||||
const parsed = ts.parseJsonConfigFileContent(config, host, basePath, {}, entry);
|
||||
const parsed = getParseCommandLine(entry);
|
||||
verifyDiagnostics(parsed.errors, expectedDiagnostics);
|
||||
});
|
||||
|
||||
it(name + " with jsonSourceFile", () => {
|
||||
const { parsed } = getParseCommandLineJsonSourceFile(entry);
|
||||
verifyDiagnostics(parsed.errors, expectedDiagnostics);
|
||||
});
|
||||
}
|
||||
@@ -185,4 +209,4 @@ namespace ts {
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
namespace ts {
|
||||
describe("convertCompilerOptionsFromJson", () => {
|
||||
function assertCompilerOptions(json: any, configFileName: string, expectedResult: { compilerOptions: CompilerOptions, errors: Diagnostic[] }) {
|
||||
assertCompilerOptionsWithJson(json, configFileName, expectedResult);
|
||||
assertCompilerOptionsWithJsonNode(json, configFileName, expectedResult);
|
||||
}
|
||||
|
||||
function assertCompilerOptionsWithJson(json: any, configFileName: string, expectedResult: { compilerOptions: CompilerOptions, errors: Diagnostic[] }) {
|
||||
const { options: actualCompilerOptions, errors: actualErrors} = convertCompilerOptionsFromJson(json["compilerOptions"], "/apath/", configFileName);
|
||||
|
||||
const parsedCompilerOptions = JSON.stringify(actualCompilerOptions);
|
||||
@@ -21,6 +26,34 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function assertCompilerOptionsWithJsonNode(json: any, configFileName: string, expectedResult: { compilerOptions: CompilerOptions, errors: Diagnostic[] }) {
|
||||
const fileText = JSON.stringify(json);
|
||||
const result = parseJsonText(configFileName, fileText);
|
||||
assert(!result.parseDiagnostics.length);
|
||||
assert(!!result.endOfFileToken);
|
||||
const host: ParseConfigHost = new Utils.MockParseConfigHost("/apath/", true, []);
|
||||
const { options: actualCompilerOptions, errors: actualParseErrors } = parseJsonSourceFileConfigFileContent(result, host, "/apath/", /*existingOptions*/ undefined, configFileName);
|
||||
expectedResult.compilerOptions["configFilePath"] = configFileName;
|
||||
|
||||
const parsedCompilerOptions = JSON.stringify(actualCompilerOptions);
|
||||
const expectedCompilerOptions = JSON.stringify(expectedResult.compilerOptions);
|
||||
assert.equal(parsedCompilerOptions, expectedCompilerOptions);
|
||||
assert.equal(actualCompilerOptions.configFile, result);
|
||||
|
||||
const actualErrors = filter(actualParseErrors, error => error.code !== Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code);
|
||||
const expectedErrors = expectedResult.errors;
|
||||
assert.isTrue(expectedResult.errors.length === actualErrors.length, `Expected error: ${JSON.stringify(expectedResult.errors)}. Actual error: ${JSON.stringify(actualErrors)}.`);
|
||||
for (let i = 0; i < actualErrors.length; i++) {
|
||||
const actualError = actualErrors[i];
|
||||
const expectedError = expectedErrors[i];
|
||||
assert.equal(actualError.code, expectedError.code, `Expected error-code: ${JSON.stringify(expectedError.code)}. Actual error-code: ${JSON.stringify(actualError.code)}.`);
|
||||
assert.equal(actualError.category, expectedError.category, `Expected error-category: ${JSON.stringify(expectedError.category)}. Actual error-category: ${JSON.stringify(actualError.category)}.`);
|
||||
assert(actualError.file);
|
||||
assert(actualError.start);
|
||||
assert(actualError.length);
|
||||
}
|
||||
}
|
||||
|
||||
// tsconfig.json tests
|
||||
it("Convert correctly format tsconfig.json to compiler-options ", () => {
|
||||
assertCompilerOptions(
|
||||
@@ -34,14 +67,14 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
sourceMap: false,
|
||||
lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"]
|
||||
},
|
||||
errors: <Diagnostic[]>[]
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -59,7 +92,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
@@ -67,7 +100,7 @@ namespace ts {
|
||||
allowJs: false,
|
||||
lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"]
|
||||
},
|
||||
errors: <Diagnostic[]>[]
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -84,7 +117,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
@@ -113,7 +146,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
sourceMap: false,
|
||||
@@ -141,7 +174,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
sourceMap: false,
|
||||
@@ -168,7 +201,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
noImplicitAny: false,
|
||||
sourceMap: false,
|
||||
},
|
||||
@@ -194,7 +227,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
noImplicitAny: false,
|
||||
sourceMap: false,
|
||||
},
|
||||
@@ -222,7 +255,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
@@ -253,7 +286,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
@@ -284,7 +317,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
@@ -315,7 +348,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
@@ -346,7 +379,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
@@ -382,8 +415,8 @@ namespace ts {
|
||||
it("Convert default tsconfig.json to compiler-options ", () => {
|
||||
assertCompilerOptions({}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: {} as CompilerOptions,
|
||||
errors: <Diagnostic[]>[]
|
||||
compilerOptions: {},
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -401,7 +434,7 @@ namespace ts {
|
||||
}
|
||||
}, "jsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
allowJs: true,
|
||||
maxNodeModuleJsDepth: 2,
|
||||
allowSyntheticDefaultImports: true,
|
||||
@@ -412,7 +445,7 @@ namespace ts {
|
||||
sourceMap: false,
|
||||
lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"]
|
||||
},
|
||||
errors: <Diagnostic[]>[]
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -430,7 +463,7 @@ namespace ts {
|
||||
}
|
||||
}, "jsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
allowJs: false,
|
||||
maxNodeModuleJsDepth: 2,
|
||||
allowSyntheticDefaultImports: true,
|
||||
@@ -441,7 +474,7 @@ namespace ts {
|
||||
sourceMap: false,
|
||||
lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"]
|
||||
},
|
||||
errors: <Diagnostic[]>[]
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -483,7 +516,7 @@ namespace ts {
|
||||
allowSyntheticDefaultImports: true,
|
||||
skipLibCheck: true
|
||||
},
|
||||
errors: <Diagnostic[]>[]
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
@@ -2,14 +2,20 @@
|
||||
/// <reference path="..\..\compiler\commandLineParser.ts" />
|
||||
|
||||
namespace ts {
|
||||
type ExpectedResult = { typeAcquisition: TypeAcquisition, errors: Diagnostic[] };
|
||||
describe("convertTypeAcquisitionFromJson", () => {
|
||||
function assertTypeAcquisition(json: any, configFileName: string, expectedResult: { typeAcquisition: TypeAcquisition, errors: Diagnostic[] }) {
|
||||
const jsonOptions = json["typeAcquisition"] || json["typingOptions"];
|
||||
const { options: actualTypeAcquisition, errors: actualErrors } = convertTypeAcquisitionFromJson(jsonOptions, "/apath/", configFileName);
|
||||
function assertTypeAcquisition(json: any, configFileName: string, expectedResult: ExpectedResult) {
|
||||
assertTypeAcquisitionWithJson(json, configFileName, expectedResult);
|
||||
assertTypeAcquisitionWithJsonNode(json, configFileName, expectedResult);
|
||||
}
|
||||
|
||||
function verifyAcquisition(actualTypeAcquisition: TypeAcquisition, expectedResult: ExpectedResult) {
|
||||
const parsedTypeAcquisition = JSON.stringify(actualTypeAcquisition);
|
||||
const expectedTypeAcquisition = JSON.stringify(expectedResult.typeAcquisition);
|
||||
assert.equal(parsedTypeAcquisition, expectedTypeAcquisition);
|
||||
}
|
||||
|
||||
function verifyErrors(actualErrors: Diagnostic[], expectedResult: ExpectedResult, hasLocation?: boolean) {
|
||||
const expectedErrors = expectedResult.errors;
|
||||
assert.isTrue(expectedResult.errors.length === actualErrors.length, `Expected error: ${JSON.stringify(expectedResult.errors)}. Actual error: ${JSON.stringify(actualErrors)}.`);
|
||||
for (let i = 0; i < actualErrors.length; i++) {
|
||||
@@ -17,9 +23,34 @@ namespace ts {
|
||||
const expectedError = expectedErrors[i];
|
||||
assert.equal(actualError.code, expectedError.code, `Expected error-code: ${JSON.stringify(expectedError.code)}. Actual error-code: ${JSON.stringify(actualError.code)}.`);
|
||||
assert.equal(actualError.category, expectedError.category, `Expected error-category: ${JSON.stringify(expectedError.category)}. Actual error-category: ${JSON.stringify(actualError.category)}.`);
|
||||
if (hasLocation) {
|
||||
assert(actualError.file);
|
||||
assert(actualError.start);
|
||||
assert(actualError.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assertTypeAcquisitionWithJson(json: any, configFileName: string, expectedResult: ExpectedResult) {
|
||||
const jsonOptions = json["typeAcquisition"] || json["typingOptions"];
|
||||
const { options: actualTypeAcquisition, errors: actualErrors } = convertTypeAcquisitionFromJson(jsonOptions, "/apath/", configFileName);
|
||||
verifyAcquisition(actualTypeAcquisition, expectedResult);
|
||||
verifyErrors(actualErrors, expectedResult);
|
||||
}
|
||||
|
||||
function assertTypeAcquisitionWithJsonNode(json: any, configFileName: string, expectedResult: ExpectedResult) {
|
||||
const fileText = JSON.stringify(json);
|
||||
const result = parseJsonText(configFileName, fileText);
|
||||
assert(!result.parseDiagnostics.length);
|
||||
assert(!!result.endOfFileToken);
|
||||
const host: ParseConfigHost = new Utils.MockParseConfigHost("/apath/", true, []);
|
||||
const { typeAcquisition: actualTypeAcquisition, errors: actualParseErrors } = parseJsonSourceFileConfigFileContent(result, host, "/apath/", /*existingOptions*/ undefined, configFileName);
|
||||
verifyAcquisition(actualTypeAcquisition, expectedResult);
|
||||
|
||||
const actualErrors = filter(actualParseErrors, error => error.code !== Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code);
|
||||
verifyErrors(actualErrors, expectedResult, /*hasLocation*/ true);
|
||||
}
|
||||
|
||||
// tsconfig.json
|
||||
it("Convert deprecated typingOptions.enableAutoDiscovery format tsconfig.json to typeAcquisition ", () => {
|
||||
assertTypeAcquisition(
|
||||
@@ -177,7 +208,7 @@ namespace ts {
|
||||
},
|
||||
errors: [
|
||||
{
|
||||
category: Diagnostics.Unknown_compiler_option_0.category,
|
||||
category: Diagnostics.Unknown_type_acquisition_option_0.category,
|
||||
code: Diagnostics.Unknown_type_acquisition_option_0.code,
|
||||
file: undefined,
|
||||
start: 0,
|
||||
|
||||
@@ -0,0 +1,591 @@
|
||||
/// <reference path="..\harness.ts" />
|
||||
/// <reference path="tsserverProjectSystem.ts" />
|
||||
|
||||
namespace ts {
|
||||
interface Range {
|
||||
start: number;
|
||||
end: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface Test {
|
||||
source: string;
|
||||
ranges: Map<Range>;
|
||||
}
|
||||
|
||||
function extractTest(source: string): Test {
|
||||
const activeRanges: Range[] = [];
|
||||
let text = "";
|
||||
let lastPos = 0;
|
||||
let pos = 0;
|
||||
const ranges = createMap<Range>();
|
||||
|
||||
while (pos < source.length) {
|
||||
if (source.charCodeAt(pos) === CharacterCodes.openBracket &&
|
||||
(source.charCodeAt(pos + 1) === CharacterCodes.hash || source.charCodeAt(pos + 1) === CharacterCodes.$)) {
|
||||
const saved = pos;
|
||||
pos += 2;
|
||||
const s = pos;
|
||||
consumeIdentifier();
|
||||
const e = pos;
|
||||
if (source.charCodeAt(pos) === CharacterCodes.bar) {
|
||||
pos++;
|
||||
text += source.substring(lastPos, saved);
|
||||
const name = s === e
|
||||
? source.charCodeAt(saved + 1) === CharacterCodes.hash ? "selection" : "extracted"
|
||||
: source.substring(s, e);
|
||||
activeRanges.push({ name, start: text.length, end: undefined });
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
pos = saved;
|
||||
}
|
||||
}
|
||||
else if (source.charCodeAt(pos) === CharacterCodes.bar && source.charCodeAt(pos + 1) === CharacterCodes.closeBracket) {
|
||||
text += source.substring(lastPos, pos);
|
||||
activeRanges[activeRanges.length - 1].end = text.length;
|
||||
const range = activeRanges.pop();
|
||||
if (range.name in ranges) {
|
||||
throw new Error(`Duplicate name of range ${range.name}`);
|
||||
}
|
||||
ranges.set(range.name, range);
|
||||
pos += 2;
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
text += source.substring(lastPos, pos);
|
||||
|
||||
function consumeIdentifier() {
|
||||
while (isIdentifierPart(source.charCodeAt(pos), ScriptTarget.Latest)) {
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
return { source: text, ranges };
|
||||
}
|
||||
|
||||
const newLineCharacter = "\n";
|
||||
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;
|
||||
}
|
||||
|
||||
function testExtractRangeFailed(caption: string, s: string, expectedErrors: string[]) {
|
||||
return it(caption, () => {
|
||||
const t = extractTest(s);
|
||||
const file = createSourceFile("a.ts", t.source, ScriptTarget.Latest, /*setParentNodes*/ true);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${s} does not specify selection range`);
|
||||
}
|
||||
const result = refactor.extractMethod.getRangeToExtract(file, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
assert(result.targetRange === undefined, "failure expected");
|
||||
const sortedErrors = result.errors.map(e => <string>e.messageText).sort();
|
||||
assert.deepEqual(sortedErrors, expectedErrors.sort(), "unexpected errors");
|
||||
});
|
||||
}
|
||||
|
||||
function testExtractRange(s: string): void {
|
||||
const t = extractTest(s);
|
||||
const f = createSourceFile("a.ts", t.source, ScriptTarget.Latest, /*setParentNodes*/ true);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${s} does not specify selection range`);
|
||||
}
|
||||
const result = refactor.extractMethod.getRangeToExtract(f, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
const expectedRange = t.ranges.get("extracted");
|
||||
if (expectedRange) {
|
||||
let start: number, end: number;
|
||||
if (ts.isArray(result.targetRange.range)) {
|
||||
start = result.targetRange.range[0].getStart(f);
|
||||
end = ts.lastOrUndefined(result.targetRange.range).getEnd();
|
||||
}
|
||||
else {
|
||||
start = result.targetRange.range.getStart(f);
|
||||
end = result.targetRange.range.getEnd();
|
||||
}
|
||||
assert.equal(start, expectedRange.start, "incorrect start of range");
|
||||
assert.equal(end, expectedRange.end, "incorrect end of range");
|
||||
}
|
||||
else {
|
||||
assert.isTrue(!result.targetRange, `expected range to extract to be undefined`);
|
||||
}
|
||||
}
|
||||
|
||||
describe("extractMethods", () => {
|
||||
it("get extract range from selection", () => {
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|var x = 1;
|
||||
var y = 2;|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
var x = 1;
|
||||
var y = 2|];
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|var x = 1|];
|
||||
var y = 2;
|
||||
`);
|
||||
testExtractRange(`
|
||||
if ([#|[#extracted|a && b && c && d|]|]) {
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
if [#|(a && b && c && d|]) {
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
if (a && b && c && d) {
|
||||
[#| [$|var x = 1;
|
||||
console.log(x);|] |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
if (a) {
|
||||
return 100;
|
||||
} |]
|
||||
`);
|
||||
testExtractRange(`
|
||||
function foo() {
|
||||
[#| [$|if (a) {
|
||||
}
|
||||
return 100|] |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|l1:
|
||||
if (x) {
|
||||
break l1;
|
||||
}|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|l2:
|
||||
{
|
||||
if (x) {
|
||||
}
|
||||
break l2;
|
||||
}|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
while (true) {
|
||||
[#| if(x) {
|
||||
}
|
||||
break; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
while (true) {
|
||||
[#| if(x) {
|
||||
}
|
||||
continue; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
l3:
|
||||
{
|
||||
[#|
|
||||
if (x) {
|
||||
}
|
||||
break l3; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
if (x) {
|
||||
return;
|
||||
} |]
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
[$|if (x) {
|
||||
}
|
||||
return;|]
|
||||
|]
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
return [#| [$|1 + 2|] |]+ 3;
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
return [$|1 + [#|2 + 3|]|];
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
return [$|1 + 2 + [#|3 + 4|]|];
|
||||
}
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed1",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
return 10;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional return statement."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed2",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
break;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional break or continue statements."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed3",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
continue;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional break or continue statements."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed4",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
l1: {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
break l1;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing labeled break or continue with target outside of the range."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed5",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
try {
|
||||
f2()
|
||||
return 10;
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
|]
|
||||
}
|
||||
function f2() {
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional return statement."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed6",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
try {
|
||||
f2()
|
||||
}
|
||||
catch (e) {
|
||||
return 10;
|
||||
}
|
||||
|]
|
||||
}
|
||||
function f2() {
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional return statement."
|
||||
]);
|
||||
|
||||
testExtractMethod("extractMethod1",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod2",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod3",
|
||||
`namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function* a(z: number) {
|
||||
[#|
|
||||
let y = 5;
|
||||
yield z;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod4",
|
||||
`namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
async function a(z: number, z1: any) {
|
||||
[#|
|
||||
let y = 5;
|
||||
if (z) {
|
||||
await z1;
|
||||
}
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod5",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod6",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod7",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export namespace C {
|
||||
export function foo() {
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return C.foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod8",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
namespace B {
|
||||
function a() {
|
||||
let a1 = 1;
|
||||
return 1 + [#|a1 + x|] + 100;
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod9",
|
||||
`namespace A {
|
||||
export interface I { x: number };
|
||||
namespace B {
|
||||
function a() {
|
||||
[#|let a1: I = { x: 1 };
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod10",
|
||||
`namespace A {
|
||||
export interface I { x: number };
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1: I = { x: 1 };
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod11",
|
||||
`namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod12",
|
||||
`namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
b() {}
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
this.b();
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
});
|
||||
|
||||
|
||||
function testExtractMethod(caption: string, text: string) {
|
||||
it(caption, () => {
|
||||
Harness.Baseline.runBaseline(`extractMethod/${caption}.js`, () => {
|
||||
const t = extractTest(text);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${caption} does not specify selection range`);
|
||||
}
|
||||
const f = {
|
||||
path: "/a.ts",
|
||||
content: t.source
|
||||
};
|
||||
const host = projectSystem.createServerHost([f]);
|
||||
const projectService = projectSystem.createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
const program = projectService.inferredProjects[0].getLanguageService().getProgram();
|
||||
const sourceFile = program.getSourceFile(f.path);
|
||||
const context: RefactorContext = {
|
||||
cancellationToken: { throwIfCancellationRequested() { }, isCancellationRequested() { return false; } },
|
||||
newLineCharacter,
|
||||
program,
|
||||
file: sourceFile,
|
||||
startPosition: -1,
|
||||
rulesProvider: getRuleProvider()
|
||||
};
|
||||
const result = refactor.extractMethod.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
assert.equal(result.errors, undefined, "expect no errors");
|
||||
const results = refactor.extractMethod.getPossibleExtractions(result.targetRange, context);
|
||||
const data: string[] = [];
|
||||
data.push(`==ORIGINAL==`);
|
||||
data.push(sourceFile.text);
|
||||
for (const r of results) {
|
||||
const changes = refactor.extractMethod.getPossibleExtractions(result.targetRange, context, results.indexOf(r))[0].changes;
|
||||
data.push(`==SCOPE::${r.scopeDescription}==`);
|
||||
data.push(textChanges.applyChanges(sourceFile.text, changes[0].textChanges));
|
||||
}
|
||||
return data.join(newLineCharacter);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -44,8 +44,8 @@ namespace ts {
|
||||
parsesCorrectly("functionType1", "{function()}");
|
||||
parsesCorrectly("functionType2", "{function(string, boolean)}");
|
||||
parsesCorrectly("functionReturnType1", "{function(string, boolean)}");
|
||||
parsesCorrectly("thisType1", "{this:a.b}");
|
||||
parsesCorrectly("newType1", "{new:a.b}");
|
||||
parsesCorrectly("thisType1", "{function(this:a.b)}");
|
||||
parsesCorrectly("newType1", "{function(new:a.b)}");
|
||||
parsesCorrectly("variadicType", "{...number}");
|
||||
parsesCorrectly("optionalType", "{number=}");
|
||||
parsesCorrectly("optionalNullable", "{?=}");
|
||||
@@ -54,7 +54,7 @@ namespace ts {
|
||||
parsesCorrectly("typeReference3", "{a.function}");
|
||||
parsesCorrectly("arrayType1", "{a[]}");
|
||||
parsesCorrectly("arrayType2", "{a[][]}");
|
||||
parsesCorrectly("arrayType3", "{a[][]=}");
|
||||
parsesCorrectly("arrayType3", "{(a[][])=}");
|
||||
parsesCorrectly("keyword1", "{var}");
|
||||
parsesCorrectly("keyword2", "{null}");
|
||||
parsesCorrectly("keyword3", "{undefined}");
|
||||
@@ -62,6 +62,12 @@ namespace ts {
|
||||
parsesCorrectly("tupleType1", "{[number]}");
|
||||
parsesCorrectly("tupleType2", "{[number,string]}");
|
||||
parsesCorrectly("tupleType3", "{[number,string,boolean]}");
|
||||
parsesCorrectly("tupleTypeWithTrailingComma", "{[number,]}");
|
||||
parsesCorrectly("typeOfType", "{typeof M}");
|
||||
parsesCorrectly("tsConstructorType", "{new () => string}");
|
||||
parsesCorrectly("tsFunctionType", "{() => string}");
|
||||
parsesCorrectly("typeArgumentsNotFollowingDot", "{a<>}");
|
||||
parsesCorrectly("functionTypeWithTrailingComma", "{function(a,)}");
|
||||
});
|
||||
|
||||
describe("parsesIncorrectly", () => {
|
||||
@@ -69,21 +75,13 @@ namespace ts {
|
||||
parsesIncorrectly("unionTypeWithTrailingBar", "{(a|)}");
|
||||
parsesIncorrectly("unionTypeWithoutTypes", "{()}");
|
||||
parsesIncorrectly("nullableTypeWithoutType", "{!}");
|
||||
parsesIncorrectly("functionTypeWithTrailingComma", "{function(a,)}");
|
||||
parsesIncorrectly("thisWithoutType", "{this:}");
|
||||
parsesIncorrectly("newWithoutType", "{new:}");
|
||||
parsesIncorrectly("variadicWithoutType", "{...}");
|
||||
parsesIncorrectly("optionalWithoutType", "{=}");
|
||||
parsesIncorrectly("allWithType", "{*foo}");
|
||||
parsesIncorrectly("typeArgumentsNotFollowingDot", "{a<>}");
|
||||
parsesIncorrectly("emptyTypeArguments", "{a.<>}");
|
||||
parsesIncorrectly("typeArgumentsWithTrailingComma", "{a.<a,>}");
|
||||
parsesIncorrectly("tsFunctionType", "{() => string}");
|
||||
parsesIncorrectly("tsConstructoType", "{new () => string}");
|
||||
parsesIncorrectly("typeOfType", "{typeof M}");
|
||||
parsesIncorrectly("namedParameter", "{function(a: number)}");
|
||||
parsesIncorrectly("tupleTypeWithComma", "{[,]}");
|
||||
parsesIncorrectly("tupleTypeWithTrailingComma", "{[number,]}");
|
||||
parsesIncorrectly("tupleTypeWithLeadingComma", "{[,number]}");
|
||||
});
|
||||
});
|
||||
|
||||
+222
-183
@@ -73,6 +73,7 @@ namespace ts {
|
||||
"c:/dev/a.d.ts",
|
||||
"c:/dev/a.js",
|
||||
"c:/dev/b.ts",
|
||||
"c:/dev/x/a.ts",
|
||||
"c:/dev/node_modules/a.ts",
|
||||
"c:/dev/bower_components/a.ts",
|
||||
"c:/dev/jspm_packages/a.ts"
|
||||
@@ -95,6 +96,42 @@ namespace ts {
|
||||
assert.deepEqual(actual.errors, expected.errors);
|
||||
}
|
||||
|
||||
function validateMatches(expected: ts.ParsedCommandLine, json: any, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[]) {
|
||||
{
|
||||
const jsonText = JSON.stringify(json);
|
||||
const result = parseJsonText(caseInsensitiveTsconfigPath, jsonText);
|
||||
const actual = ts.parseJsonSourceFileConfigFileContent(result, host, basePath, existingOptions, configFileName, resolutionStack);
|
||||
for (const error of expected.errors) {
|
||||
if (error.file) {
|
||||
error.file = result;
|
||||
}
|
||||
}
|
||||
assertParsed(actual, expected);
|
||||
}
|
||||
{
|
||||
const actual = ts.parseJsonConfigFileContent(json, host, basePath, existingOptions, configFileName, resolutionStack);
|
||||
expected.errors = expected.errors.map<Diagnostic>(error => ({
|
||||
category: error.category,
|
||||
code: error.code,
|
||||
file: undefined,
|
||||
length: undefined,
|
||||
messageText: error.messageText,
|
||||
start: undefined,
|
||||
}));
|
||||
assertParsed(actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
function createDiagnosticForConfigFile(json: any, start: number, length: number, diagnosticMessage: DiagnosticMessage, arg0: string) {
|
||||
const text = JSON.stringify(json);
|
||||
const file = <SourceFile>{ // tslint:disable-line no-object-literal-type-assertion
|
||||
fileName: caseInsensitiveTsconfigPath,
|
||||
kind: SyntaxKind.SourceFile,
|
||||
text
|
||||
};
|
||||
return ts.createFileDiagnostic(file, start, length, diagnosticMessage, arg0);
|
||||
}
|
||||
|
||||
describe("matchFiles", () => {
|
||||
it("with defaults", () => {
|
||||
const json = {};
|
||||
@@ -103,14 +140,14 @@ namespace ts {
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/a.ts",
|
||||
"c:/dev/b.ts"
|
||||
"c:/dev/b.ts",
|
||||
"c:/dev/x/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
|
||||
describe("with literal file list", () => {
|
||||
@@ -130,8 +167,7 @@ namespace ts {
|
||||
],
|
||||
wildcardDirectories: {},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("missing files are still present", () => {
|
||||
const json = {
|
||||
@@ -149,8 +185,7 @@ namespace ts {
|
||||
],
|
||||
wildcardDirectories: {},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("are not removed due to excludes", () => {
|
||||
const json = {
|
||||
@@ -171,8 +206,7 @@ namespace ts {
|
||||
],
|
||||
wildcardDirectories: {},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -193,8 +227,7 @@ namespace ts {
|
||||
],
|
||||
wildcardDirectories: {},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with non .ts file extensions are excluded", () => {
|
||||
const json = {
|
||||
@@ -212,8 +245,7 @@ namespace ts {
|
||||
fileNames: [],
|
||||
wildcardDirectories: {},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
});
|
||||
it("with missing files are excluded", () => {
|
||||
const json = {
|
||||
@@ -231,8 +263,7 @@ namespace ts {
|
||||
fileNames: [],
|
||||
wildcardDirectories: {},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
});
|
||||
it("with literal excludes", () => {
|
||||
const json = {
|
||||
@@ -252,8 +283,7 @@ namespace ts {
|
||||
],
|
||||
wildcardDirectories: {},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with wildcard excludes", () => {
|
||||
const json = {
|
||||
@@ -280,8 +310,7 @@ namespace ts {
|
||||
],
|
||||
wildcardDirectories: {},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with recursive excludes", () => {
|
||||
const json = {
|
||||
@@ -307,8 +336,7 @@ namespace ts {
|
||||
],
|
||||
wildcardDirectories: {},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with case sensitive exclude", () => {
|
||||
const json = {
|
||||
@@ -327,8 +355,7 @@ namespace ts {
|
||||
],
|
||||
wildcardDirectories: {},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseSensitiveHost, caseSensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseSensitiveHost, caseSensitiveBasePath);
|
||||
});
|
||||
it("with common package folders and no exclusions", () => {
|
||||
const json = {
|
||||
@@ -352,8 +379,7 @@ namespace ts {
|
||||
],
|
||||
wildcardDirectories: {},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with common package folders and exclusions", () => {
|
||||
const json = {
|
||||
@@ -379,8 +405,7 @@ namespace ts {
|
||||
],
|
||||
wildcardDirectories: {},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with common package folders and empty exclude", () => {
|
||||
const json = {
|
||||
@@ -404,8 +429,7 @@ namespace ts {
|
||||
],
|
||||
wildcardDirectories: {},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -436,10 +460,8 @@ namespace ts {
|
||||
"c:/dev/x": ts.WatchDirectoryFlags.None
|
||||
},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
|
||||
it("same named declarations are excluded", () => {
|
||||
const json = {
|
||||
include: [
|
||||
@@ -458,8 +480,7 @@ namespace ts {
|
||||
"c:/dev": ts.WatchDirectoryFlags.None
|
||||
},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("`*` matches only ts files", () => {
|
||||
const json = {
|
||||
@@ -479,8 +500,7 @@ namespace ts {
|
||||
"c:/dev": ts.WatchDirectoryFlags.None
|
||||
},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("`?` matches only a single character", () => {
|
||||
const json = {
|
||||
@@ -499,8 +519,7 @@ namespace ts {
|
||||
"c:/dev/x": ts.WatchDirectoryFlags.None
|
||||
},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with recursive directory", () => {
|
||||
const json = {
|
||||
@@ -521,8 +540,7 @@ namespace ts {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with multiple recursive directories", () => {
|
||||
const json = {
|
||||
@@ -545,8 +563,7 @@ namespace ts {
|
||||
"c:/dev/z": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("case sensitive", () => {
|
||||
const json = {
|
||||
@@ -564,8 +581,7 @@ namespace ts {
|
||||
"/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseSensitiveHost, caseSensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseSensitiveHost, caseSensitiveBasePath);
|
||||
});
|
||||
it("with missing files are excluded", () => {
|
||||
const json = {
|
||||
@@ -584,8 +600,7 @@ namespace ts {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
});
|
||||
it("always include literal files", () => {
|
||||
const json = {
|
||||
@@ -609,8 +624,7 @@ namespace ts {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("exclude folders", () => {
|
||||
const json = {
|
||||
@@ -634,77 +648,129 @@ namespace ts {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with common package folders and no exclusions", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"**/a.ts"
|
||||
]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/a.ts",
|
||||
"c:/dev/bower_components/a.ts",
|
||||
"c:/dev/jspm_packages/a.ts",
|
||||
"c:/dev/node_modules/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
});
|
||||
it("with common package folders and exclusions", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"**/a.ts"
|
||||
],
|
||||
exclude: [
|
||||
"a.ts"
|
||||
]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/bower_components/a.ts",
|
||||
"c:/dev/jspm_packages/a.ts",
|
||||
"c:/dev/node_modules/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
});
|
||||
it("with common package folders and empty exclude", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"**/a.ts"
|
||||
],
|
||||
exclude: <string[]>[]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/a.ts",
|
||||
"c:/dev/bower_components/a.ts",
|
||||
"c:/dev/jspm_packages/a.ts",
|
||||
"c:/dev/node_modules/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
describe("with common package folders", () => {
|
||||
it("and no exclusions", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"**/a.ts"
|
||||
]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/a.ts",
|
||||
"c:/dev/x/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("and exclusions", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"**/?.ts"
|
||||
],
|
||||
exclude: [
|
||||
"a.ts"
|
||||
]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/b.ts",
|
||||
"c:/dev/x/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("and empty exclude", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"**/a.ts"
|
||||
],
|
||||
exclude: <string[]>[]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/a.ts",
|
||||
"c:/dev/x/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("and explicit recursive include", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"**/a.ts",
|
||||
"**/node_modules/a.ts"
|
||||
]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/a.ts",
|
||||
"c:/dev/x/a.ts",
|
||||
"c:/dev/node_modules/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("and wildcard include", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"*/a.ts"
|
||||
]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/x/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("and explicit wildcard include", () => {
|
||||
const json = {
|
||||
include: [
|
||||
"*/a.ts",
|
||||
"node_modules/a.ts"
|
||||
]
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/x/a.ts",
|
||||
"c:/dev/node_modules/a.ts"
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
},
|
||||
};
|
||||
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
});
|
||||
it("exclude .js files when allowJs=false", () => {
|
||||
const json = {
|
||||
@@ -728,8 +794,7 @@ namespace ts {
|
||||
"c:/dev/js": ts.WatchDirectoryFlags.None
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
});
|
||||
it("include .js files when allowJs=true", () => {
|
||||
const json = {
|
||||
@@ -753,8 +818,7 @@ namespace ts {
|
||||
"c:/dev/js": ts.WatchDirectoryFlags.None
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("include explicitly listed .min.js files when allowJs=true", () => {
|
||||
const json = {
|
||||
@@ -778,8 +842,7 @@ namespace ts {
|
||||
"c:/dev/js": ts.WatchDirectoryFlags.None
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("include paths outside of the project", () => {
|
||||
const json = {
|
||||
@@ -802,8 +865,7 @@ namespace ts {
|
||||
"c:/ext": ts.WatchDirectoryFlags.None
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("include paths outside of the project using relative paths", () => {
|
||||
const json = {
|
||||
@@ -825,8 +887,7 @@ namespace ts {
|
||||
"c:/ext": ts.WatchDirectoryFlags.None
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("exclude paths outside of the project using relative paths", () => {
|
||||
const json = {
|
||||
@@ -846,8 +907,7 @@ namespace ts {
|
||||
fileNames: [],
|
||||
wildcardDirectories: {}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
});
|
||||
it("include files with .. in their name", () => {
|
||||
const json = {
|
||||
@@ -866,8 +926,7 @@ namespace ts {
|
||||
],
|
||||
wildcardDirectories: {}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("exclude files with .. in their name", () => {
|
||||
const json = {
|
||||
@@ -888,8 +947,7 @@ namespace ts {
|
||||
"c:/ext": ts.WatchDirectoryFlags.Recursive
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with jsx=none, allowJs=false", () => {
|
||||
const json = {
|
||||
@@ -911,8 +969,7 @@ namespace ts {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with jsx=preserve, allowJs=false", () => {
|
||||
const json = {
|
||||
@@ -936,8 +993,7 @@ namespace ts {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with jsx=react-native, allowJs=false", () => {
|
||||
const json = {
|
||||
@@ -961,8 +1017,7 @@ namespace ts {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with jsx=none, allowJs=true", () => {
|
||||
const json = {
|
||||
@@ -986,8 +1041,7 @@ namespace ts {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with jsx=preserve, allowJs=true", () => {
|
||||
const json = {
|
||||
@@ -1013,8 +1067,7 @@ namespace ts {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with jsx=react-native, allowJs=true", () => {
|
||||
const json = {
|
||||
@@ -1040,8 +1093,7 @@ namespace ts {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("exclude .min.js files using wildcards", () => {
|
||||
const json = {
|
||||
@@ -1067,9 +1119,9 @@ namespace ts {
|
||||
"c:/dev/js": ts.WatchDirectoryFlags.None
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
|
||||
describe("with trailing recursive directory", () => {
|
||||
it("in includes", () => {
|
||||
const json = {
|
||||
@@ -1080,15 +1132,14 @@ namespace ts {
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [
|
||||
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**"),
|
||||
createDiagnosticForConfigFile(json, 12, 4, ts.Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**"),
|
||||
ts.createCompilerDiagnostic(ts.Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2,
|
||||
caseInsensitiveTsconfigPath, JSON.stringify(json.include), "[]")
|
||||
],
|
||||
fileNames: [],
|
||||
wildcardDirectories: {}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
});
|
||||
it("in excludes", () => {
|
||||
const json = {
|
||||
@@ -1108,8 +1159,7 @@ namespace ts {
|
||||
fileNames: [],
|
||||
wildcardDirectories: {}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
});
|
||||
});
|
||||
describe("with multiple recursive directory patterns", () => {
|
||||
@@ -1122,15 +1172,14 @@ namespace ts {
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [
|
||||
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, "**/x/**/*"),
|
||||
createDiagnosticForConfigFile(json, 12, 11, ts.Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, "**/x/**/*"),
|
||||
ts.createCompilerDiagnostic(ts.Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2,
|
||||
caseInsensitiveTsconfigPath, JSON.stringify(json.include), "[]")
|
||||
],
|
||||
fileNames: [],
|
||||
wildcardDirectories: {}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
});
|
||||
it("in excludes", () => {
|
||||
const json = {
|
||||
@@ -1144,7 +1193,7 @@ namespace ts {
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [
|
||||
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, "**/x/**")
|
||||
createDiagnosticForConfigFile(json, 34, 9, ts.Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, "**/x/**")
|
||||
],
|
||||
fileNames: [
|
||||
"c:/dev/a.ts",
|
||||
@@ -1156,8 +1205,7 @@ namespace ts {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1171,15 +1219,14 @@ namespace ts {
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [
|
||||
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/../*"),
|
||||
createDiagnosticForConfigFile(json, 12, 9, ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/../*"),
|
||||
ts.createCompilerDiagnostic(ts.Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2,
|
||||
caseInsensitiveTsconfigPath, JSON.stringify(json.include), "[]")
|
||||
],
|
||||
fileNames: [],
|
||||
wildcardDirectories: {}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
});
|
||||
|
||||
it("in includes after a subdirectory", () => {
|
||||
@@ -1191,15 +1238,14 @@ namespace ts {
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [
|
||||
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/y/../*"),
|
||||
createDiagnosticForConfigFile(json, 12, 11, ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/y/../*"),
|
||||
ts.createCompilerDiagnostic(ts.Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2,
|
||||
caseInsensitiveTsconfigPath, JSON.stringify(json.include), "[]")
|
||||
],
|
||||
fileNames: [],
|
||||
wildcardDirectories: {}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
});
|
||||
|
||||
it("in excludes immediately after", () => {
|
||||
@@ -1214,7 +1260,7 @@ namespace ts {
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [
|
||||
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/..")
|
||||
createDiagnosticForConfigFile(json, 34, 7, ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/..")
|
||||
],
|
||||
fileNames: [
|
||||
"c:/dev/a.ts",
|
||||
@@ -1226,8 +1272,7 @@ namespace ts {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
|
||||
it("in excludes after a subdirectory", () => {
|
||||
@@ -1242,7 +1287,7 @@ namespace ts {
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {},
|
||||
errors: [
|
||||
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/y/..")
|
||||
createDiagnosticForConfigFile(json, 34, 9, ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/y/..")
|
||||
],
|
||||
fileNames: [
|
||||
"c:/dev/a.ts",
|
||||
@@ -1254,8 +1299,7 @@ namespace ts {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1272,11 +1316,11 @@ namespace ts {
|
||||
"c:/dev/z": ts.WatchDirectoryFlags.Recursive
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with files or folders that begin with a .", () => {
|
||||
it("that are not explicitly included", () => {
|
||||
const json = {
|
||||
@@ -1297,8 +1341,7 @@ namespace ts {
|
||||
"c:/dev/w": ts.WatchDirectoryFlags.Recursive
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
describe("that are explicitly included", () => {
|
||||
it("without wildcards", () => {
|
||||
@@ -1317,8 +1360,7 @@ namespace ts {
|
||||
],
|
||||
wildcardDirectories: {}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with recursive wildcards that match directories", () => {
|
||||
const json = {
|
||||
@@ -1339,8 +1381,7 @@ namespace ts {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with recursive wildcards that match nothing", () => {
|
||||
const json = {
|
||||
@@ -1361,8 +1402,7 @@ namespace ts {
|
||||
"c:/dev/x": ts.WatchDirectoryFlags.Recursive
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
|
||||
});
|
||||
it("with wildcard excludes that implicitly exclude dotted files", () => {
|
||||
const json = {
|
||||
@@ -1382,8 +1422,7 @@ namespace ts {
|
||||
fileNames: [],
|
||||
wildcardDirectories: {}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
assertParsed(actual, expected);
|
||||
validateMatches(expected, json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace ts {
|
||||
if (!expected === !actual) {
|
||||
if (expected) {
|
||||
assert.isTrue(expected.resolvedFileName === actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
|
||||
assert.isTrue(expected.extension === actual.extension, `'ext': expected '${Extension[expected.extension]}' to be equal to '${Extension[actual.extension]}'`);
|
||||
assert.isTrue(expected.extension === actual.extension, `'ext': expected '${expected.extension}' to be equal to '${actual.extension}'`);
|
||||
assert.isTrue(expected.isExternalLibraryImport === actual.isExternalLibraryImport, `'isExternalLibraryImport': expected '${expected.isExternalLibraryImport}' to be equal to '${actual.isExternalLibraryImport}'`);
|
||||
}
|
||||
return true;
|
||||
@@ -26,10 +26,19 @@ namespace ts {
|
||||
interface File {
|
||||
name: string;
|
||||
content?: string;
|
||||
symlinks?: string[];
|
||||
}
|
||||
|
||||
function createModuleResolutionHost(hasDirectoryExists: boolean, ...files: File[]): ModuleResolutionHost {
|
||||
const map = arrayToMap(files, f => f.name);
|
||||
const map = createMap<File>();
|
||||
for (const file of files) {
|
||||
map.set(file.name, file);
|
||||
if (file.symlinks) {
|
||||
for (const symlink of file.symlinks) {
|
||||
map.set(symlink, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDirectoryExists) {
|
||||
const directories = createMap<string>();
|
||||
@@ -46,6 +55,7 @@ namespace ts {
|
||||
}
|
||||
return {
|
||||
readFile,
|
||||
realpath,
|
||||
directoryExists: path => directories.has(path),
|
||||
fileExists: path => {
|
||||
assert.isTrue(directories.has(getDirectoryPath(path)), `'fileExists' '${path}' request in non-existing directory`);
|
||||
@@ -54,12 +64,15 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
else {
|
||||
return { readFile, fileExists: path => map.has(path) };
|
||||
return { readFile, realpath, fileExists: path => map.has(path) };
|
||||
}
|
||||
function readFile(path: string): string {
|
||||
function readFile(path: string): string | undefined {
|
||||
const file = map.get(path);
|
||||
return file && file.content;
|
||||
}
|
||||
function realpath(path: string): string {
|
||||
return map.get(path).name;
|
||||
}
|
||||
}
|
||||
|
||||
describe("Node module resolution - relative paths", () => {
|
||||
@@ -233,8 +246,8 @@ namespace ts {
|
||||
test(/*hasDirectoryExists*/ true);
|
||||
|
||||
function test(hasDirectoryExists: boolean) {
|
||||
const containingFile = { name: "/a/node_modules/b/c/node_modules/d/e.ts" };
|
||||
const moduleFile = { name: "/a/node_modules/foo/index.d.ts" };
|
||||
const containingFile: File = { name: "/a/node_modules/b/c/node_modules/d/e.ts" };
|
||||
const moduleFile: File = { name: "/a/node_modules/foo/index.d.ts" };
|
||||
const resolution = nodeModuleNameResolver("foo", containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, moduleFile));
|
||||
checkResolvedModuleWithFailedLookupLocations(resolution, createResolvedModule(moduleFile.name, /*isExternalLibraryImport*/ true), [
|
||||
"/a/node_modules/b/c/node_modules/d/node_modules/foo.ts",
|
||||
@@ -289,6 +302,19 @@ namespace ts {
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
testPreserveSymlinks(/*preserveSymlinks*/ false);
|
||||
testPreserveSymlinks(/*preserveSymlinks*/ true);
|
||||
function testPreserveSymlinks(preserveSymlinks: boolean) {
|
||||
it(`preserveSymlinks: ${preserveSymlinks}`, () => {
|
||||
const realFileName = "/linked/index.d.ts";
|
||||
const symlinkFileName = "/app/node_modulex/linked/index.d.ts";
|
||||
const host = createModuleResolutionHost(/*hasDirectoryExists*/ true, { name: realFileName, symlinks: [symlinkFileName] });
|
||||
const resolution = nodeModuleNameResolver("linked", "/app/app.ts", { preserveSymlinks }, host);
|
||||
const resolvedFileName = preserveSymlinks ? symlinkFileName : realFileName;
|
||||
checkResolvedModule(resolution.resolvedModule, { resolvedFileName, isExternalLibraryImport: true, extension: Extension.Dts });
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("Module resolution - relative imports", () => {
|
||||
@@ -950,8 +976,8 @@ import b = require("./moduleB");
|
||||
{
|
||||
const f1 = { name: "/root/src/app.ts" };
|
||||
const f2 = { name: "/root/src/types/lib/typings/lib.d.ts" };
|
||||
const package = { name: "/root/src/types/lib/package.json", content: JSON.stringify({ types: "typings/lib.d.ts" }) };
|
||||
test(/*typesRoot*/"/root/src/types", /* typeDirective */"lib", /*primary*/ true, f1, f2, package);
|
||||
const packageFile = { name: "/root/src/types/lib/package.json", content: JSON.stringify({ types: "typings/lib.d.ts" }) };
|
||||
test(/*typesRoot*/"/root/src/types", /* typeDirective */"lib", /*primary*/ true, f1, f2, packageFile);
|
||||
}
|
||||
{
|
||||
const f1 = { name: "/root/src/app.ts" };
|
||||
@@ -961,8 +987,8 @@ import b = require("./moduleB");
|
||||
{
|
||||
const f1 = { name: "/root/src/app.ts" };
|
||||
const f2 = { name: "/root/src/node_modules/lib/typings/lib.d.ts" };
|
||||
const package = { name: "/root/src/node_modules/lib/package.json", content: JSON.stringify({ types: "typings/lib.d.ts" }) };
|
||||
test(/*typesRoot*/"/root/src/types", /* typeDirective */"lib", /*primary*/ false, f1, f2, package);
|
||||
const packageFile = { name: "/root/src/node_modules/lib/package.json", content: JSON.stringify({ types: "typings/lib.d.ts" }) };
|
||||
test(/*typesRoot*/"/root/src/types", /* typeDirective */"lib", /*primary*/ false, f1, f2, packageFile);
|
||||
}
|
||||
{
|
||||
const f1 = { name: "/root/src/app.ts" };
|
||||
@@ -972,8 +998,8 @@ import b = require("./moduleB");
|
||||
{
|
||||
const f1 = { name: "/root/src/app.ts" };
|
||||
const f2 = { name: "/root/src/node_modules/@types/lib/typings/lib.d.ts" };
|
||||
const package = { name: "/root/src/node_modules/@types/lib/package.json", content: JSON.stringify({ types: "typings/lib.d.ts" }) };
|
||||
test(/*typesRoot*/"/root/src/types", /* typeDirective */"lib", /*primary*/ false, f1, f2, package);
|
||||
const packageFile = { name: "/root/src/node_modules/@types/lib/package.json", content: JSON.stringify({ types: "typings/lib.d.ts" }) };
|
||||
test(/*typesRoot*/"/root/src/types", /* typeDirective */"lib", /*primary*/ false, f1, f2, packageFile);
|
||||
}
|
||||
});
|
||||
it("Can be resolved from secondary location", () => {
|
||||
@@ -990,8 +1016,8 @@ import b = require("./moduleB");
|
||||
{
|
||||
const f1 = { name: "/root/src/app.ts" };
|
||||
const f2 = { name: "/root/node_modules/lib/typings/lib.d.ts" };
|
||||
const package = { name: "/root/node_modules/lib/package.json", content: JSON.stringify({ typings: "typings/lib.d.ts" }) };
|
||||
test(/*typesRoot*/"/root/src/types", /* typeDirective */"lib", /*primary*/ false, f1, f2, package);
|
||||
const packageFile = { name: "/root/node_modules/lib/package.json", content: JSON.stringify({ typings: "typings/lib.d.ts" }) };
|
||||
test(/*typesRoot*/"/root/src/types", /* typeDirective */"lib", /*primary*/ false, f1, f2, packageFile);
|
||||
}
|
||||
{
|
||||
const f1 = { name: "/root/src/app.ts" };
|
||||
@@ -1001,8 +1027,8 @@ import b = require("./moduleB");
|
||||
{
|
||||
const f1 = { name: "/root/src/app.ts" };
|
||||
const f2 = { name: "/root/node_modules/@types/lib/typings/lib.d.ts" };
|
||||
const package = { name: "/root/node_modules/@types/lib/package.json", content: JSON.stringify({ typings: "typings/lib.d.ts" }) };
|
||||
test(/*typesRoot*/"/root/src/types", /* typeDirective */"lib", /*primary*/ false, f1, f2, package);
|
||||
const packageFile = { name: "/root/node_modules/@types/lib/package.json", content: JSON.stringify({ typings: "typings/lib.d.ts" }) };
|
||||
test(/*typesRoot*/"/root/src/types", /* typeDirective */"lib", /*primary*/ false, f1, f2, packageFile);
|
||||
}
|
||||
});
|
||||
it("Primary resolution overrides secondary resolutions", () => {
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/// <reference path="..\harness.ts" />
|
||||
|
||||
namespace ts {
|
||||
describe("Program.getMissingFilePaths", () => {
|
||||
|
||||
const options: CompilerOptions = {
|
||||
noLib: true,
|
||||
};
|
||||
|
||||
const emptyFileName = "empty.ts";
|
||||
const emptyFileRelativePath = "./" + emptyFileName;
|
||||
|
||||
const emptyFile: Harness.Compiler.TestFile = {
|
||||
unitName: emptyFileName,
|
||||
content: ""
|
||||
};
|
||||
|
||||
const referenceFileName = "reference.ts";
|
||||
const referenceFileRelativePath = "./" + referenceFileName;
|
||||
|
||||
const referenceFile: Harness.Compiler.TestFile = {
|
||||
unitName: referenceFileName,
|
||||
content:
|
||||
"/// <reference path=\"d:/imaginary/nonexistent1.ts\"/>\n" + // Absolute
|
||||
"/// <reference path=\"./nonexistent2.ts\"/>\n" + // Relative
|
||||
"/// <reference path=\"nonexistent3.ts\"/>\n" + // Unqualified
|
||||
"/// <reference path=\"nonexistent4\"/>\n" // No extension
|
||||
};
|
||||
|
||||
const testCompilerHost = Harness.Compiler.createCompilerHost(
|
||||
/*inputFiles*/ [emptyFile, referenceFile],
|
||||
/*writeFile*/ undefined,
|
||||
/*scriptTarget*/ undefined,
|
||||
/*useCaseSensitiveFileNames*/ false,
|
||||
/*currentDirectory*/ "d:\\pretend\\",
|
||||
/*newLineKind*/ NewLineKind.LineFeed,
|
||||
/*libFiles*/ undefined
|
||||
);
|
||||
|
||||
it("handles no missing root files", () => {
|
||||
const program = createProgram([emptyFileRelativePath], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths();
|
||||
assert.isDefined(missing);
|
||||
assert.deepEqual(missing, []);
|
||||
});
|
||||
|
||||
it("handles missing root file", () => {
|
||||
const program = createProgram(["./nonexistent.ts"], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths();
|
||||
assert.isDefined(missing);
|
||||
assert.deepEqual(missing, ["d:/pretend/nonexistent.ts"]); // Absolute path
|
||||
});
|
||||
|
||||
it("handles multiple missing root files", () => {
|
||||
const program = createProgram(["./nonexistent0.ts", "./nonexistent1.ts"], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths().sort();
|
||||
assert.deepEqual(missing, ["d:/pretend/nonexistent0.ts", "d:/pretend/nonexistent1.ts"]);
|
||||
});
|
||||
|
||||
it("handles a mix of present and missing root files", () => {
|
||||
const program = createProgram(["./nonexistent0.ts", emptyFileRelativePath, "./nonexistent1.ts"], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths().sort();
|
||||
assert.deepEqual(missing, ["d:/pretend/nonexistent0.ts", "d:/pretend/nonexistent1.ts"]);
|
||||
});
|
||||
|
||||
it("handles repeatedly specified root files", () => {
|
||||
const program = createProgram(["./nonexistent.ts", "./nonexistent.ts"], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths();
|
||||
assert.isDefined(missing);
|
||||
assert.deepEqual(missing, ["d:/pretend/nonexistent.ts"]);
|
||||
});
|
||||
|
||||
it("normalizes file paths", () => {
|
||||
const program0 = createProgram(["./nonexistent.ts", "./NONEXISTENT.ts"], options, testCompilerHost);
|
||||
const program1 = createProgram(["./NONEXISTENT.ts", "./nonexistent.ts"], options, testCompilerHost);
|
||||
const missing0 = program0.getMissingFilePaths();
|
||||
const missing1 = program1.getMissingFilePaths();
|
||||
assert.equal(missing0.length, 1);
|
||||
assert.deepEqual(missing0, missing1);
|
||||
});
|
||||
|
||||
it("handles missing triple slash references", () => {
|
||||
const program = createProgram([referenceFileRelativePath], options, testCompilerHost);
|
||||
const missing = program.getMissingFilePaths().sort();
|
||||
assert.isDefined(missing);
|
||||
assert.deepEqual(missing, [
|
||||
// From absolute reference
|
||||
"d:/imaginary/nonexistent1.ts",
|
||||
|
||||
// From relative reference
|
||||
"d:/pretend/nonexistent2.ts",
|
||||
|
||||
// From unqualified reference
|
||||
"d:/pretend/nonexistent3.ts",
|
||||
|
||||
// From no-extension reference
|
||||
"d:/pretend/nonexistent4.d.ts",
|
||||
"d:/pretend/nonexistent4.ts",
|
||||
"d:/pretend/nonexistent4.tsx"
|
||||
]);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -4,9 +4,12 @@
|
||||
|
||||
namespace ts.projectSystem {
|
||||
describe("Project errors", () => {
|
||||
function checkProjectErrors(projectFiles: server.ProjectFilesWithTSDiagnostics, expectedErrors: string[]) {
|
||||
function checkProjectErrors(projectFiles: server.ProjectFilesWithTSDiagnostics, expectedErrors: ReadonlyArray<string>): void {
|
||||
assert.isTrue(projectFiles !== undefined, "missing project files");
|
||||
const errors = projectFiles.projectErrors;
|
||||
checkProjectErrorsWorker(projectFiles.projectErrors, expectedErrors);
|
||||
}
|
||||
|
||||
function checkProjectErrorsWorker(errors: ReadonlyArray<Diagnostic>, expectedErrors: ReadonlyArray<string>): void {
|
||||
assert.equal(errors ? errors.length : 0, expectedErrors.length, `expected ${expectedErrors.length} error in the list`);
|
||||
if (expectedErrors.length) {
|
||||
for (let i = 0; i < errors.length; i++) {
|
||||
@@ -122,21 +125,24 @@ namespace ts.projectSystem {
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
|
||||
assert.isTrue(configuredProject !== undefined, "should find configured project");
|
||||
checkProjectErrors(configuredProject, [
|
||||
"')' expected.",
|
||||
"Declaration or statement expected.",
|
||||
"Declaration or statement expected.",
|
||||
"Failed to parse file '/a/b/tsconfig.json'"
|
||||
checkProjectErrors(configuredProject, []);
|
||||
const projectErrors = projectService.configuredProjects[0].getAllProjectErrors();
|
||||
checkProjectErrorsWorker(projectErrors, [
|
||||
"'{' expected."
|
||||
]);
|
||||
assert.isNotNull(projectErrors[0].file);
|
||||
assert.equal(projectErrors[0].file.fileName, corruptedConfig.path);
|
||||
}
|
||||
// fix config and trigger watcher
|
||||
host.reloadFS([file1, file2, correctConfig]);
|
||||
host.triggerFileWatcherCallback(correctConfig.path, /*false*/);
|
||||
host.triggerFileWatcherCallback(correctConfig.path, FileWatcherEventKind.Changed);
|
||||
{
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
|
||||
assert.isTrue(configuredProject !== undefined, "should find configured project");
|
||||
checkProjectErrors(configuredProject, []);
|
||||
const projectErrors = projectService.configuredProjects[0].getAllProjectErrors();
|
||||
checkProjectErrorsWorker(projectErrors, []);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -166,21 +172,24 @@ namespace ts.projectSystem {
|
||||
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
|
||||
assert.isTrue(configuredProject !== undefined, "should find configured project");
|
||||
checkProjectErrors(configuredProject, []);
|
||||
const projectErrors = projectService.configuredProjects[0].getAllProjectErrors();
|
||||
checkProjectErrorsWorker(projectErrors, []);
|
||||
}
|
||||
// break config and trigger watcher
|
||||
host.reloadFS([file1, file2, corruptedConfig]);
|
||||
host.triggerFileWatcherCallback(corruptedConfig.path, /*false*/);
|
||||
host.triggerFileWatcherCallback(corruptedConfig.path, FileWatcherEventKind.Changed);
|
||||
{
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
|
||||
assert.isTrue(configuredProject !== undefined, "should find configured project");
|
||||
checkProjectErrors(configuredProject, [
|
||||
"')' expected.",
|
||||
"Declaration or statement expected.",
|
||||
"Declaration or statement expected.",
|
||||
"Failed to parse file '/a/b/tsconfig.json'"
|
||||
checkProjectErrors(configuredProject, []);
|
||||
const projectErrors = projectService.configuredProjects[0].getAllProjectErrors();
|
||||
checkProjectErrorsWorker(projectErrors, [
|
||||
"'{' expected."
|
||||
]);
|
||||
assert.isNotNull(projectErrors[0].file);
|
||||
assert.equal(projectErrors[0].file.fileName, corruptedConfig.path);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,10 @@ namespace ts {
|
||||
function createTestCompilerHost(texts: NamedSourceText[], target: ScriptTarget, oldProgram?: ProgramWithSourceTexts): TestCompilerHost {
|
||||
const files = arrayToMap(texts, t => t.name, t => {
|
||||
if (oldProgram) {
|
||||
const oldFile = <SourceFileWithText>oldProgram.getSourceFile(t.name);
|
||||
let oldFile = <SourceFileWithText>oldProgram.getSourceFile(t.name);
|
||||
if (oldFile && oldFile.redirectInfo) {
|
||||
oldFile = oldFile.redirectInfo.unredirected;
|
||||
}
|
||||
if (oldFile && oldFile.sourceText.getVersion() === t.text.getVersion()) {
|
||||
return oldFile;
|
||||
}
|
||||
@@ -171,11 +174,16 @@ namespace ts {
|
||||
return program;
|
||||
}
|
||||
|
||||
function updateProgramText(files: ReadonlyArray<NamedSourceText>, fileName: string, newProgramText: string) {
|
||||
const file = find(files, f => f.name === fileName)!;
|
||||
file.text = file.text.updateProgram(newProgramText);
|
||||
}
|
||||
|
||||
function checkResolvedTypeDirective(expected: ResolvedTypeReferenceDirective, actual: ResolvedTypeReferenceDirective): boolean {
|
||||
if (!expected === !actual) {
|
||||
if (expected) {
|
||||
assert.isTrue(expected.resolvedFileName === actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
|
||||
assert.isTrue(expected.primary === actual.primary, `'primary': expected '${expected.primary}' to be equal to '${actual.primary}'`);
|
||||
assert.equal(expected.resolvedFileName, actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
|
||||
assert.equal(expected.primary, actual.primary, `'primary': expected '${expected.primary}' to be equal to '${actual.primary}'`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -238,7 +246,7 @@ namespace ts {
|
||||
const program_2 = updateProgram(program_1, ["a.ts"], { target }, files => {
|
||||
files[0].text = files[0].text.updateProgram("var x = 100");
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Completely);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
const program1Diagnostics = program_1.getSemanticDiagnostics(program_1.getSourceFile("a.ts"));
|
||||
const program2Diagnostics = program_2.getSemanticDiagnostics(program_1.getSourceFile("a.ts"));
|
||||
assert.equal(program1Diagnostics.length, program2Diagnostics.length);
|
||||
@@ -249,7 +257,7 @@ namespace ts {
|
||||
const program_2 = updateProgram(program_1, ["a.ts"], { target }, files => {
|
||||
files[0].text = files[0].text.updateProgram("var x = 100");
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Completely);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
const program1Diagnostics = program_1.getSemanticDiagnostics(program_1.getSourceFile("a.ts"));
|
||||
const program2Diagnostics = program_2.getSemanticDiagnostics(program_1.getSourceFile("a.ts"));
|
||||
assert.equal(program1Diagnostics.length, program2Diagnostics.length);
|
||||
@@ -263,19 +271,19 @@ namespace ts {
|
||||
`;
|
||||
files[0].text = files[0].text.updateReferences(newReferences);
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.SafeModules);
|
||||
});
|
||||
|
||||
it("fails if change affects type references", () => {
|
||||
const program_1 = newProgram(files, ["a.ts"], { types: ["a"] });
|
||||
updateProgram(program_1, ["a.ts"], { types: ["b"] }, noop);
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Not);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
});
|
||||
|
||||
it("succeeds if change doesn't affect type references", () => {
|
||||
const program_1 = newProgram(files, ["a.ts"], { types: ["a"] });
|
||||
updateProgram(program_1, ["a.ts"], { types: ["a"] }, noop);
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Completely);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
});
|
||||
|
||||
it("fails if change affects imports", () => {
|
||||
@@ -283,7 +291,7 @@ namespace ts {
|
||||
updateProgram(program_1, ["a.ts"], { target }, files => {
|
||||
files[2].text = files[2].text.updateImportsAndExports("import x from 'b'");
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.SafeModules);
|
||||
});
|
||||
|
||||
it("fails if change affects type directives", () => {
|
||||
@@ -295,25 +303,50 @@ namespace ts {
|
||||
/// <reference types="typerefs1" />`;
|
||||
files[0].text = files[0].text.updateReferences(newReferences);
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.SafeModules);
|
||||
});
|
||||
|
||||
it("fails if module kind changes", () => {
|
||||
const program_1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS });
|
||||
updateProgram(program_1, ["a.ts"], { target, module: ModuleKind.AMD }, noop);
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Not);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
});
|
||||
|
||||
it("fails if rootdir changes", () => {
|
||||
const program_1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/b" });
|
||||
updateProgram(program_1, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/c" }, noop);
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Not);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
});
|
||||
|
||||
it("fails if config path changes", () => {
|
||||
const program_1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, configFilePath: "/a/b/tsconfig.json" });
|
||||
updateProgram(program_1, ["a.ts"], { target, module: ModuleKind.CommonJS, configFilePath: "/a/c/tsconfig.json" }, noop);
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Not);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
});
|
||||
|
||||
it("succeeds if missing files remain missing", () => {
|
||||
const options: CompilerOptions = { target, noLib: true };
|
||||
|
||||
const program_1 = newProgram(files, ["a.ts"], options);
|
||||
assert.notDeepEqual(emptyArray, program_1.getMissingFilePaths());
|
||||
|
||||
const program_2 = updateProgram(program_1, ["a.ts"], options, noop);
|
||||
assert.deepEqual(program_1.getMissingFilePaths(), program_2.getMissingFilePaths());
|
||||
|
||||
assert.equal(StructureIsReused.Completely, program_1.structureIsReused);
|
||||
});
|
||||
|
||||
it("fails if missing file is created", () => {
|
||||
const options: CompilerOptions = { target, noLib: true };
|
||||
|
||||
const program_1 = newProgram(files, ["a.ts"], options);
|
||||
assert.notDeepEqual(emptyArray, program_1.getMissingFilePaths());
|
||||
|
||||
const newTexts: NamedSourceText[] = files.concat([{ name: "non-existing-file.ts", text: SourceText.New("", "", `var x = 1`) }]);
|
||||
const program_2 = updateProgram(program_1, ["a.ts"], options, noop, newTexts);
|
||||
assert.deepEqual(emptyArray, program_2.getMissingFilePaths());
|
||||
|
||||
assert.equal(StructureIsReused.SafeModules, program_1.structureIsReused);
|
||||
});
|
||||
|
||||
it("resolution cache follows imports", () => {
|
||||
@@ -332,7 +365,7 @@ namespace ts {
|
||||
const program_2 = updateProgram(program_1, ["a.ts"], options, files => {
|
||||
files[0].text = files[0].text.updateProgram("var x = 2");
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Completely);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
|
||||
// content of resolution cache should not change
|
||||
checkResolvedModulesCache(program_1, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts") }));
|
||||
@@ -342,7 +375,7 @@ namespace ts {
|
||||
const program_3 = updateProgram(program_2, ["a.ts"], options, files => {
|
||||
files[0].text = files[0].text.updateImportsAndExports("");
|
||||
});
|
||||
assert.isTrue(program_2.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_2.structureIsReused, StructureIsReused.SafeModules);
|
||||
checkResolvedModulesCache(program_3, "a.ts", /*expectedContent*/ undefined);
|
||||
|
||||
const program_4 = updateProgram(program_3, ["a.ts"], options, files => {
|
||||
@@ -351,7 +384,7 @@ namespace ts {
|
||||
`;
|
||||
files[0].text = files[0].text.updateImportsAndExports(newImports);
|
||||
});
|
||||
assert.isTrue(program_3.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_3.structureIsReused, StructureIsReused.SafeModules);
|
||||
checkResolvedModulesCache(program_4, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts"), "c": undefined }));
|
||||
});
|
||||
|
||||
@@ -369,7 +402,7 @@ namespace ts {
|
||||
const program_2 = updateProgram(program_1, ["/a.ts"], options, files => {
|
||||
files[0].text = files[0].text.updateProgram("var x = 2");
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Completely);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
|
||||
// content of resolution cache should not change
|
||||
checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
|
||||
@@ -380,7 +413,7 @@ namespace ts {
|
||||
files[0].text = files[0].text.updateReferences("");
|
||||
});
|
||||
|
||||
assert.isTrue(program_2.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_2.structureIsReused, StructureIsReused.SafeModules);
|
||||
checkResolvedTypeDirectivesCache(program_3, "/a.ts", /*expectedContent*/ undefined);
|
||||
|
||||
updateProgram(program_3, ["/a.ts"], options, files => {
|
||||
@@ -389,7 +422,7 @@ namespace ts {
|
||||
`;
|
||||
files[0].text = files[0].text.updateReferences(newReferences);
|
||||
});
|
||||
assert.isTrue(program_3.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_3.structureIsReused, StructureIsReused.SafeModules);
|
||||
checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
|
||||
});
|
||||
|
||||
@@ -429,7 +462,7 @@ namespace ts {
|
||||
"initialProgram: execute module resolution normally.");
|
||||
|
||||
const initialProgramDiagnostics = initialProgram.getSemanticDiagnostics(initialProgram.getSourceFile("file1.ts"));
|
||||
assert(initialProgramDiagnostics.length === 1, `initialProgram: import should fail.`);
|
||||
assert.lengthOf(initialProgramDiagnostics, 1, `initialProgram: import should fail.`);
|
||||
}
|
||||
|
||||
const afterNpmInstallProgram = updateProgram(initialProgram, rootFiles.map(f => f.name), options, f => {
|
||||
@@ -453,7 +486,7 @@ namespace ts {
|
||||
"afterNpmInstallProgram: execute module resolution normally.");
|
||||
|
||||
const afterNpmInstallProgramDiagnostics = afterNpmInstallProgram.getSemanticDiagnostics(afterNpmInstallProgram.getSourceFile("file1.ts"));
|
||||
assert(afterNpmInstallProgramDiagnostics.length === 0, `afterNpmInstallProgram: program is well-formed with import.`);
|
||||
assert.lengthOf(afterNpmInstallProgramDiagnostics, 0, `afterNpmInstallProgram: program is well-formed with import.`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -592,10 +625,10 @@ namespace ts {
|
||||
"File 'f1.ts' exist - use it as a name resolution result.",
|
||||
"======== Module name './f1' was successfully resolved to 'f1.ts'. ========"
|
||||
],
|
||||
"program_1: execute module reoslution normally.");
|
||||
"program_1: execute module resolution normally.");
|
||||
|
||||
const program_1Diagnostics = program_1.getSemanticDiagnostics(program_1.getSourceFile("f2.ts"));
|
||||
assert(program_1Diagnostics.length === expectedErrors, `initial program should be well-formed`);
|
||||
assert.lengthOf(program_1Diagnostics, expectedErrors, `initial program should be well-formed`);
|
||||
}
|
||||
const indexOfF1 = 6;
|
||||
const program_2 = updateProgram(program_1, program_1.getRootFileNames(), options, f => {
|
||||
@@ -605,7 +638,7 @@ namespace ts {
|
||||
|
||||
{
|
||||
const program_2Diagnostics = program_2.getSemanticDiagnostics(program_2.getSourceFile("f2.ts"));
|
||||
assert(program_2Diagnostics.length === expectedErrors, `removing no-default-lib shouldn't affect any types used.`);
|
||||
assert.lengthOf(program_2Diagnostics, expectedErrors, `removing no-default-lib shouldn't affect any types used.`);
|
||||
|
||||
assert.deepEqual(program_2.host.getTrace(), [
|
||||
"======== Resolving type reference directive 'typerefs1', containing file 'f1.ts', root directory 'node_modules/@types'. ========",
|
||||
@@ -634,7 +667,7 @@ namespace ts {
|
||||
|
||||
{
|
||||
const program_3Diagnostics = program_3.getSemanticDiagnostics(program_3.getSourceFile("f2.ts"));
|
||||
assert(program_3Diagnostics.length === expectedErrors, `typerefs2 was unused, so diagnostics should be unaffected.`);
|
||||
assert.lengthOf(program_3Diagnostics, expectedErrors, `typerefs2 was unused, so diagnostics should be unaffected.`);
|
||||
|
||||
assert.deepEqual(program_3.host.getTrace(), [
|
||||
"======== Resolving module './b1' from 'f1.ts'. ========",
|
||||
@@ -659,7 +692,7 @@ namespace ts {
|
||||
|
||||
{
|
||||
const program_4Diagnostics = program_4.getSemanticDiagnostics(program_4.getSourceFile("f2.ts"));
|
||||
assert(program_4Diagnostics.length === expectedErrors, `a1.ts was unused, so diagnostics should be unaffected.`);
|
||||
assert.lengthOf(program_4Diagnostics, expectedErrors, `a1.ts was unused, so diagnostics should be unaffected.`);
|
||||
|
||||
assert.deepEqual(program_4.host.getTrace(), [
|
||||
"======== Resolving module './b1' from 'f1.ts'. ========",
|
||||
@@ -683,7 +716,7 @@ namespace ts {
|
||||
|
||||
{
|
||||
const program_5Diagnostics = program_5.getSemanticDiagnostics(program_5.getSourceFile("f2.ts"));
|
||||
assert(program_5Diagnostics.length === ++expectedErrors, `import of BB in f1 fails. BB is of type any. Add one error`);
|
||||
assert.lengthOf(program_5Diagnostics, ++expectedErrors, `import of BB in f1 fails. BB is of type any. Add one error`);
|
||||
|
||||
assert.deepEqual(program_5.host.getTrace(), [
|
||||
"======== Resolving module './b1' from 'f1.ts'. ========",
|
||||
@@ -700,7 +733,7 @@ namespace ts {
|
||||
|
||||
{
|
||||
const program_6Diagnostics = program_6.getSemanticDiagnostics(program_6.getSourceFile("f2.ts"));
|
||||
assert(program_6Diagnostics.length === expectedErrors, `import of BB in f1 fails.`);
|
||||
assert.lengthOf(program_6Diagnostics, expectedErrors, `import of BB in f1 fails.`);
|
||||
|
||||
assert.deepEqual(program_6.host.getTrace(), [
|
||||
"======== Resolving module './b1' from 'f1.ts'. ========",
|
||||
@@ -724,7 +757,7 @@ namespace ts {
|
||||
|
||||
{
|
||||
const program_7Diagnostics = program_7.getSemanticDiagnostics(program_7.getSourceFile("f2.ts"));
|
||||
assert(program_7Diagnostics.length === expectedErrors, `removing import is noop with respect to program, so no change in diagnostics.`);
|
||||
assert.lengthOf(program_7Diagnostics, expectedErrors, `removing import is noop with respect to program, so no change in diagnostics.`);
|
||||
|
||||
assert.deepEqual(program_7.host.getTrace(), [
|
||||
"======== Resolving type reference directive 'typerefs2', containing file 'f2.ts', root directory 'node_modules/@types'. ========",
|
||||
@@ -737,6 +770,98 @@ namespace ts {
|
||||
], "program_7 should reuse module resolutions in f2 since it is unchanged");
|
||||
}
|
||||
});
|
||||
|
||||
describe("redirects", () => {
|
||||
const axIndex = "/node_modules/a/node_modules/x/index.d.ts";
|
||||
const axPackage = "/node_modules/a/node_modules/x/package.json";
|
||||
const bxIndex = "/node_modules/b/node_modules/x/index.d.ts";
|
||||
const bxPackage = "/node_modules/b/node_modules/x/package.json";
|
||||
const root = "/a.ts";
|
||||
const compilerOptions = { target, moduleResolution: ModuleResolutionKind.NodeJs };
|
||||
|
||||
function createRedirectProgram(options?: { bText: string, bVersion: string }): ProgramWithSourceTexts {
|
||||
const files: NamedSourceText[] = [
|
||||
{
|
||||
name: "/node_modules/a/index.d.ts",
|
||||
text: SourceText.New("", 'import X from "x";', "export function a(x: X): void;"),
|
||||
},
|
||||
{
|
||||
name: axIndex,
|
||||
text: SourceText.New("", "", "export default class X { private x: number; }"),
|
||||
},
|
||||
{
|
||||
name: axPackage,
|
||||
text: SourceText.New("", "", JSON.stringify({ name: "x", version: "1.2.3" })),
|
||||
},
|
||||
{
|
||||
name: "/node_modules/b/index.d.ts",
|
||||
text: SourceText.New("", 'import X from "x";', "export const b: X;"),
|
||||
},
|
||||
{
|
||||
name: bxIndex,
|
||||
text: SourceText.New("", "", options ? options.bText : "export default class X { private x: number; }"),
|
||||
},
|
||||
{
|
||||
name: bxPackage,
|
||||
text: SourceText.New("", "", JSON.stringify({ name: "x", version: options ? options.bVersion : "1.2.3" })),
|
||||
},
|
||||
{
|
||||
name: root,
|
||||
text: SourceText.New("", 'import { a } from "a"; import { b } from "b";', "a(b)"),
|
||||
},
|
||||
];
|
||||
|
||||
return newProgram(files, [root], compilerOptions);
|
||||
}
|
||||
|
||||
function updateRedirectProgram(program: ProgramWithSourceTexts, updater: (files: NamedSourceText[]) => void): ProgramWithSourceTexts {
|
||||
return updateProgram(program, [root], compilerOptions, updater);
|
||||
}
|
||||
|
||||
it("No changes -> redirect not broken", () => {
|
||||
const program_1 = createRedirectProgram();
|
||||
|
||||
const program_2 = updateRedirectProgram(program_1, files => {
|
||||
updateProgramText(files, root, "const x = 1;");
|
||||
});
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
assert.deepEqual(program_2.getSemanticDiagnostics(), emptyArray);
|
||||
});
|
||||
|
||||
it("Target changes -> redirect broken", () => {
|
||||
const program_1 = createRedirectProgram();
|
||||
assert.deepEqual(program_1.getSemanticDiagnostics(), emptyArray);
|
||||
|
||||
const program_2 = updateRedirectProgram(program_1, files => {
|
||||
updateProgramText(files, axIndex, "export default class X { private x: number; private y: number; }");
|
||||
updateProgramText(files, axPackage, JSON.stringify('{ name: "x", version: "1.2.4" }'));
|
||||
});
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
assert.lengthOf(program_2.getSemanticDiagnostics(), 1);
|
||||
});
|
||||
|
||||
it("Underlying changes -> redirect broken", () => {
|
||||
const program_1 = createRedirectProgram();
|
||||
|
||||
const program_2 = updateRedirectProgram(program_1, files => {
|
||||
updateProgramText(files, bxIndex, "export default class X { private x: number; private y: number; }");
|
||||
updateProgramText(files, bxPackage, JSON.stringify({ name: "x", version: "1.2.4" }));
|
||||
});
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
assert.lengthOf(program_2.getSemanticDiagnostics(), 1);
|
||||
});
|
||||
|
||||
it("Previously duplicate packages -> program structure not reused", () => {
|
||||
const program_1 = createRedirectProgram({ bVersion: "1.2.4", bText: "export = class X { private x: number; }" });
|
||||
|
||||
const program_2 = updateRedirectProgram(program_1, files => {
|
||||
updateProgramText(files, bxIndex, "export default class X { private x: number; }");
|
||||
updateProgramText(files, bxPackage, JSON.stringify({ name: "x", version: "1.2.3" }));
|
||||
});
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
assert.deepEqual(program_2.getSemanticDiagnostics(), []);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("host is optional", () => {
|
||||
|
||||
@@ -30,13 +30,9 @@ describe("Colorization", function () {
|
||||
function identifier(text: string, position?: number) { return createClassification(text, ts.TokenClass.Identifier, position); }
|
||||
function numberLiteral(text: string, position?: number) { return createClassification(text, ts.TokenClass.NumberLiteral, position); }
|
||||
function stringLiteral(text: string, position?: number) { return createClassification(text, ts.TokenClass.StringLiteral, position); }
|
||||
function finalEndOfLineState(value: number): ClassificationEntry { return { value: value, classification: undefined, position: 0 }; }
|
||||
function createClassification(text: string, tokenClass: ts.TokenClass, position?: number): ClassificationEntry {
|
||||
return {
|
||||
value: text,
|
||||
classification: tokenClass,
|
||||
position: position,
|
||||
};
|
||||
function finalEndOfLineState(value: number): ClassificationEntry { return { value, classification: undefined, position: 0 }; }
|
||||
function createClassification(value: string, classification: ts.TokenClass, position?: number): ClassificationEntry {
|
||||
return { value, classification, position };
|
||||
}
|
||||
|
||||
function testLexicalClassification(text: string, initialEndOfLineState: ts.EndOfLineState, ...expectedEntries: ClassificationEntry[]): void {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user