Merge branch 'master' into cast_of_await

This commit is contained in:
Andy Hanson 2016-08-19 06:16:57 -07:00
commit b482fa58f4
850 changed files with 26597 additions and 35015 deletions

View File

@ -7,9 +7,33 @@ node_js:
sudo: false
os:
- linux
- osx
env:
- workerCount=3
matrix:
fast_finish: true
include:
- os: osx
node_js: stable
osx_image: xcode7.3
env: workerCount=2
allow_failures:
- os: osx
branches:
only:
- master
- transforms
install:
- npm uninstall typescript
- npm uninstall tslint
- npm install
- npm update
cache:
directories:
- node_modules
git:
depth: 1

View File

@ -17,7 +17,7 @@ declare module "gulp-typescript" {
stripInternal?: boolean;
types?: string[];
}
interface CompileStream extends NodeJS.ReadWriteStream {} // Either gulp or gulp-typescript has some odd typings which don't reflect reality, making this required
interface CompileStream extends NodeJS.ReadWriteStream { } // Either gulp or gulp-typescript has some odd typings which don't reflect reality, making this required
}
import * as insert from "gulp-insert";
import * as sourcemaps from "gulp-sourcemaps";
@ -34,7 +34,7 @@ import through2 = require("through2");
import merge2 = require("merge2");
import intoStream = require("into-stream");
import * as os from "os";
import Linter = require("tslint");
import fold = require("travis-fold");
const gulp = helpMaker(originalGulp);
const mochaParallel = require("./scripts/mocha-parallel.js");
const {runTestsInParallel} = mochaParallel;
@ -59,14 +59,13 @@ const cmdLineOptions = minimist(process.argv.slice(2), {
browser: process.env.browser || process.env.b || "IE",
tests: process.env.test || process.env.tests || process.env.t,
light: process.env.light || false,
port: process.env.port || process.env.p || "8888",
reporter: process.env.reporter || process.env.r,
lint: process.env.lint || true,
files: process.env.f || process.env.file || process.env.files || "",
}
});
function exec(cmd: string, args: string[], complete: () => void = (() => {}), error: (e: any, status: number) => void = (() => {})) {
function exec(cmd: string, args: string[], complete: () => void = (() => { }), error: (e: any, status: number) => void = (() => { })) {
console.log(`${cmd} ${args.join(" ")}`);
// TODO (weswig): Update child_process types to add windowsVerbatimArguments to the type definition
const subshellFlag = isWin ? "/c" : "-c";
@ -117,12 +116,12 @@ const es2015LibrarySources = [
];
const es2015LibrarySourceMap = es2015LibrarySources.map(function(source) {
return { target: "lib." + source, sources: ["header.d.ts", source] };
return { target: "lib." + source, sources: ["header.d.ts", source] };
});
const es2016LibrarySource = [ "es2016.array.include.d.ts" ];
const es2016LibrarySource = ["es2016.array.include.d.ts"];
const es2016LibrarySourceMap = es2016LibrarySource.map(function (source) {
const es2016LibrarySourceMap = es2016LibrarySource.map(function(source) {
return { target: "lib." + source, sources: ["header.d.ts", source] };
});
@ -131,38 +130,38 @@ const es2017LibrarySource = [
"es2017.sharedmemory.d.ts"
];
const es2017LibrarySourceMap = es2017LibrarySource.map(function (source) {
const es2017LibrarySourceMap = es2017LibrarySource.map(function(source) {
return { target: "lib." + source, sources: ["header.d.ts", source] };
});
const hostsLibrarySources = ["dom.generated.d.ts", "webworker.importscripts.d.ts", "scripthost.d.ts"];
const librarySourceMap = [
// Host library
{ target: "lib.dom.d.ts", sources: ["header.d.ts", "dom.generated.d.ts"] },
{ target: "lib.dom.iterable.d.ts", sources: ["header.d.ts", "dom.iterable.d.ts"] },
{ target: "lib.webworker.d.ts", sources: ["header.d.ts", "webworker.generated.d.ts"] },
{ target: "lib.scripthost.d.ts", sources: ["header.d.ts", "scripthost.d.ts"] },
// Host library
{ target: "lib.dom.d.ts", sources: ["header.d.ts", "dom.generated.d.ts"] },
{ target: "lib.dom.iterable.d.ts", sources: ["header.d.ts", "dom.iterable.d.ts"] },
{ target: "lib.webworker.d.ts", sources: ["header.d.ts", "webworker.generated.d.ts"] },
{ target: "lib.scripthost.d.ts", sources: ["header.d.ts", "scripthost.d.ts"] },
// JavaScript library
{ target: "lib.es5.d.ts", sources: ["header.d.ts", "es5.d.ts"] },
{ target: "lib.es2015.d.ts", sources: ["header.d.ts", "es2015.d.ts"] },
{ target: "lib.es2016.d.ts", sources: ["header.d.ts", "es2016.d.ts"] },
{ target: "lib.es2017.d.ts", sources: ["header.d.ts", "es2017.d.ts"] },
// JavaScript library
{ target: "lib.es5.d.ts", sources: ["header.d.ts", "es5.d.ts"] },
{ target: "lib.es2015.d.ts", sources: ["header.d.ts", "es2015.d.ts"] },
{ target: "lib.es2016.d.ts", sources: ["header.d.ts", "es2016.d.ts"] },
{ target: "lib.es2017.d.ts", sources: ["header.d.ts", "es2017.d.ts"] },
// JavaScript + all host library
{ target: "lib.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(hostsLibrarySources) },
{ target: "lib.es6.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(es2015LibrarySources, hostsLibrarySources, "dom.iterable.d.ts") }
// JavaScript + all host library
{ target: "lib.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(hostsLibrarySources) },
{ target: "lib.es6.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(es2015LibrarySources, hostsLibrarySources, "dom.iterable.d.ts") }
].concat(es2015LibrarySourceMap, es2016LibrarySourceMap, es2017LibrarySourceMap);
const libraryTargets = librarySourceMap.map(function (f) {
const libraryTargets = librarySourceMap.map(function(f) {
return path.join(builtLocalDirectory, f.target);
});
for (const i in libraryTargets) {
const entry = librarySourceMap[i];
const target = libraryTargets[i];
const sources = [copyright].concat(entry.sources.map(function (s) {
const sources = [copyright].concat(entry.sources.map(function(s) {
return path.join(libraryDirectory, s);
}));
gulp.task(target, false, [], function() {
@ -392,7 +391,7 @@ gulp.task(servicesFile, false, ["lib", "generate-diagnostics"], () => {
.pipe(sourcemaps.init())
.pipe(tsc(servicesProject));
const completedJs = js.pipe(prependCopyright())
.pipe(sourcemaps.write("."));
.pipe(sourcemaps.write("."));
const completedDts = dts.pipe(prependCopyright(/*outputCopyright*/true))
.pipe(insert.transform((contents, file) => {
file.path = standaloneDefinitionsFile;
@ -435,22 +434,22 @@ const tsserverLibraryDefinitionFile = path.join(builtLocalDirectory, "tsserverli
gulp.task(tsserverLibraryFile, false, [servicesFile], (done) => {
const serverLibraryProject = tsc.createProject("src/server/tsconfig.library.json", getCompilerSettings({}, /*useBuiltCompiler*/ true));
const {js, dts}: {js: NodeJS.ReadableStream, dts: NodeJS.ReadableStream} = serverLibraryProject.src()
const {js, dts}: { js: NodeJS.ReadableStream, dts: NodeJS.ReadableStream } = serverLibraryProject.src()
.pipe(sourcemaps.init())
.pipe(newer(tsserverLibraryFile))
.pipe(tsc(serverLibraryProject));
return merge2([
js.pipe(prependCopyright())
.pipe(sourcemaps.write("."))
.pipe(gulp.dest(builtLocalDirectory)),
.pipe(sourcemaps.write("."))
.pipe(gulp.dest(builtLocalDirectory)),
dts.pipe(prependCopyright())
.pipe(gulp.dest(builtLocalDirectory))
.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]);
gulp.task("local", "Builds the full compiler and services", [builtLocalCompiler, servicesFile, serverFile, builtGeneratedDiagnosticMessagesJSON, tsserverLibraryFile]);
gulp.task("tsc", "Builds only the compiler", [builtLocalCompiler]);
@ -477,7 +476,7 @@ gulp.task(specMd, false, [word2mdJs], (done) => {
const specMDFullPath = path.resolve(specMd);
const cmd = "cscript //nologo " + word2mdJs + " \"" + specWordFullPath + "\" " + "\"" + specMDFullPath + "\"";
console.log(cmd);
cp.exec(cmd, function () {
cp.exec(cmd, function() {
done();
});
});
@ -493,18 +492,18 @@ gulp.task("dontUseDebugMode", false, [], (done) => { useDebugMode = false; done(
gulp.task("VerifyLKG", false, [], () => {
const expectedFiles = [builtLocalCompiler, servicesFile, serverFile, nodePackageFile, nodeDefinitionsFile, standaloneDefinitionsFile, tsserverLibraryFile, tsserverLibraryDefinitionFile].concat(libraryTargets);
const missingFiles = expectedFiles.filter(function (f) {
const missingFiles = expectedFiles.filter(function(f) {
return !fs.existsSync(f);
});
if (missingFiles.length > 0) {
throw new Error("Cannot replace the LKG unless all built targets are present in directory " + builtLocalDirectory +
". The following files are missing:\n" + missingFiles.join("\n"));
". The following files are missing:\n" + missingFiles.join("\n"));
}
// Copy all the targets into the LKG directory
return gulp.src(expectedFiles).pipe(gulp.dest(LKGDirectory));
});
gulp.task("LKGInternal", false, ["lib", "local", "lssl"]);
gulp.task("LKGInternal", false, ["lib", "local"]);
gulp.task("LKG", "Makes a new LKG out of the built js files", ["clean", "dontUseDebugMode"], () => {
return runSequence("LKGInternal", "VerifyLKG");
@ -532,8 +531,6 @@ const localRwcBaseline = path.join(internalTests, "baselines/rwc/local");
const refRwcBaseline = path.join(internalTests, "baselines/rwc/reference");
const localTest262Baseline = path.join(internalTests, "baselines/test262/local");
const refTest262Baseline = path.join(internalTests, "baselines/test262/reference");
gulp.task("tests", "Builds the test infrastructure using the built compiler", [run]);
gulp.task("tests-debug", "Builds the test sources and automation in debug mode", () => {
@ -628,7 +625,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: 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) {
@ -680,7 +677,7 @@ gulp.task("runtests",
["build-rules", "tests"],
(done) => {
runConsoleTests("mocha-fivemat-progress-reporter", /*runInParallel*/ false, done);
});
});
const nodeServerOutFile = "tests/webTestServer.js";
const nodeServerInFile = "tests/webTestServer.ts";
@ -710,7 +707,7 @@ gulp.task("browserify", "Runs browserify on run.js to produce a file suitable fo
const originalMap = file.sourceMap;
const prebundledContent = file.contents.toString();
// Make paths absolute to help sorcery deal with all the terrible paths being thrown around
originalMap.sources = originalMap.sources.map(s => path.resolve(s));
originalMap.sources = originalMap.sources.map(s => path.resolve("src", s));
// intoStream (below) makes browserify think the input file is named this, so this is what it puts in the sourcemap
originalMap.file = "built/local/_stream_0.js";
@ -766,7 +763,7 @@ function writeTestConfigFile(tests: string, light: boolean, taskConfigsFolder?:
}
gulp.task("runtests-browser", "Runs the tests using the built run.js file like 'gulp runtests'. Syntax is gulp runtests-browser. Additional optional parameters --tests=[regex], --port=, --browser=[chrome|IE]", ["browserify", nodeServerOutFile], (done) => {
gulp.task("runtests-browser", "Runs the tests using the built run.js file like 'gulp runtests'. Syntax is gulp runtests-browser. Additional optional parameters --tests=[regex], --browser=[chrome|IE]", ["browserify", nodeServerOutFile], (done) => {
cleanTestDirs((err) => {
if (err) { console.error(err); done(err); process.exit(1); }
host = "node";
@ -781,9 +778,6 @@ gulp.task("runtests-browser", "Runs the tests using the built run.js file like '
}
const args = [nodeServerOutFile];
if (cmdLineOptions["port"]) {
args.push(cmdLineOptions["port"]);
}
if (cmdLineOptions["browser"]) {
args.push(cmdLineOptions["browser"]);
}
@ -815,32 +809,36 @@ gulp.task("diff-rwc", "Diffs the RWC baselines using the diff tool specified by
exec(getDiffTool(), [refRwcBaseline, localRwcBaseline], done, done);
});
gulp.task("baseline-accept", "Makes the most recent test results the new baseline, overwriting the old baseline", () => {
return baselineAccept("");
});
function baselineAccept(subfolder = "") {
return merge2(baselineCopy(subfolder), baselineDelete(subfolder));
}
function baselineCopy(subfolder = "") {
return gulp.src([`tests/baselines/local/${subfolder}/**`, `!tests/baselines/local/${subfolder}/**/*.delete`])
.pipe(gulp.dest(refBaseline));
}
function baselineDelete(subfolder = "") {
return gulp.src(["tests/baselines/local/**/*.delete"])
.pipe(insert.transform((content, fileObj) => {
const target = path.join(refBaseline, fileObj.relative.substr(0, fileObj.relative.length - ".delete".length));
del.sync(target);
del.sync(fileObj.path);
return "";
}));
}
gulp.task("baseline-accept", "Makes the most recent test results the new baseline, overwriting the old baseline", (done) => {
const softAccept = cmdLineOptions["soft"];
if (!softAccept) {
del(refBaseline).then(() => {
fs.renameSync(localBaseline, refBaseline);
done();
}, done);
}
else {
gulp.src(localBaseline)
.pipe(gulp.dest(refBaseline))
.on("end", () => {
del(path.join(refBaseline, "local")).then(() => done(), done);
});
}
});
gulp.task("baseline-accept-rwc", "Makes the most recent rwc test results the new baseline, overwriting the old baseline", () => {
return del(refRwcBaseline).then(() => {
fs.renameSync(localRwcBaseline, refRwcBaseline);
});
return baselineAccept("rwc");
});
gulp.task("baseline-accept-test262", "Makes the most recent test262 test results the new baseline, overwriting the old baseline", () => {
return del(refTest262Baseline).then(() => {
fs.renameSync(localTest262Baseline, refTest262Baseline);
});
return baselineAccept("test262");
});
@ -918,56 +916,19 @@ gulp.task("update-sublime", "Updates the sublime plugin's tsserver", ["local", s
return gulp.src([serverFile, serverFile + ".map"]).pipe(gulp.dest("../TypeScript-Sublime-Plugin/tsserver/"));
});
const tslintRuleDir = "scripts/tslint";
const tslintRules = [
"nextLineRule",
"preferConstRule",
"booleanTriviaRule",
"typeOperatorSpacingRule",
"noInOperatorRule",
"noIncrementDecrementRule",
"objectLiteralSurroundingSpaceRule",
];
const tslintRulesFiles = tslintRules.map(function(p) {
return path.join(tslintRuleDir, p + ".ts");
gulp.task("build-rules", "Compiles tslint rules to js", () => {
const settings: tsc.Settings = getCompilerSettings({ module: "commonjs" }, /*useBuiltCompiler*/ false);
const dest = path.join(builtLocalDirectory, "tslint");
return gulp.src("scripts/tslint/**/*.ts")
.pipe(newer({
dest,
ext: ".js"
}))
.pipe(sourcemaps.init())
.pipe(tsc(settings))
.pipe(sourcemaps.write("."))
.pipe(gulp.dest(dest));
});
const tslintRulesOutFiles = tslintRules.map(function(p, i) {
const pathname = path.join(builtLocalDirectory, "tslint", p + ".js");
gulp.task(pathname, false, [], () => {
const settings: tsc.Settings = getCompilerSettings({ module: "commonjs" }, /*useBuiltCompiler*/ false);
return gulp.src(tslintRulesFiles[i])
.pipe(newer(pathname))
.pipe(sourcemaps.init())
.pipe(tsc(settings))
.pipe(sourcemaps.write("."))
.pipe(gulp.dest(path.join(builtLocalDirectory, "tslint")));
});
return pathname;
});
gulp.task("build-rules", "Compiles tslint rules to js", tslintRulesOutFiles);
function getLinterOptions() {
return {
configuration: require("./tslint.json"),
formatter: "prose",
formattersDirectory: undefined,
rulesDirectory: "built/local/tslint"
};
}
function lintFileContents(options, path, contents) {
const ll = new Linter(path, contents, options);
console.log("Linting '" + path + "'.");
return ll.lint();
}
function lintFile(options, path) {
const contents = fs.readFileSync(path, "utf8");
return lintFileContents(options, path, contents);
}
const lintTargets = [
"Gulpfile.ts",
@ -977,29 +938,75 @@ const lintTargets = [
"src/server/**/*.ts",
"scripts/tslint/**/*.ts",
"src/services/**/*.ts",
"tests/*.ts", "tests/webhost/*.ts" // Note: does *not* descend recursively
];
function sendNextFile(files: {path: string}[], child: cp.ChildProcess, callback: (failures: number) => void, failures: number) {
const file = files.pop();
if (file) {
console.log(`Linting '${file.path}'.`);
child.send({ kind: "file", name: file.path });
}
else {
child.send({ kind: "close" });
callback(failures);
}
}
function spawnLintWorker(files: {path: string}[], callback: (failures: number) => void) {
const child = cp.fork("./scripts/parallel-lint");
let failures = 0;
child.on("message", function(data) {
switch (data.kind) {
case "result":
if (data.failures > 0) {
failures += data.failures;
console.log(data.output);
}
sendNextFile(files, child, callback, failures);
break;
case "error":
console.error(data.error);
failures++;
sendNextFile(files, child, callback, failures);
break;
}
});
sendNextFile(files, child, callback, failures);
}
gulp.task("lint", "Runs tslint on the compiler sources. Optional arguments are: --f[iles]=regex", ["build-rules"], () => {
const fileMatcher = RegExp(cmdLineOptions["files"]);
const lintOptions = getLinterOptions();
let failed = 0;
return gulp.src(lintTargets)
.pipe(insert.transform((contents, file) => {
if (!fileMatcher.test(file.path)) return contents;
const result = lintFile(lintOptions, file.path);
if (result.failureCount > 0) {
console.log(result.output);
failed += result.failureCount;
if (fold.isTravis()) console.log(fold.start("lint"));
let files: {stat: fs.Stats, path: string}[] = [];
return gulp.src(lintTargets, { read: false })
.pipe(through2.obj((chunk, enc, cb) => {
files.push(chunk);
cb();
}, (cb) => {
files = files.filter(file => fileMatcher.test(file.path)).sort((filea, fileb) => filea.stat.size - fileb.stat.size);
const workerCount = (process.env.workerCount && +process.env.workerCount) || os.cpus().length;
for (let i = 0; i < workerCount; i++) {
spawnLintWorker(files, finished);
}
return contents; // TODO (weswig): Automatically apply fixes? :3
}))
.on("end", () => {
if (failed > 0) {
console.error("Linter errors.");
process.exit(1);
let completed = 0;
let failures = 0;
function finished(fails) {
completed++;
failures += fails;
if (completed === workerCount) {
if (fold.isTravis()) console.log(fold.end("lint"));
if (failures > 0) {
throw new Error(`Linter errors: ${failures}`);
}
else {
cb();
}
}
}
});
}));
});

View File

@ -4,7 +4,7 @@ var fs = require("fs");
var os = require("os");
var path = require("path");
var child_process = require("child_process");
var Linter = require("tslint");
var fold = require("travis-fold");
var runTestsInParallel = require("./scripts/mocha-parallel").runTestsInParallel;
// Variables
@ -32,6 +32,28 @@ if (process.env.path !== undefined) {
process.env.PATH = nodeModulesPathPrefix + process.env.PATH;
}
function toNs(diff) {
return diff[0] * 1e9 + diff[1];
}
function mark() {
if (!fold.isTravis()) return;
var stamp = process.hrtime();
var id = Math.floor(Math.random() * 0xFFFFFFFF).toString(16);
console.log("travis_time:start:" + id + "\r");
return {
stamp: stamp,
id: id
};
}
function measure(marker) {
if (!fold.isTravis()) return;
var diff = process.hrtime(marker.stamp);
var total = [marker.stamp[0] + diff[0], marker.stamp[1] + diff[1]];
console.log("travis_time:end:" + marker.id + ":start=" + toNs(marker.stamp) + ",finish=" + toNs(total) + ",duration=" + toNs(diff) + "\r");
}
var compilerSources = [
"core.ts",
"performance.ts",
@ -158,7 +180,8 @@ var harnessSources = harnessCoreSources.concat([
"convertCompilerOptionsFromJson.ts",
"convertTypingOptionsFromJson.ts",
"tsserverProjectSystem.ts",
"matchFiles.ts"
"matchFiles.ts",
"initializeTSConfig.ts",
].map(function (f) {
return path.join(unittestsDirectory, f);
})).concat([
@ -285,6 +308,7 @@ var builtLocalCompiler = path.join(builtLocalDirectory, compilerFilename);
*/
function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts, callback) {
file(outFile, prereqs, function() {
var startCompileTime = mark();
opts = opts || {};
var compilerPath = useBuiltCompiler ? builtLocalCompiler : LKGCompiler;
var options = "--noImplicitAny --noImplicitThis --noEmitOnError --types "
@ -361,11 +385,13 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts
callback();
}
measure(startCompileTime);
complete();
});
ex.addListener("error", function() {
fs.unlinkSync(outFile);
fail("Compilation of " + outFile + " unsuccessful");
measure(startCompileTime);
});
ex.run();
}, {async: true});
@ -551,7 +577,7 @@ var tsserverLibraryDefinitionFile = path.join(builtLocalDirectory, "tsserverlibr
compileFile(
tsserverLibraryFile,
languageServiceLibrarySources,
[builtLocalDirectory, copyright].concat(languageServiceLibrarySources),
[builtLocalDirectory, copyright, builtLocalCompiler].concat(languageServiceLibrarySources).concat(libraryTargets),
/*prefixes*/ [copyright],
/*useBuiltCompiler*/ true,
{ noOutFile: false, generateDeclarations: true });
@ -560,9 +586,19 @@ compileFile(
desc("Builds language service server library");
task("lssl", [tsserverLibraryFile, tsserverLibraryDefinitionFile]);
desc("Emit the start of the build fold");
task("build-fold-start", [] , function() {
if (fold.isTravis()) console.log(fold.start("build"));
});
desc("Emit the end of the build fold");
task("build-fold-end", [] , function() {
if (fold.isTravis()) console.log(fold.end("build"));
});
// Local target to build the compiler and services
desc("Builds the full compiler and services");
task("local", ["generate-diagnostics", "lib", tscFile, servicesFile, nodeDefinitionsFile, serverFile, builtGeneratedDiagnosticMessagesJSON]);
task("local", ["build-fold-start", "generate-diagnostics", "lib", tscFile, servicesFile, nodeDefinitionsFile, serverFile, builtGeneratedDiagnosticMessagesJSON, "lssl", "build-fold-end"]);
// Local target to build only tsc.js
desc("Builds only the compiler");
@ -617,7 +653,7 @@ task("generate-spec", [specMd]);
// Makes a new LKG. This target does not build anything, but errors if not all the outputs are present in the built/local directory
desc("Makes a new LKG out of the built js files");
task("LKG", ["clean", "release", "local", "lssl"].concat(libraryTargets), function() {
task("LKG", ["clean", "release", "local"].concat(libraryTargets), function() {
var expectedFiles = [tscFile, servicesFile, serverFile, nodePackageFile, nodeDefinitionsFile, standaloneDefinitionsFile, tsserverLibraryFile, tsserverLibraryDefinitionFile].concat(libraryTargets);
var missingFiles = expectedFiles.filter(function (f) {
return !fs.existsSync(f);
@ -645,7 +681,7 @@ var run = path.join(builtLocalDirectory, "run.js");
compileFile(
/*outFile*/ run,
/*source*/ harnessSources,
/*prereqs*/ [builtLocalDirectory, tscFile].concat(libraryTargets).concat(harnessSources),
/*prereqs*/ [builtLocalDirectory, tscFile].concat(libraryTargets).concat(servicesSources).concat(harnessSources),
/*prefixes*/ [],
/*useBuiltCompiler:*/ true,
/*opts*/ { inlineSourceMap: true, types: ["node", "mocha", "chai"] });
@ -758,6 +794,7 @@ function runConsoleTests(defaultReporter, runInParallel) {
// timeout normally isn't necessary but Travis-CI has been timing out on compiler baselines occasionally
// default timeout is 2sec which really should be enough, but maybe we just need a small amount longer
if(!runInParallel) {
var startTime = mark();
tests = tests ? ' -g "' + tests + '"' : '';
var cmd = "mocha" + (debug ? " --debug-brk" : "") + " -R " + reporter + tests + colors + bail + ' -t ' + testTimeout + ' ' + run;
console.log(cmd);
@ -766,10 +803,12 @@ function runConsoleTests(defaultReporter, runInParallel) {
process.env.NODE_ENV = "development";
exec(cmd, function () {
process.env.NODE_ENV = savedNodeEnv;
measure(startTime);
runLinter();
finish();
}, function(e, status) {
process.env.NODE_ENV = savedNodeEnv;
measure(startTime);
finish(status);
});
@ -777,9 +816,10 @@ function runConsoleTests(defaultReporter, runInParallel) {
else {
var savedNodeEnv = process.env.NODE_ENV;
process.env.NODE_ENV = "development";
var startTime = mark();
runTestsInParallel(taskConfigsFolder, run, { testTimeout: testTimeout, noColors: colors === " --no-colors " }, function (err) {
process.env.NODE_ENV = savedNodeEnv;
measure(startTime);
// last worker clean everything and runs linter in case if there were no errors
deleteTemporaryProjectOutput();
jake.rmRf(taskConfigsFolder);
@ -847,11 +887,10 @@ task("browserify", ["tests", builtLocalDirectory, nodeServerOutFile], function()
exec(cmd);
}, {async: true});
desc("Runs the tests using the built run.js file like 'jake runtests'. Syntax is jake runtests-browser. Additional optional parameters tests=[regex], port=, browser=[chrome|IE]");
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() {
cleanTestDirs();
host = "node";
port = process.env.port || process.env.p || '8888';
browser = process.env.browser || process.env.b || "IE";
tests = process.env.test || process.env.tests || process.env.t;
var light = process.env.light || false;
@ -864,7 +903,7 @@ task("runtests-browser", ["tests", "browserify", builtLocalDirectory, servicesFi
}
tests = tests ? tests : '';
var cmd = host + " tests/webTestServer.js " + port + " " + browser + " " + JSON.stringify(tests);
var cmd = host + " tests/webTestServer.js " + browser + " " + JSON.stringify(tests);
console.log(cmd);
exec(cmd);
}, {async: true});
@ -899,16 +938,16 @@ task("tests-debug", ["setDebugMode", "tests"]);
// Makes the test results the new baseline
desc("Makes the most recent test results the new baseline, overwriting the old baseline");
task("baseline-accept", function(hardOrSoft) {
if (!hardOrSoft || hardOrSoft === "hard") {
jake.rmRf(refBaseline);
fs.renameSync(localBaseline, refBaseline);
}
else if (hardOrSoft === "soft") {
var files = jake.readdirR(localBaseline);
for (var i in files) {
var files = jake.readdirR(localBaseline);
var deleteEnding = '.delete';
for (var i in files) {
if (files[i].substr(files[i].length - deleteEnding.length) === deleteEnding) {
var filename = path.basename(files[i]);
filename = filename.substr(0, filename.length - deleteEnding.length);
fs.unlink(path.join(refBaseline, filename));
} else {
jake.cpR(files[i], refBaseline);
}
jake.rmRf(path.join(refBaseline, "local"));
}
});
@ -990,6 +1029,7 @@ var tslintRules = [
"noInOperatorRule",
"noIncrementDecrementRule",
"objectLiteralSurroundingSpaceRule",
"noTypeAssertionWhitespaceRule"
];
var tslintRulesFiles = tslintRules.map(function(p) {
return path.join(tslintRuleDir, p + ".ts");
@ -998,41 +1038,21 @@ var tslintRulesOutFiles = tslintRules.map(function(p) {
return path.join(builtLocalDirectory, "tslint", p + ".js");
});
desc("Compiles tslint rules to js");
task("build-rules", tslintRulesOutFiles);
task("build-rules", ["build-rules-start"].concat(tslintRulesOutFiles).concat(["build-rules-end"]));
tslintRulesFiles.forEach(function(ruleFile, i) {
compileFile(tslintRulesOutFiles[i], [ruleFile], [ruleFile], [], /*useBuiltCompiler*/ false,
{ noOutFile: true, generateDeclarations: false, outDir: path.join(builtLocalDirectory, "tslint")});
});
function getLinterOptions() {
return {
configuration: require("./tslint.json"),
formatter: "prose",
formattersDirectory: undefined,
rulesDirectory: "built/local/tslint"
};
}
desc("Emit the start of the build-rules fold");
task("build-rules-start", [] , function() {
if (fold.isTravis()) console.log(fold.start("build-rules"));
});
function lintFileContents(options, path, contents) {
var ll = new Linter(path, contents, options);
console.log("Linting '" + path + "'.");
return ll.lint();
}
function lintFile(options, path) {
var contents = fs.readFileSync(path, "utf8");
return lintFileContents(options, path, contents);
}
function lintFileAsync(options, path, cb) {
fs.readFile(path, "utf8", function(err, contents) {
if (err) {
return cb(err);
}
var result = lintFileContents(options, path, contents);
cb(undefined, result);
});
}
desc("Emit the end of the build-rules fold");
task("build-rules-end", [] , function() {
if (fold.isTravis()) console.log(fold.end("build-rules"));
});
var lintTargets = compilerSources
.concat(harnessSources)
@ -1041,73 +1061,81 @@ var lintTargets = compilerSources
.concat(serverCoreSources)
.concat(tslintRulesFiles)
.concat(servicesSources)
.concat(["Gulpfile.ts"]);
.concat(["Gulpfile.ts"])
.concat([nodeServerInFile, perftscPath, "tests/perfsys.ts", webhostPath]);
function sendNextFile(files, child, callback, failures) {
var file = files.pop();
if (file) {
console.log("Linting '" + file + "'.");
child.send({kind: "file", name: file});
}
else {
child.send({kind: "close"});
callback(failures);
}
}
function spawnLintWorker(files, callback) {
var child = child_process.fork("./scripts/parallel-lint");
var failures = 0;
child.on("message", function(data) {
switch (data.kind) {
case "result":
if (data.failures > 0) {
failures += data.failures;
console.log(data.output);
}
sendNextFile(files, child, callback, failures);
break;
case "error":
console.error(data.error);
failures++;
sendNextFile(files, child, callback, failures);
break;
}
});
sendNextFile(files, child, callback, failures);
}
desc("Runs tslint on the compiler sources. Optional arguments are: f[iles]=regex");
task("lint", ["build-rules"], function() {
var lintOptions = getLinterOptions();
if (fold.isTravis()) console.log(fold.start("lint"));
var startTime = mark();
var failed = 0;
var fileMatcher = RegExp(process.env.f || process.env.file || process.env.files || "");
var done = {};
for (var i in lintTargets) {
var target = lintTargets[i];
if (!done[target] && fileMatcher.test(target)) {
var result = lintFile(lintOptions, target);
if (result.failureCount > 0) {
console.log(result.output);
failed += result.failureCount;
}
done[target] = true;
done[target] = fs.statSync(target).size;
}
}
if (failed > 0) {
fail('Linter errors.', failed);
}
});
/**
* This is required because file watches on Windows get fires _twice_
* when a file changes on some node/windows version configuations
* (node v4 and win 10, for example). By not running a lint for a file
* which already has a pending lint, we avoid duplicating our work.
* (And avoid printing duplicate results!)
*/
var lintSemaphores = {};
var workerCount = (process.env.workerCount && +process.env.workerCount) || os.cpus().length;
function lintWatchFile(filename) {
fs.watch(filename, {persistent: true}, function(event) {
if (event !== "change") {
return;
}
if (!lintSemaphores[filename]) {
lintSemaphores[filename] = true;
lintFileAsync(getLinterOptions(), filename, function(err, result) {
delete lintSemaphores[filename];
if (err) {
console.log(err);
return;
}
if (result.failureCount > 0) {
console.log("***Lint failure***");
for (var i = 0; i < result.failures.length; i++) {
var failure = result.failures[i];
var start = failure.startPosition.lineAndCharacter;
var end = failure.endPosition.lineAndCharacter;
console.log("warning " + filename + " (" + (start.line + 1) + "," + (start.character + 1) + "," + (end.line + 1) + "," + (end.character + 1) + "): " + failure.failure);
}
console.log("*** Total " + result.failureCount + " failures.");
}
});
}
var names = Object.keys(done).sort(function(namea, nameb) {
return done[namea] - done[nameb];
});
}
desc("Watches files for changes to rerun a lint pass");
task("lint-server", ["build-rules"], function() {
console.log("Watching ./src for changes to linted files");
for (var i = 0; i < lintTargets.length; i++) {
lintWatchFile(lintTargets[i]);
for (var i = 0; i < workerCount; i++) {
spawnLintWorker(names, finished);
}
});
var completed = 0;
var failures = 0;
function finished(fails) {
completed++;
failures += fails;
if (completed === workerCount) {
measure(startTime);
if (fold.isTravis()) console.log(fold.end("lint"));
if (failures > 0) {
fail('Linter errors.', failed);
}
else {
complete();
}
}
}
}, {async: true});

View File

@ -6,7 +6,7 @@
[![Join the chat at https://gitter.im/Microsoft/TypeScript](https://badges.gitter.im/Join%20Chat.svg)](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](http://blogs.msdn.com/typescript) and [Twitter account](https://twitter.com/typescriptlang).
[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).
## Installing

View File

@ -30,8 +30,8 @@
},
"devDependencies": {
"@types/browserify": "latest",
"@types/convert-source-map": "latest",
"@types/chai": "latest",
"@types/convert-source-map": "latest",
"@types/del": "latest",
"@types/glob": "latest",
"@types/gulp": "latest",
@ -69,16 +69,18 @@
"mkdirp": "latest",
"mocha": "latest",
"mocha-fivemat-progress-reporter": "latest",
"q": "latest",
"run-sequence": "latest",
"sorcery": "latest",
"through2": "latest",
"travis-fold": "latest",
"ts-node": "latest",
"tslint": "next",
"typescript": "next"
},
"scripts": {
"pretest": "jake tests",
"test": "jake runtests",
"test": "jake runtests-parallel",
"build": "npm run build:compiler && npm run build:tests",
"build:compiler": "jake local",
"build:tests": "jake tests",

View File

@ -1,4 +1,4 @@
/// <reference path="../src/harness/external/node.d.ts" />
/// <reference types="node"/>
import fs = require('fs');
import path = require('path');

45
scripts/parallel-lint.js Normal file
View File

@ -0,0 +1,45 @@
var Linter = require("tslint");
var fs = require("fs");
function getLinterOptions() {
return {
configuration: require("../tslint.json"),
formatter: "prose",
formattersDirectory: undefined,
rulesDirectory: "built/local/tslint"
};
}
function lintFileContents(options, path, contents) {
var ll = new Linter(path, contents, options);
return ll.lint();
}
function lintFileAsync(options, path, cb) {
fs.readFile(path, "utf8", function (err, contents) {
if (err) {
return cb(err);
}
var result = lintFileContents(options, path, contents);
cb(undefined, result);
});
}
process.on("message", function (data) {
switch (data.kind) {
case "file":
var target = data.name;
var lintOptions = getLinterOptions();
lintFileAsync(lintOptions, target, function (err, result) {
if (err) {
process.send({ kind: "error", error: err.toString() });
return;
}
process.send({ kind: "result", failures: result.failureCount, output: result.output });
});
break;
case "close":
process.exit(0);
break;
}
});

View File

@ -69,7 +69,7 @@ function checkForUniqueCodes(messages: string[], diagnosticTable: InputDiagnosti
}
function buildUniqueNameMap(names: string[]): ts.Map<string> {
var nameMap: ts.Map<string> = {};
var nameMap = ts.createMap<string>();
var uniqueNames = NameGenerator.ensureUniqueness(names, /* isCaseSensitive */ false, /* isFixed */ undefined);

View File

@ -0,0 +1,25 @@
import * as Lint from "tslint/lib/lint";
import * as ts from "typescript";
export class Rule extends Lint.Rules.AbstractRule {
public static TRAILING_FAILURE_STRING = "Excess trailing whitespace found around type assertion.";
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithWalker(new TypeAssertionWhitespaceWalker(sourceFile, this.getOptions()));
}
}
class TypeAssertionWhitespaceWalker extends Lint.RuleWalker {
public visitNode(node: ts.Node) {
if (node.kind === ts.SyntaxKind.TypeAssertionExpression) {
const refined = node as ts.TypeAssertion;
const leftSideWhitespaceStart = refined.type.getEnd() + 1;
const rightSideWhitespaceEnd = refined.expression.getStart();
if (leftSideWhitespaceStart !== rightSideWhitespaceEnd) {
this.addFailure(this.createFailure(leftSideWhitespaceStart, rightSideWhitespaceEnd, Rule.TRAILING_FAILURE_STRING));
}
}
super.visitNode(node);
}
}

View File

@ -1,7 +1,6 @@
import * as Lint from "tslint/lib/lint";
import * as ts from "typescript";
export class Rule extends Lint.Rules.AbstractRule {
public static FAILURE_STRING_FACTORY = (identifier: string) => `Identifier '${identifier}' never appears on the LHS of an assignment - use const instead of let for its declaration.`;
@ -64,7 +63,7 @@ interface DeclarationUsages {
}
class PreferConstWalker extends Lint.RuleWalker {
private inScopeLetDeclarations: ts.Map<DeclarationUsages>[] = [];
private inScopeLetDeclarations: ts.MapLike<DeclarationUsages>[] = [];
private errors: Lint.RuleFailure[] = [];
private markAssignment(identifier: ts.Identifier) {
const name = identifier.text;
@ -172,7 +171,7 @@ class PreferConstWalker extends Lint.RuleWalker {
}
private visitAnyForStatement(node: ts.ForOfStatement | ts.ForInStatement) {
const names: ts.Map<DeclarationUsages> = {};
const names: ts.MapLike<DeclarationUsages> = {};
if (isLet(node.initializer)) {
if (node.initializer.kind === ts.SyntaxKind.VariableDeclarationList) {
this.collectLetIdentifiers(node.initializer as ts.VariableDeclarationList, names);
@ -194,7 +193,7 @@ class PreferConstWalker extends Lint.RuleWalker {
}
visitBlock(node: ts.Block) {
const names: ts.Map<DeclarationUsages> = {};
const names: ts.MapLike<DeclarationUsages> = {};
for (const statement of node.statements) {
if (statement.kind === ts.SyntaxKind.VariableStatement) {
this.collectLetIdentifiers((statement as ts.VariableStatement).declarationList, names);
@ -205,7 +204,7 @@ class PreferConstWalker extends Lint.RuleWalker {
this.popDeclarations();
}
private collectLetIdentifiers(list: ts.VariableDeclarationList, ret: ts.Map<DeclarationUsages>) {
private collectLetIdentifiers(list: ts.VariableDeclarationList, ret: ts.MapLike<DeclarationUsages>) {
for (const node of list.declarations) {
if (isLet(node) && !isExported(node)) {
this.collectNameIdentifiers(node, node.name, ret);
@ -213,7 +212,7 @@ class PreferConstWalker extends Lint.RuleWalker {
}
}
private collectNameIdentifiers(declaration: ts.VariableDeclaration, node: ts.Identifier | ts.BindingPattern, table: ts.Map<DeclarationUsages>) {
private collectNameIdentifiers(declaration: ts.VariableDeclaration, node: ts.Identifier | ts.BindingPattern, table: ts.MapLike<DeclarationUsages>) {
if (node.kind === ts.SyntaxKind.Identifier) {
table[(node as ts.Identifier).text] = { declaration, usages: 0 };
}
@ -222,7 +221,7 @@ class PreferConstWalker extends Lint.RuleWalker {
}
}
private collectBindingPatternIdentifiers(value: ts.VariableDeclaration, pattern: ts.BindingPattern, table: ts.Map<DeclarationUsages>) {
private collectBindingPatternIdentifiers(value: ts.VariableDeclaration, pattern: ts.BindingPattern, table: ts.MapLike<DeclarationUsages>) {
for (const element of pattern.elements) {
this.collectNameIdentifiers(value, element.name, table);
}

View File

@ -10,7 +10,7 @@ declare module "gulp-insert" {
export function append(text: string | Buffer): NodeJS.ReadWriteStream;
export function prepend(text: string | Buffer): NodeJS.ReadWriteStream;
export function wrap(text: string | Buffer, tail: string | Buffer): NodeJS.ReadWriteStream;
export function transform(cb: (contents: string, file: {path: string}) => string): NodeJS.ReadWriteStream; // file is a vinyl file
export function transform(cb: (contents: string, file: {path: string, relative: string}) => string): NodeJS.ReadWriteStream; // file is a vinyl file
}
declare module "into-stream" {
@ -22,3 +22,4 @@ declare module "into-stream" {
}
declare module "sorcery";
declare module "travis-fold";

View File

@ -89,9 +89,10 @@ namespace ts {
const binder = createBinder();
export function bindSourceFile(file: SourceFile, options: CompilerOptions) {
const start = performance.mark();
performance.mark("beforeBind");
binder(file, options);
performance.measure("Bind", start);
performance.mark("afterBind");
performance.measure("Bind", "beforeBind", "afterBind");
}
function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
@ -135,7 +136,7 @@ namespace ts {
options = opts;
languageVersion = getEmitScriptTarget(options);
inStrictMode = !!file.externalModuleIndicator;
classifiableNames = {};
classifiableNames = createMap<string>();
symbolCount = 0;
Symbol = objectAllocator.getSymbolConstructor();
@ -183,11 +184,11 @@ namespace ts {
symbol.declarations.push(node);
if (symbolFlags & SymbolFlags.HasExports && !symbol.exports) {
symbol.exports = {};
symbol.exports = createMap<Symbol>();
}
if (symbolFlags & SymbolFlags.HasMembers && !symbol.members) {
symbol.members = {};
symbol.members = createMap<Symbol>();
}
if (symbolFlags & SymbolFlags.Value) {
@ -298,8 +299,10 @@ namespace ts {
const name = isDefaultExport && parent ? "default" : getDeclarationName(node);
let symbol: Symbol;
if (name !== undefined) {
if (name === undefined) {
symbol = createSymbol(SymbolFlags.None, "__missing");
}
else {
// Check and see if the symbol table already has a symbol with this name. If not,
// create a new symbol with this name and add it to the table. Note that we don't
// give the new symbol any flags *yet*. This ensures that it will not conflict
@ -311,6 +314,11 @@ namespace ts {
// declaration we have for this symbol, and then create a new symbol for this
// declaration.
//
// Note that when properties declared in Javascript constructors
// (marked by isReplaceableByMethod) conflict with another symbol, the property loses.
// Always. This allows the common Javascript pattern of overwriting a prototype method
// with an bound instance method of the same type: `this.method = this.method.bind(this)`
//
// If we created a new symbol, either because we didn't have a symbol with this name
// in the symbol table, or we conflicted with an existing symbol, then just add this
// node as the sole declaration of the new symbol.
@ -318,42 +326,44 @@ namespace ts {
// Otherwise, we'll be merging into a compatible existing symbol (for example when
// 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 = hasProperty(symbolTable, name)
? symbolTable[name]
: (symbolTable[name] = createSymbol(SymbolFlags.None, name));
symbol = symbolTable[name] || (symbolTable[name] = createSymbol(SymbolFlags.None, name));
if (name && (includes & SymbolFlags.Classifiable)) {
classifiableNames[name] = name;
}
if (symbol.flags & excludes) {
if (node.name) {
node.name.parent = node;
if (symbol.isReplaceableByMethod) {
// Javascript constructor-declared symbols can be discarded in favor of
// prototype symbols like methods.
symbol = symbolTable[name] = createSymbol(SymbolFlags.None, name);
}
// Report errors every position with duplicate declaration
// Report errors on previous encountered declarations
let message = symbol.flags & SymbolFlags.BlockScopedVariable
? Diagnostics.Cannot_redeclare_block_scoped_variable_0
: Diagnostics.Duplicate_identifier_0;
forEach(symbol.declarations, declaration => {
if (declaration.flags & NodeFlags.Default) {
message = Diagnostics.A_module_cannot_have_multiple_default_exports;
else {
if (node.name) {
node.name.parent = node;
}
});
forEach(symbol.declarations, declaration => {
file.bindDiagnostics.push(createDiagnosticForNode(declaration.name || declaration, message, getDisplayName(declaration)));
});
file.bindDiagnostics.push(createDiagnosticForNode(node.name || node, message, getDisplayName(node)));
// Report errors every position with duplicate declaration
// Report errors on previous encountered declarations
let message = symbol.flags & SymbolFlags.BlockScopedVariable
? Diagnostics.Cannot_redeclare_block_scoped_variable_0
: Diagnostics.Duplicate_identifier_0;
symbol = createSymbol(SymbolFlags.None, name);
forEach(symbol.declarations, declaration => {
if (declaration.flags & NodeFlags.Default) {
message = Diagnostics.A_module_cannot_have_multiple_default_exports;
}
});
forEach(symbol.declarations, declaration => {
file.bindDiagnostics.push(createDiagnosticForNode(declaration.name || declaration, message, getDisplayName(declaration)));
});
file.bindDiagnostics.push(createDiagnosticForNode(node.name || node, message, getDisplayName(node)));
symbol = createSymbol(SymbolFlags.None, name);
}
}
}
else {
symbol = createSymbol(SymbolFlags.None, "__missing");
}
addDeclarationToSymbol(symbol, node, includes);
symbol.parent = parent;
@ -434,7 +444,7 @@ namespace ts {
if (containerFlags & ContainerFlags.IsContainer) {
container = blockScopeContainer = node;
if (containerFlags & ContainerFlags.HasLocals) {
container.locals = {};
container.locals = createMap<Symbol>();
}
addToContainerChain(container);
}
@ -618,18 +628,10 @@ namespace ts {
return false;
}
function isNarrowingNullCheckOperands(expr1: Expression, expr2: Expression) {
return (expr1.kind === SyntaxKind.NullKeyword || expr1.kind === SyntaxKind.Identifier && (<Identifier>expr1).text === "undefined") && isNarrowableOperand(expr2);
}
function isNarrowingTypeofOperands(expr1: Expression, expr2: Expression) {
return expr1.kind === SyntaxKind.TypeOfExpression && isNarrowableOperand((<TypeOfExpression>expr1).expression) && expr2.kind === SyntaxKind.StringLiteral;
}
function isNarrowingDiscriminant(expr: Expression) {
return expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((<PropertyAccessExpression>expr).expression);
}
function isNarrowingBinaryExpression(expr: BinaryExpression) {
switch (expr.operatorToken.kind) {
case SyntaxKind.EqualsToken:
@ -638,9 +640,8 @@ namespace ts {
case SyntaxKind.ExclamationEqualsToken:
case SyntaxKind.EqualsEqualsEqualsToken:
case SyntaxKind.ExclamationEqualsEqualsToken:
return isNarrowingNullCheckOperands(expr.right, expr.left) || isNarrowingNullCheckOperands(expr.left, expr.right) ||
isNarrowingTypeofOperands(expr.right, expr.left) || isNarrowingTypeofOperands(expr.left, expr.right) ||
isNarrowingDiscriminant(expr.left) || isNarrowingDiscriminant(expr.right);
return isNarrowableOperand(expr.left) || isNarrowableOperand(expr.right) ||
isNarrowingTypeofOperands(expr.right, expr.left) || isNarrowingTypeofOperands(expr.left, expr.right);
case SyntaxKind.InstanceOfKeyword:
return isNarrowableOperand(expr.left);
case SyntaxKind.CommaToken:
@ -664,11 +665,6 @@ namespace ts {
return isNarrowableReference(expr);
}
function isNarrowingSwitchStatement(switchStatement: SwitchStatement) {
const expr = switchStatement.expression;
return expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((<PropertyAccessExpression>expr).expression);
}
function createBranchLabel(): FlowLabel {
return {
flags: FlowFlags.BranchLabel,
@ -718,7 +714,7 @@ namespace ts {
}
function createFlowSwitchClause(antecedent: FlowNode, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): FlowNode {
if (!isNarrowingSwitchStatement(switchStatement)) {
if (!isNarrowingExpression(switchStatement.expression)) {
return antecedent;
}
setFlowNodeReferenced(antecedent);
@ -1413,7 +1409,8 @@ namespace ts {
const typeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, "__type");
addDeclarationToSymbol(typeLiteralSymbol, node, SymbolFlags.TypeLiteral);
typeLiteralSymbol.members = { [symbol.name]: symbol };
typeLiteralSymbol.members = createMap<Symbol>();
typeLiteralSymbol.members[symbol.name] = symbol;
}
function bindObjectLiteralExpression(node: ObjectLiteralExpression) {
@ -1423,7 +1420,7 @@ namespace ts {
}
if (inStrictMode) {
const seen: Map<ElementKind> = {};
const seen = createMap<ElementKind>();
for (const prop of node.properties) {
if (prop.name.kind !== SyntaxKind.Identifier) {
@ -1479,7 +1476,7 @@ namespace ts {
// fall through.
default:
if (!blockScopeContainer.locals) {
blockScopeContainer.locals = {};
blockScopeContainer.locals = createMap<Symbol>();
addToContainerChain(blockScopeContainer);
}
declareSymbol(blockScopeContainer.locals, undefined, node, symbolFlags, symbolExcludes);
@ -1901,18 +1898,17 @@ namespace ts {
}
function bindExportAssignment(node: ExportAssignment | BinaryExpression) {
const boundExpression = node.kind === SyntaxKind.ExportAssignment ? (<ExportAssignment>node).expression : (<BinaryExpression>node).right;
if (!container.symbol || !container.symbol.exports) {
// Export assignment in some sort of block construct
bindAnonymousDeclaration(node, SymbolFlags.Alias, getDeclarationName(node));
}
else if (boundExpression.kind === SyntaxKind.Identifier && node.kind === SyntaxKind.ExportAssignment) {
// An export default clause with an identifier exports all meanings of that identifier
declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Alias, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes);
}
else {
// An export default clause with an expression exports a value
declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes);
const flags = node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(<ExportAssignment>node)
// An export default clause with an EntityNameExpression exports all meanings of that identifier
? SymbolFlags.Alias
// An export default clause with any other expression exports a value
: SymbolFlags.Property;
declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes);
}
}
@ -1939,7 +1935,7 @@ namespace ts {
}
}
file.symbol.globalExports = file.symbol.globalExports || {};
file.symbol.globalExports = file.symbol.globalExports || createMap<Symbol>();
declareSymbol(file.symbol.globalExports, file.symbol, node, SymbolFlags.Alias, SymbolFlags.AliasExcludes);
}
@ -1981,20 +1977,25 @@ namespace ts {
}
function bindThisPropertyAssignment(node: BinaryExpression) {
// Declare a 'member' in case it turns out the container was an ES5 class or ES6 constructor
let assignee: Node;
if (container.kind === SyntaxKind.FunctionDeclaration || container.kind === SyntaxKind.FunctionDeclaration) {
assignee = container;
Debug.assert(isInJavaScriptFile(node));
// Declare a 'member' if the container is an ES5 class or ES6 constructor
if (container.kind === SyntaxKind.FunctionDeclaration || container.kind === SyntaxKind.FunctionExpression) {
container.symbol.members = container.symbol.members || createMap<Symbol>();
// It's acceptable for multiple 'this' assignments of the same identifier to occur
declareSymbol(container.symbol.members, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property);
}
else if (container.kind === SyntaxKind.Constructor) {
assignee = container.parent;
// this.foo assignment in a JavaScript class
// Bind this property to the containing class
const saveContainer = container;
container = container.parent;
const symbol = bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property, SymbolFlags.None);
if (symbol) {
// constructor-declared symbols can be overwritten by subsequent method declarations
(symbol as Symbol).isReplaceableByMethod = true;
}
container = saveContainer;
}
else {
return;
}
assignee.symbol.members = assignee.symbol.members || {};
// It's acceptable for multiple 'this' assignments of the same identifier to occur
declareSymbol(assignee.symbol.members, assignee.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property);
}
function bindPrototypePropertyAssignment(node: BinaryExpression) {
@ -2018,7 +2019,7 @@ namespace ts {
// Set up the members collection if it doesn't exist already
if (!funcSymbol.members) {
funcSymbol.members = {};
funcSymbol.members = createMap<Symbol>();
}
// Declare the method/property
@ -2067,7 +2068,7 @@ namespace ts {
// 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");
if (hasProperty(symbol.exports, prototypeSymbol.name)) {
if (symbol.exports[prototypeSymbol.name]) {
if (node.name) {
node.name.parent = node;
}

File diff suppressed because it is too large Load Diff

View File

@ -61,10 +61,10 @@ namespace ts {
},
{
name: "jsx",
type: {
type: createMap({
"preserve": JsxEmit.Preserve,
"react": JsxEmit.React
},
}),
paramType: Diagnostics.KIND,
description: Diagnostics.Specify_JSX_code_generation_Colon_preserve_or_react,
},
@ -91,7 +91,7 @@ namespace ts {
{
name: "module",
shortName: "m",
type: {
type: createMap({
"none": ModuleKind.None,
"commonjs": ModuleKind.CommonJS,
"amd": ModuleKind.AMD,
@ -99,16 +99,16 @@ namespace ts {
"umd": ModuleKind.UMD,
"es6": ModuleKind.ES6,
"es2015": ModuleKind.ES2015,
},
}),
description: Diagnostics.Specify_module_code_generation_Colon_commonjs_amd_system_umd_or_es2015,
paramType: Diagnostics.KIND,
},
{
name: "newLine",
type: {
type: createMap({
"crlf": NewLineKind.CarriageReturnLineFeed,
"lf": NewLineKind.LineFeed
},
}),
description: Diagnostics.Specify_the_end_of_line_sequence_to_be_used_when_emitting_files_Colon_CRLF_dos_or_LF_unix,
paramType: Diagnostics.NEWLINE,
},
@ -126,6 +126,10 @@ namespace ts {
type: "boolean",
description: Diagnostics.Do_not_emit_outputs_if_any_errors_were_reported,
},
{
name: "noErrorTruncation",
type: "boolean"
},
{
name: "noImplicitAny",
type: "boolean",
@ -139,12 +143,12 @@ namespace ts {
{
name: "noUnusedLocals",
type: "boolean",
description: Diagnostics.Report_errors_on_unused_locals,
description: Diagnostics.Report_errors_on_unused_locals,
},
{
name: "noUnusedParameters",
type: "boolean",
description: Diagnostics.Report_errors_on_unused_parameters,
description: Diagnostics.Report_errors_on_unused_parameters,
},
{
name: "noLib",
@ -250,12 +254,12 @@ namespace ts {
{
name: "target",
shortName: "t",
type: {
type: createMap({
"es3": ScriptTarget.ES3,
"es5": ScriptTarget.ES5,
"es6": ScriptTarget.ES6,
"es2015": ScriptTarget.ES2015,
},
}),
description: Diagnostics.Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES2015,
paramType: Diagnostics.VERSION,
},
@ -284,10 +288,10 @@ namespace ts {
},
{
name: "moduleResolution",
type: {
type: createMap({
"node": ModuleResolutionKind.NodeJs,
"classic": ModuleResolutionKind.Classic,
},
}),
description: Diagnostics.Specify_module_resolution_strategy_Colon_node_Node_js_or_classic_TypeScript_pre_1_6,
},
{
@ -392,7 +396,7 @@ namespace ts {
type: "list",
element: {
name: "lib",
type: {
type: createMap({
// JavaScript only
"es5": "lib.es5.d.ts",
"es6": "lib.es2015.d.ts",
@ -417,7 +421,7 @@ namespace ts {
"es2016.array.include": "lib.es2016.array.include.d.ts",
"es2017.object": "lib.es2017.object.d.ts",
"es2017.sharedmemory": "lib.es2017.sharedmemory.d.ts"
},
}),
},
description: Diagnostics.Specify_library_files_to_be_included_in_the_compilation_Colon
},
@ -462,6 +466,14 @@ namespace ts {
shortOptionNames: Map<string>;
}
/* @internal */
export const defaultInitCompilerOptions: CompilerOptions = {
module: ModuleKind.CommonJS,
target: ScriptTarget.ES5,
noImplicitAny: false,
sourceMap: false,
};
let optionNameMapCache: OptionNameMap;
/* @internal */
@ -470,8 +482,8 @@ namespace ts {
return optionNameMapCache;
}
const optionNameMap: Map<CommandLineOption> = {};
const shortOptionNames: Map<string> = {};
const optionNameMap = createMap<CommandLineOption>();
const shortOptionNames = createMap<string>();
forEach(optionDeclarations, option => {
optionNameMap[option.name.toLowerCase()] = option;
if (option.shortName) {
@ -486,10 +498,9 @@ namespace ts {
/* @internal */
export function createCompilerDiagnosticForInvalidCustomType(opt: CommandLineOptionOfCustomType): Diagnostic {
const namesOfType: string[] = [];
forEachKey(opt.type, key => {
for (const key in opt.type) {
namesOfType.push(` '${key}'`);
});
}
return createCompilerDiagnostic(Diagnostics.Argument_for_0_option_must_be_Colon_1, `--${opt.name}`, namesOfType);
}
@ -497,7 +508,7 @@ namespace ts {
export function parseCustomTypeOption(opt: CommandLineOptionOfCustomType, value: string, errors: Diagnostic[]) {
const key = trimString((value || "")).toLowerCase();
const map = opt.type;
if (hasProperty(map, key)) {
if (key in map) {
return map[key];
}
else {
@ -551,11 +562,11 @@ namespace ts {
s = s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1).toLowerCase();
// Try to translate short option names to their full equivalents.
if (hasProperty(shortOptionNames, s)) {
if (s in shortOptionNames) {
s = shortOptionNames[s];
}
if (hasProperty(optionNameMap, s)) {
if (s in optionNameMap) {
const opt = optionNameMap[s];
if (opt.isTSConfigOnly) {
@ -668,6 +679,94 @@ namespace ts {
}
}
/**
* Generate tsconfig configuration when running command line "--init"
* @param options commandlineOptions to be generated into tsconfig.json
* @param fileNames array of filenames to be generated into tsconfig.json
*/
/* @internal */
export function generateTSConfig(options: CompilerOptions, fileNames: string[]): { compilerOptions: Map<CompilerOptionsValue> } {
const compilerOptions = extend(options, defaultInitCompilerOptions);
const configurations: any = {
compilerOptions: serializeCompilerOptions(compilerOptions)
};
if (fileNames && fileNames.length) {
// only set the files property if we have at least one file
configurations.files = fileNames;
}
return configurations;
function getCustomTypeMapOfCommandLineOption(optionDefinition: CommandLineOption): Map<string | number> | undefined {
if (optionDefinition.type === "string" || optionDefinition.type === "number" || optionDefinition.type === "boolean") {
// this is of a type CommandLineOptionOfPrimitiveType
return undefined;
}
else if (optionDefinition.type === "list") {
return getCustomTypeMapOfCommandLineOption((<CommandLineOptionOfListType>optionDefinition).element);
}
else {
return (<CommandLineOptionOfCustomType>optionDefinition).type;
}
}
function getNameOfCompilerOptionValue(value: CompilerOptionsValue, customTypeMap: MapLike<string | number>): string | undefined {
// There is a typeMap associated with this command-line option so use it to map value back to its name
for (const key in customTypeMap) {
if (customTypeMap[key] === value) {
return key;
}
}
return undefined;
}
function serializeCompilerOptions(options: CompilerOptions): Map<CompilerOptionsValue> {
const result = createMap<CompilerOptionsValue>();
const optionsNameMap = getOptionNameMap().optionNameMap;
for (const name in options) {
if (hasProperty(options, name)) {
// tsconfig only options cannot be specified via command line,
// so we can assume that only types that can appear here string | number | boolean
switch (name) {
case "init":
case "watch":
case "version":
case "help":
case "project":
break;
default:
const value = options[name];
let optionDefinition = optionsNameMap[name.toLowerCase()];
if (optionDefinition) {
const customTypeMap = getCustomTypeMapOfCommandLineOption(optionDefinition);
if (!customTypeMap) {
// There is no map associated with this compiler option then use the value as-is
// This is the case if the value is expect to be string, number, boolean or list of string
result[name] = value;
}
else {
if (optionDefinition.type === "list") {
const convertedValue: string[] = [];
for (const element of value as (string | number)[]) {
convertedValue.push(getNameOfCompilerOptionValue(element, customTypeMap));
}
result[name] = convertedValue;
}
else {
// There is a typeMap associated with this command-line option so use it to map value back to its name
result[name] = getNameOfCompilerOptionValue(value, customTypeMap);
}
}
}
break;
}
}
}
return result;
}
}
/**
* Remove the comments from a json like text.
* Comments can be single line comments (starting with # or //) or multiline comments using / * * /
@ -693,9 +792,6 @@ namespace ts {
return output;
}
// Skip over any minified JavaScript files (ending in ".min.js")
// Skip over dotted files and folders as well
const ignoreFileNamePattern = /(\.min\.js$)|([\\/]\.[\w.])/;
/**
* Parse the contents of a config file (tsconfig.json).
* @param json The contents of the config file to parse
@ -814,7 +910,7 @@ namespace ts {
const optionNameMap = arrayToMap(optionDeclarations, opt => opt.name);
for (const id in jsonOptions) {
if (hasProperty(optionNameMap, id)) {
if (id in optionNameMap) {
const opt = optionNameMap[id];
defaultOptions[opt.name] = convertJsonOption(opt, jsonOptions[id], basePath, errors);
}
@ -851,7 +947,7 @@ namespace ts {
function convertJsonOptionOfCustomType(opt: CommandLineOptionOfCustomType, value: string, errors: Diagnostic[]) {
const key = value.toLowerCase();
if (hasProperty(opt.type, key)) {
if (key in opt.type) {
return opt.type[key];
}
else {
@ -961,12 +1057,12 @@ namespace ts {
// Literal file names (provided via the "files" array in tsconfig.json) are stored in a
// file map with a possibly case insensitive key. We use this map later when when including
// wildcard paths.
const literalFileMap: Map<string> = {};
const literalFileMap = createMap<string>();
// Wildcard paths (provided via the "includes" array in tsconfig.json) are stored in a
// file map with a possibly case insensitive key. We use this map to store paths matched
// via wildcard, and to handle extension priority.
const wildcardFileMap: Map<string> = {};
const wildcardFileMap = createMap<string>();
if (include) {
include = validateSpecs(include, errors, /*allowTrailingRecursion*/ false);
@ -1007,10 +1103,6 @@ namespace ts {
continue;
}
if (ignoreFileNamePattern.test(file)) {
continue;
}
// We may have included a wildcard path with a lower priority
// extension due to the user-defined order of entries in the
// "include" array. If there is a lower priority extension in the
@ -1018,7 +1110,7 @@ namespace ts {
removeWildcardFilesWithLowerPriorityExtension(file, wildcardFileMap, supportedExtensions, keyMapper);
const key = keyMapper(file);
if (!hasProperty(literalFileMap, key) && !hasProperty(wildcardFileMap, key)) {
if (!(key in literalFileMap) && !(key in wildcardFileMap)) {
wildcardFileMap[key] = file;
}
}
@ -1070,7 +1162,7 @@ namespace ts {
// /a/b/a?z - Watch /a/b directly to catch any new file matching a?z
const rawExcludeRegex = getRegularExpressionForWildcard(exclude, path, "exclude");
const excludeRegex = rawExcludeRegex && new RegExp(rawExcludeRegex, useCaseSensitiveFileNames ? "" : "i");
const wildcardDirectories: Map<WatchDirectoryFlags> = {};
const wildcardDirectories = createMap<WatchDirectoryFlags>();
if (include !== undefined) {
const recursiveKeys: string[] = [];
for (const file of include) {
@ -1083,7 +1175,7 @@ namespace ts {
if (match) {
const key = useCaseSensitiveFileNames ? match[0] : match[0].toLowerCase();
const flags = watchRecursivePattern.test(name) ? WatchDirectoryFlags.Recursive : WatchDirectoryFlags.None;
const existingFlags = getProperty(wildcardDirectories, key);
const existingFlags = wildcardDirectories[key];
if (existingFlags === undefined || existingFlags < flags) {
wildcardDirectories[key] = flags;
if (flags === WatchDirectoryFlags.Recursive) {
@ -1095,11 +1187,9 @@ namespace ts {
// Remove any subpaths under an existing recursively watched directory.
for (const key in wildcardDirectories) {
if (hasProperty(wildcardDirectories, key)) {
for (const recursiveKey of recursiveKeys) {
if (key !== recursiveKey && containsPath(recursiveKey, key, path, !useCaseSensitiveFileNames)) {
delete wildcardDirectories[key];
}
for (const recursiveKey of recursiveKeys) {
if (key !== recursiveKey && containsPath(recursiveKey, key, path, !useCaseSensitiveFileNames)) {
delete wildcardDirectories[key];
}
}
}
@ -1122,7 +1212,7 @@ namespace ts {
for (let i = ExtensionPriority.Highest; i < adjustedExtensionPriority; i++) {
const higherPriorityExtension = extensions[i];
const higherPriorityPath = keyMapper(changeExtension(file, higherPriorityExtension));
if (hasProperty(literalFiles, higherPriorityPath) || hasProperty(wildcardFiles, higherPriorityPath)) {
if (higherPriorityPath in literalFiles || higherPriorityPath in wildcardFiles) {
return true;
}
}

View File

@ -19,8 +19,28 @@ namespace ts {
True = -1
}
const createObject = Object.create;
export function createMap<T>(template?: MapLike<T>): Map<T> {
const map: Map<T> = createObject(null); // tslint:disable-line:no-null-keyword
// Using 'delete' on an object causes V8 to put the object in dictionary mode.
// This disables creation of hidden classes, which are expensive when an object is
// constantly changing shape.
map["__"] = undefined;
delete map["__"];
// Copies keys/values from template. Note that for..in will not throw if
// template is undefined, and instead will just exit the loop.
for (const key in template) if (hasOwnProperty.call(template, key)) {
map[key] = template[key];
}
return map;
}
export function createFileMap<T>(keyMapper?: (key: string) => string): FileMap<T> {
let files: Map<T> = {};
let files = createMap<T>();
return {
get,
set,
@ -46,7 +66,7 @@ namespace ts {
}
function contains(path: Path) {
return hasProperty(files, toKey(path));
return toKey(path) in files;
}
function remove(path: Path) {
@ -55,7 +75,7 @@ namespace ts {
}
function clear() {
files = {};
files = createMap<T>();
}
function toKey(path: Path): string {
@ -81,7 +101,7 @@ namespace ts {
* returns a truthy value, then returns that value.
* If no such value is found, the callback is applied to each element of array and undefined is returned.
*/
export function forEach<T, U>(array: T[], callback: (element: T, index: number) => U): U {
export function forEach<T, U>(array: T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined {
if (array) {
for (let i = 0, len = array.length; i < len; i++) {
const result = callback(array[i], i);
@ -93,10 +113,21 @@ namespace ts {
return undefined;
}
export function contains<T>(array: T[], value: T, areEqual?: (a: T, b: T) => boolean): boolean {
/** Like `forEach`, but assumes existence of array and fails if no truthy value is found. */
export function find<T, U>(array: T[], callback: (element: T, index: number) => U | undefined): U {
for (let i = 0, len = array.length; i < len; i++) {
const result = callback(array[i], i);
if (result) {
return result;
}
}
Debug.fail();
}
export function contains<T>(array: T[], value: T): boolean {
if (array) {
for (const v of array) {
if (areEqual ? areEqual(v, value) : v === value) {
if (v === value) {
return true;
}
}
@ -136,17 +167,44 @@ namespace ts {
return count;
}
/**
* Filters an array by a predicate function. Returns the same array instance if the predicate is
* true for all elements, otherwise returns a new array instance containing the filtered subset.
*/
export function filter<T>(array: T[], f: (x: T) => boolean): T[] {
let result: T[];
if (array) {
result = [];
for (const item of array) {
if (f(item)) {
result.push(item);
const len = array.length;
let i = 0;
while (i < len && f(array[i])) i++;
if (i < len) {
const result = array.slice(0, i);
i++;
while (i < len) {
const item = array[i];
if (f(item)) {
result.push(item);
}
i++;
}
return result;
}
}
return result;
return array;
}
export function removeWhere<T>(array: T[], f: (x: T) => boolean): boolean {
let outIndex = 0;
for (const item of array) {
if (!f(item)) {
array[outIndex] = item;
outIndex++;
}
}
if (outIndex !== array.length) {
array.length = outIndex;
return true;
}
return false;
}
export function filterMutate<T>(array: T[], f: (x: T) => boolean): void {
@ -182,10 +240,13 @@ namespace ts {
let result: T[];
if (array) {
result = [];
for (const item of array) {
if (!contains(result, item, areEqual)) {
result.push(item);
loop: for (const item of array) {
for (const res of result) {
if (areEqual ? areEqual(res, item) : res === item) {
continue loop;
}
}
result.push(item);
}
}
return result;
@ -308,78 +369,142 @@ namespace ts {
const hasOwnProperty = Object.prototype.hasOwnProperty;
export function hasProperty<T>(map: Map<T>, key: string): boolean {
/**
* Indicates whether a map-like contains an own property with the specified key.
*
* NOTE: This is intended for use only with MapLike<T> objects. For Map<T> objects, use
* the 'in' operator.
*
* @param map A map-like.
* @param key A property key.
*/
export function hasProperty<T>(map: MapLike<T>, key: string): boolean {
return hasOwnProperty.call(map, key);
}
export function getKeys<T>(map: Map<T>): string[] {
/**
* Gets the value of an owned property in a map-like.
*
* NOTE: This is intended for use only with MapLike<T> objects. For Map<T> objects, use
* an indexer.
*
* @param map A map-like.
* @param key A property key.
*/
export function getProperty<T>(map: MapLike<T>, key: string): T | undefined {
return hasOwnProperty.call(map, key) ? map[key] : undefined;
}
/**
* Gets the owned, enumerable property keys of a map-like.
*
* NOTE: This is intended for use with MapLike<T> objects. For Map<T> objects, use
* Object.keys instead as it offers better performance.
*
* @param map A map-like.
*/
export function getOwnKeys<T>(map: MapLike<T>): string[] {
const keys: string[] = [];
for (const key in map) {
for (const key in map) if (hasOwnProperty.call(map, key)) {
keys.push(key);
}
return keys;
}
export function getProperty<T>(map: Map<T>, key: string): T {
return hasOwnProperty.call(map, key) ? map[key] : undefined;
/**
* Enumerates the properties of a Map<T>, invoking a callback and returning the first truthy result.
*
* @param map A map for which properties should be enumerated.
* @param callback A callback to invoke for each property.
*/
export function forEachProperty<T, U>(map: Map<T>, callback: (value: T, key: string) => U): U {
let result: U;
for (const key in map) {
if (result = callback(map[key], key)) break;
}
return result;
}
export function isEmpty<T>(map: Map<T>) {
for (const id in map) {
if (hasProperty(map, id)) {
return false;
}
/**
* Returns true if a Map<T> has some matching property.
*
* @param map A map whose properties should be tested.
* @param predicate An optional callback used to test each property.
*/
export function someProperties<T>(map: Map<T>, predicate?: (value: T, key: string) => boolean) {
for (const key in map) {
if (!predicate || predicate(map[key], key)) return true;
}
return false;
}
/**
* Performs a shallow copy of the properties from a source Map<T> to a target MapLike<T>
*
* @param source A map from which properties should be copied.
* @param target A map to which properties should be copied.
*/
export function copyProperties<T>(source: Map<T>, target: MapLike<T>): void {
for (const key in source) {
target[key] = source[key];
}
}
/**
* Reduce the properties of a map.
*
* NOTE: This is intended for use with Map<T> objects. For MapLike<T> objects, use
* reduceOwnProperties instead as it offers better runtime safety.
*
* @param map The map to reduce
* @param callback An aggregation function that is called for each entry in the map
* @param initial The initial value for the reduction.
*/
export function reduceProperties<T, U>(map: Map<T>, callback: (aggregate: U, value: T, key: string) => U, initial: U): U {
let result = initial;
for (const key in map) {
result = callback(result, map[key], String(key));
}
return result;
}
/**
* Reduce the properties defined on a map-like (but not from its prototype chain).
*
* NOTE: This is intended for use with MapLike<T> objects. For Map<T> objects, use
* reduceProperties instead as it offers better performance.
*
* @param map The map-like to reduce
* @param callback An aggregation function that is called for each entry in the map
* @param initial The initial value for the reduction.
*/
export function reduceOwnProperties<T, U>(map: MapLike<T>, callback: (aggregate: U, value: T, key: string) => U, initial: U): U {
let result = initial;
for (const key in map) if (hasOwnProperty.call(map, key)) {
result = callback(result, map[key], String(key));
}
return result;
}
/**
* Performs a shallow equality comparison of the contents of two map-likes.
*
* @param left A map-like whose properties should be compared.
* @param right A map-like whose properties should be compared.
*/
export function equalOwnProperties<T>(left: MapLike<T>, right: MapLike<T>, equalityComparer?: (left: T, right: T) => boolean) {
if (left === right) return true;
if (!left || !right) return false;
for (const key in left) if (hasOwnProperty.call(left, key)) {
if (!hasOwnProperty.call(right, key) === undefined) return false;
if (equalityComparer ? !equalityComparer(left[key], right[key]) : left[key] !== right[key]) return false;
}
for (const key in right) if (hasOwnProperty.call(right, key)) {
if (!hasOwnProperty.call(left, key)) return false;
}
return true;
}
export function clone<T>(object: T): T {
const result: any = {};
for (const id in object) {
result[id] = (<any>object)[id];
}
return <T>result;
}
export function extend<T1 extends Map<{}>, T2 extends Map<{}>>(first: T1 , second: T2): T1 & T2 {
const result: T1 & T2 = <any>{};
for (const id in first) {
(result as any)[id] = first[id];
}
for (const id in second) {
if (!hasProperty(result, id)) {
(result as any)[id] = second[id];
}
}
return result;
}
export function forEachValue<T, U>(map: Map<T>, callback: (value: T) => U): U {
let result: U;
for (const id in map) {
if (result = callback(map[id])) break;
}
return result;
}
export function forEachKey<T, U>(map: Map<T>, callback: (key: string) => U): U {
let result: U;
for (const id in map) {
if (result = callback(id)) break;
}
return result;
}
export function lookUp<T>(map: Map<T>, key: string): T {
return hasProperty(map, key) ? map[key] : undefined;
}
export function copyMap<T>(source: Map<T>, target: Map<T>): void {
for (const p in source) {
target[p] = source[p];
}
}
/**
* Creates a map from the elements of an array.
*
@ -390,33 +515,40 @@ namespace ts {
* the same key with the given 'makeKey' function, then the element with the higher
* index in the array will be the one associated with the produced key.
*/
export function arrayToMap<T>(array: T[], makeKey: (value: T) => string): Map<T> {
const result: Map<T> = {};
forEach(array, value => {
result[makeKey(value)] = value;
});
export function arrayToMap<T>(array: T[], makeKey: (value: T) => string): Map<T>;
export function arrayToMap<T, U>(array: T[], makeKey: (value: T) => string, makeValue: (value: T) => U): Map<U>;
export function arrayToMap<T, U>(array: T[], makeKey: (value: T) => string, makeValue?: (value: T) => U): Map<T | U> {
const result = createMap<T | U>();
for (const value of array) {
result[makeKey(value)] = makeValue ? makeValue(value) : value;
}
return result;
}
/**
* Reduce the properties of a map.
*
* @param map The map to reduce
* @param callback An aggregation function that is called for each entry in the map
* @param initial The initial value for the reduction.
*/
export function reduceProperties<T, U>(map: Map<T>, callback: (aggregate: U, value: T, key: string) => U, initial: U): U {
let result = initial;
if (map) {
for (const key in map) {
if (hasProperty(map, key)) {
result = callback(result, map[key], String(key));
}
export function cloneMap<T>(map: Map<T>) {
const clone = createMap<T>();
copyProperties(map, clone);
return clone;
}
export function clone<T>(object: T): T {
const result: any = {};
for (const id in object) {
if (hasOwnProperty.call(object, id)) {
result[id] = (<any>object)[id];
}
}
return result;
}
export function extend<T1, T2>(first: T1 , second: T2): T1 & T2 {
const result: T1 & T2 = <any>{};
for (const id in second) if (hasOwnProperty.call(second, id)) {
(result as any)[id] = (second as any)[id];
}
for (const id in first) if (hasOwnProperty.call(first, id)) {
(result as any)[id] = (first as any)[id];
}
return result;
}
@ -447,9 +579,7 @@ namespace ts {
export let localizedDiagnosticMessages: Map<string> = undefined;
export function getLocaleSpecificMessage(message: DiagnosticMessage) {
return localizedDiagnosticMessages && localizedDiagnosticMessages[message.key]
? localizedDiagnosticMessages[message.key]
: message.message;
return localizedDiagnosticMessages && localizedDiagnosticMessages[message.key] || message.message;
}
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage, ...args: any[]): Diagnostic;
@ -932,11 +1062,29 @@ namespace ts {
const reservedCharacterPattern = /[^\w\s\/]/g;
const wildcardCharCodes = [CharacterCodes.asterisk, CharacterCodes.question];
/**
* Matches any single directory segment unless it is the last segment and a .min.js file
* Breakdown:
* [^./] # matches everything up to the first . character (excluding directory seperators)
* (\\.(?!min\\.js$))? # matches . characters but not if they are part of the .min.js file extension
*/
const singleAsteriskRegexFragmentFiles = "([^./]|(\\.(?!min\\.js$))?)*";
const singleAsteriskRegexFragmentOther = "[^/]*";
export function getRegularExpressionForWildcard(specs: string[], basePath: string, usage: "files" | "directories" | "exclude") {
if (specs === undefined || specs.length === 0) {
return undefined;
}
const replaceWildcardCharacter = usage === "files" ? replaceWildCardCharacterFiles : replaceWildCardCharacterOther;
const singleAsteriskRegexFragment = usage === "files" ? singleAsteriskRegexFragmentFiles : singleAsteriskRegexFragmentOther;
/**
* Regex for the ** wildcard. Matches any number of subdirectories. When used for including
* files or directories, does not match subdirectories that start with a . character
*/
const doubleAsteriskRegexFragment = usage === "exclude" ? "(/.+?)?" : "(/[^/.][^/]*)*?";
let pattern = "";
let hasWrittenSubpattern = false;
spec: for (const spec of specs) {
@ -957,13 +1105,13 @@ namespace ts {
components[0] = removeTrailingDirectorySeparator(components[0]);
let optionalCount = 0;
for (const component of components) {
for (let component of components) {
if (component === "**") {
if (hasRecursiveDirectoryWildcard) {
continue spec;
}
subpattern += "(/.+?)?";
subpattern += doubleAsteriskRegexFragment;
hasRecursiveDirectoryWildcard = true;
hasWrittenComponent = true;
}
@ -977,6 +1125,20 @@ namespace ts {
subpattern += directorySeparator;
}
if (usage !== "exclude") {
// The * and ? wildcards should not match directories or files that start with . if they
// appear first in a component. Dotted directories and files can be included explicitly
// like so: **/.*/.*
if (component.charCodeAt(0) === CharacterCodes.asterisk) {
subpattern += "([^./]" + singleAsteriskRegexFragment + ")?";
component = component.substr(1);
}
else if (component.charCodeAt(0) === CharacterCodes.question) {
subpattern += "[^./]";
component = component.substr(1);
}
}
subpattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter);
hasWrittenComponent = true;
}
@ -1002,8 +1164,16 @@ namespace ts {
return "^(" + pattern + (usage === "exclude" ? ")($|/)" : ")$");
}
function replaceWildcardCharacter(match: string) {
return match === "*" ? "[^/]*" : match === "?" ? "[^/]" : "\\" + match;
function replaceWildCardCharacterFiles(match: string) {
return replaceWildcardCharacter(match, singleAsteriskRegexFragmentFiles);
}
function replaceWildCardCharacterOther(match: string) {
return replaceWildcardCharacter(match, singleAsteriskRegexFragmentOther);
}
function replaceWildcardCharacter(match: string, singleAsteriskRegexFragment: string) {
return match === "*" ? singleAsteriskRegexFragment : match === "?" ? "[^/]" : "\\" + match;
}
export interface FileSystemEntries {

View File

@ -157,9 +157,7 @@ namespace ts {
if (usedTypeDirectiveReferences) {
for (const directive in usedTypeDirectiveReferences) {
if (hasProperty(usedTypeDirectiveReferences, directive)) {
referencesOutput += `/// <reference types="${directive}" />${newLine}`;
}
referencesOutput += `/// <reference types="${directive}" />${newLine}`;
}
}
@ -269,10 +267,10 @@ namespace ts {
}
if (!usedTypeDirectiveReferences) {
usedTypeDirectiveReferences = {};
usedTypeDirectiveReferences = createMap<string>();
}
for (const directive of typeReferenceDirectives) {
if (!hasProperty(usedTypeDirectiveReferences, directive)) {
if (!(directive in usedTypeDirectiveReferences)) {
usedTypeDirectiveReferences[directive] = directive;
}
}
@ -397,7 +395,7 @@ namespace ts {
case SyntaxKind.NullKeyword:
case SyntaxKind.NeverKeyword:
case SyntaxKind.ThisType:
case SyntaxKind.StringLiteralType:
case SyntaxKind.LiteralType:
return writeTextOfNode(currentText, type);
case SyntaxKind.ExpressionWithTypeArguments:
return emitExpressionWithTypeArguments(<ExpressionWithTypeArguments>type);
@ -441,7 +439,7 @@ namespace ts {
}
}
function emitEntityName(entityName: EntityName | PropertyAccessExpression) {
function emitEntityName(entityName: EntityNameOrEntityNameExpression) {
const visibilityResult = resolver.isEntityNameVisible(entityName,
// Aliases can be written asynchronously so use correct enclosing declaration
entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration ? entityName.parent : enclosingDeclaration);
@ -452,9 +450,9 @@ namespace ts {
}
function emitExpressionWithTypeArguments(node: ExpressionWithTypeArguments) {
if (isSupportedExpressionWithTypeArguments(node)) {
if (isEntityNameExpression(node.expression)) {
Debug.assert(node.expression.kind === SyntaxKind.Identifier || node.expression.kind === SyntaxKind.PropertyAccessExpression);
emitEntityName(<Identifier | PropertyAccessExpression>node.expression);
emitEntityName(node.expression);
if (node.typeArguments) {
write("<");
emitCommaList(node.typeArguments, emitType);
@ -537,14 +535,14 @@ namespace ts {
// do not need to keep track of created temp names.
function getExportDefaultTempVariableName(): string {
const baseName = "_default";
if (!hasProperty(currentIdentifiers, baseName)) {
if (!(baseName in currentIdentifiers)) {
return baseName;
}
let count = 0;
while (true) {
count++;
const name = baseName + "_" + count;
if (!hasProperty(currentIdentifiers, name)) {
if (!(name in currentIdentifiers)) {
return name;
}
}
@ -1019,7 +1017,7 @@ namespace ts {
}
function emitTypeOfTypeReference(node: ExpressionWithTypeArguments) {
if (isSupportedExpressionWithTypeArguments(node)) {
if (isEntityNameExpression(node.expression)) {
emitTypeWithNewGetSymbolAccessibilityDiagnostic(node, getHeritageClauseVisibilityError);
}
else if (!isImplementsList && node.expression.kind === SyntaxKind.NullKeyword) {

View File

@ -1755,6 +1755,10 @@
"category": "Error",
"code": 2534
},
"Enum type '{0}' has members with initializers that are not literals.": {
"category": "Error",
"code": 2535
},
"JSX element attributes type '{0}' may not be a union type.": {
"category": "Error",
"code": 2600
@ -1943,6 +1947,10 @@
"category": "Error",
"code": 2689
},
"A class must be declared after its base class.": {
"category": "Error",
"code": 2690
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
"code": 4000
@ -2223,7 +2231,7 @@
"category": "Error",
"code": 4082
},
"Conflicting library definitions for '{0}' found at '{1}' and '{2}'. Copy the correct file to the 'typings' folder to resolve this conflict.": {
"Conflicting definitions for '{0}' found at '{1}' and '{2}'. Consider installing a specific version of this library to resolve the conflict.": {
"category": "Message",
"code": 4090
},
@ -2336,6 +2344,10 @@
"category": "Error",
"code": 5065
},
"Substitutions for pattern '{0}' shouldn't be an empty array.": {
"category": "Error",
"code": 5066
},
"Concatenate and emit output to single file.": {
"category": "Message",
"code": 6001
@ -2800,11 +2812,11 @@
"category": "Error",
"code": 6133
},
"Report errors on unused locals.": {
"Report errors on unused locals.": {
"category": "Message",
"code": 6134
},
"Report errors on unused parameters.": {
"Report errors on unused parameters.": {
"category": "Message",
"code": 6135
},
@ -2816,6 +2828,10 @@
"category": "Message",
"code": 6137
},
"Property '{0}' is declared but never used.": {
"category": "Error",
"code": 6138
},
"Variable '{0}' implicitly has an '{1}' type.": {
"category": "Error",
"code": 7005

View File

@ -24,7 +24,7 @@ namespace ts {
Return = 1 << 3
}
const entities: Map<number> = {
const entities = createMap({
"quot": 0x0022,
"amp": 0x0026,
"apos": 0x0027,
@ -278,7 +278,7 @@ namespace ts {
"clubs": 0x2663,
"hearts": 0x2665,
"diams": 0x2666
};
});
// Flags enum to track count of temp variables and a few dedicated names
const enum TempFlags {
@ -407,7 +407,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function isUniqueLocalName(name: string, container: Node): boolean {
for (let node = container; isNodeDescendentOf(node, container); node = node.nextContainer) {
if (node.locals && hasProperty(node.locals, name)) {
if (node.locals && name in node.locals) {
// We conservatively include alias symbols to cover cases where they're emitted as locals
if (node.locals[name].flags & (SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias)) {
return false;
@ -489,13 +489,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function setLabeledJump(state: ConvertedLoopState, isBreak: boolean, labelText: string, labelMarker: string): void {
if (isBreak) {
if (!state.labeledNonLocalBreaks) {
state.labeledNonLocalBreaks = {};
state.labeledNonLocalBreaks = createMap<string>();
}
state.labeledNonLocalBreaks[labelText] = labelMarker;
}
else {
if (!state.labeledNonLocalContinues) {
state.labeledNonLocalContinues = {};
state.labeledNonLocalContinues = createMap<string>();
}
state.labeledNonLocalContinues[labelText] = labelMarker;
}
@ -577,27 +577,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
const setSourceMapWriterEmit = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? changeSourceMapEmit : function (writer: SourceMapWriter) { };
const moduleEmitDelegates: Map<(node: SourceFile, emitRelativePathAsModuleName?: boolean) => void> = {
const moduleEmitDelegates = createMap<(node: SourceFile, emitRelativePathAsModuleName?: boolean) => void>({
[ModuleKind.ES6]: emitES6Module,
[ModuleKind.AMD]: emitAMDModule,
[ModuleKind.System]: emitSystemModule,
[ModuleKind.UMD]: emitUMDModule,
[ModuleKind.CommonJS]: emitCommonJSModule,
};
});
const bundleEmitDelegates: Map<(node: SourceFile, emitRelativePathAsModuleName?: boolean) => void> = {
const bundleEmitDelegates = createMap<(node: SourceFile, emitRelativePathAsModuleName?: boolean) => void>({
[ModuleKind.ES6]() {},
[ModuleKind.AMD]: emitAMDModule,
[ModuleKind.System]: emitSystemModule,
[ModuleKind.UMD]() {},
[ModuleKind.CommonJS]() {},
};
});
return doEmit;
function doEmit(jsFilePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) {
sourceMap.initialize(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit);
generatedNameSet = {};
generatedNameSet = createMap<string>();
nodeToGeneratedName = [];
decoratedClassAliases = [];
isOwnFileEmit = !isBundledEmit;
@ -669,8 +669,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function isUniqueName(name: string): boolean {
return !resolver.hasGlobalName(name) &&
!hasProperty(currentFileIdentifiers, name) &&
!hasProperty(generatedNameSet, name);
!(name in currentFileIdentifiers) &&
!(name in generatedNameSet);
}
// Return the next available name in the pattern _a ... _z, _0, _1, ...
@ -2578,7 +2578,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
operand = (<TypeAssertion | NonNullExpression>operand).expression;
}
// We have an expression of the form: (<Type>SubExpr)
// We have an expression of the form: (<Type>SubExpr) or (SubExpr as Type)
// Emitting this as (SubExpr) is really not desirable. We would like to emit the subexpr as is.
// Omitting the parentheses, however, could cause change in the semantics of the generated
// code if the casted expression has a lower precedence than the rest of the expression, e.g.:
@ -2592,6 +2592,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
operand.kind !== SyntaxKind.DeleteExpression &&
operand.kind !== SyntaxKind.PostfixUnaryExpression &&
operand.kind !== SyntaxKind.NewExpression &&
!(operand.kind === SyntaxKind.BinaryExpression && node.expression.kind === SyntaxKind.AsExpression) &&
!(operand.kind === SyntaxKind.CallExpression && node.parent.kind === SyntaxKind.NewExpression) &&
!(operand.kind === SyntaxKind.FunctionExpression && node.parent.kind === SyntaxKind.CallExpression) &&
!(operand.kind === SyntaxKind.NumericLiteral && node.parent.kind === SyntaxKind.PropertyAccessExpression)) {
@ -2645,7 +2646,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
return false;
}
return !exportEquals && exportSpecifiers && hasProperty(exportSpecifiers, (<Identifier>node).text);
return !exportEquals && exportSpecifiers && (<Identifier>node).text in exportSpecifiers;
}
function emitPrefixUnaryExpression(node: PrefixUnaryExpression) {
@ -2667,7 +2668,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
isNameOfExportedDeclarationInNonES6Module(node.operand);
if (internalExportChanged) {
emitAliasEqual(<Identifier> node.operand);
emitAliasEqual(<Identifier>node.operand);
}
write(tokenToString(node.operator));
@ -2722,7 +2723,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
}
}
else if (internalExportChanged) {
emitAliasEqual(<Identifier> node.operand);
emitAliasEqual(<Identifier>node.operand);
emit(node.operand);
if (node.operator === SyntaxKind.PlusPlusToken) {
write(" += 1");
@ -3256,13 +3257,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
// Don't initialize seen unless we have at least one element.
// Emit a comma to separate for all but the first element.
if (!seen) {
seen = {};
seen = createMap<string>();
}
else {
write(", ");
}
if (!hasProperty(seen, id.text)) {
if (!(id.text in seen)) {
emit(id);
seen[id.text] = id.text;
}
@ -3855,7 +3856,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
if (convertedLoopState) {
if (!convertedLoopState.labels) {
convertedLoopState.labels = {};
convertedLoopState.labels = createMap<string>();
}
convertedLoopState.labels[node.label.text] = node.label.text;
}
@ -3969,7 +3970,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
return;
}
if (!exportEquals && exportSpecifiers && hasProperty(exportSpecifiers, name.text)) {
if (!exportEquals && exportSpecifiers && name.text in exportSpecifiers) {
for (const specifier of exportSpecifiers[name.text]) {
writeLine();
emitStart(specifier.name);
@ -5310,18 +5311,22 @@ const _super = (function (geti, seti) {
emitSignatureParameters(ctor);
}
else {
// Based on EcmaScript6 section 14.5.14: Runtime Semantics: ClassDefinitionEvaluation.
// If constructor is empty, then,
// If ClassHeritageopt is present, then
// Let constructor be the result of parsing the String "constructor(... args){ super (...args);}" using the syntactic grammar with the goal symbol MethodDefinition.
// The ES2015 spec specifies in 14.5.14. Runtime Semantics: ClassDefinitionEvaluation:
// If constructor is empty, then
// If ClassHeritag_eopt is present and protoParent is not null, then
// Let constructor be the result of parsing the source text
// constructor(...args) { super (...args);}
// using the syntactic grammar with the goal symbol MethodDefinition[~Yield].
// Else,
// Let constructor be the result of parsing the String "constructor( ){ }" using the syntactic grammar with the goal symbol MethodDefinition
if (baseTypeElement) {
write("(...args)");
}
else {
write("()");
}
// Let constructor be the result of parsing the source text
// constructor( ){ }
// using the syntactic grammar with the goal symbol MethodDefinition[~Yield].
//
// While we could emit the '...args' rest parameter, certain later tools in the pipeline might
// downlevel the '...args' portion less efficiently by naively copying the contents of 'arguments' to an array.
// Instead, we'll avoid using a rest parameter and spread into the super call as
// 'super(...arguments)' instead of 'super(...args)', as you can see below.
write("()");
}
}
@ -5359,7 +5364,8 @@ const _super = (function (geti, seti) {
write("_super.apply(this, arguments);");
}
else {
write("super(...args);");
// See comment above on using '...arguments' instead of '...args'.
write("super(...arguments);");
}
emitEnd(baseTypeElement);
}
@ -5526,13 +5532,17 @@ const _super = (function (geti, seti) {
// If the class has static properties, and it's a class expression, then we'll need
// to specialize the emit a bit. for a class expression of the form:
//
// class C { static a = 1; static b = 2; ... }
// (class C { static a = 1; static b = 2; ... })
//
// We'll emit:
//
// let C_1 = class C{};
// C_1.a = 1;
// C_1.b = 2; // so forth and so on
// ((C_1 = class C {
// // Normal class body
// },
// C_1.a = 1,
// C_1.b = 2,
// C_1));
// var C_1;
//
// This keeps the expression as an expression, while ensuring that the static parts
// of it have been initialized by the time it is used.
@ -5541,7 +5551,7 @@ const _super = (function (geti, seti) {
let generatedName: string;
if (isClassExpressionWithStaticProperties) {
generatedName = getGeneratedNameForNode(node.name);
generatedName = node.name ? getGeneratedNameForNode(node.name) : makeUniqueName("classExpression");
const synthesizedNode = <Identifier>createSynthesizedNode(SyntaxKind.Identifier);
synthesizedNode.text = generatedName;
recordTempDeclaration(synthesizedNode);
@ -6041,7 +6051,7 @@ const _super = (function (geti, seti) {
return;
case SyntaxKind.StringKeyword:
case SyntaxKind.StringLiteralType:
case SyntaxKind.LiteralType:
write("String");
return;
@ -6456,7 +6466,7 @@ const _super = (function (geti, seti) {
* Here we check if alternative name was provided for a given moduleName and return it if possible.
*/
function tryRenameExternalModule(moduleName: LiteralExpression): string {
if (renamedDependencies && hasProperty(renamedDependencies, moduleName.text)) {
if (renamedDependencies && moduleName.text in renamedDependencies) {
return `"${renamedDependencies[moduleName.text]}"`;
}
return undefined;
@ -6798,7 +6808,7 @@ const _super = (function (geti, seti) {
function collectExternalModuleInfo(sourceFile: SourceFile) {
externalImports = [];
exportSpecifiers = {};
exportSpecifiers = createMap<ExportSpecifier[]>();
exportEquals = undefined;
hasExportStarsToExportValues = false;
for (const node of sourceFile.statements) {
@ -6936,7 +6946,7 @@ const _super = (function (geti, seti) {
}
// local names set should only be added if we have anything exported
if (!exportedDeclarations && isEmpty(exportSpecifiers)) {
if (!exportedDeclarations && !someProperties(exportSpecifiers)) {
// no exported declarations (export var ...) or export specifiers (export {x})
// check if we have any non star export declarations.
let hasExportDeclarationWithExportClause = false;
@ -7076,7 +7086,7 @@ const _super = (function (geti, seti) {
if (hoistedVars) {
writeLine();
write("var ");
const seen: Map<string> = {};
const seen = createMap<string>();
for (let i = 0; i < hoistedVars.length; i++) {
const local = hoistedVars[i];
const name = local.kind === SyntaxKind.Identifier
@ -7086,7 +7096,7 @@ const _super = (function (geti, seti) {
if (name) {
// do not emit duplicate entries (in case of declaration merging) in the list of hoisted variables
const text = unescapeIdentifier(name.text);
if (hasProperty(seen, text)) {
if (text in seen) {
continue;
}
else {
@ -7442,7 +7452,7 @@ const _super = (function (geti, seti) {
writeModuleName(node, emitRelativePathAsModuleName);
write("[");
const groupIndices: Map<number> = {};
const groupIndices = createMap<number>();
const dependencyGroups: DependencyGroup[] = [];
for (let i = 0; i < externalImports.length; i++) {
@ -7455,7 +7465,7 @@ const _super = (function (geti, seti) {
// for deduplication purposes in key remove leading and trailing quotes so 'a' and "a" will be considered the same
const key = text.substr(1, text.length - 2);
if (hasProperty(groupIndices, key)) {
if (key in groupIndices) {
// deduplicate/group entries in dependency list by the dependency name
const groupIndex = groupIndices[key];
dependencyGroups[groupIndex].push(externalImports[i]);

File diff suppressed because it is too large Load Diff

View File

@ -2,75 +2,61 @@
namespace ts {
declare const performance: { now?(): number } | undefined;
/** Gets a timestamp with (at least) ms resolution */
export const timestamp = typeof performance !== "undefined" && performance.now ? performance.now : Date.now ? Date.now : () => +(new Date());
export const timestamp = typeof performance !== "undefined" && performance.now ? () => performance.now() : Date.now ? Date.now : () => +(new Date());
}
/*@internal*/
/** Performance measurements for the compiler. */
namespace ts.performance {
/** Performance measurements for the compiler. */
declare const onProfilerEvent: { (markName: string): void; profiler: boolean; };
let profilerEvent: (markName: string) => void;
let counters: Map<number>;
const profilerEvent = typeof onProfilerEvent === "function" && onProfilerEvent.profiler === true
? onProfilerEvent
: (markName: string) => { };
let enabled = false;
let profilerStart = 0;
let counts: Map<number>;
let marks: Map<number>;
let measures: Map<number>;
/**
* Emit a performance event if ts-profiler is connected. This is primarily used
* to generate heap snapshots.
* Marks a performance event.
*
* @param eventName A name for the event.
* @param markName The name of the mark.
*/
export function emit(eventName: string) {
if (profilerEvent) {
profilerEvent(eventName);
export function mark(markName: string) {
if (enabled) {
marks[markName] = timestamp();
counts[markName] = (counts[markName] || 0) + 1;
profilerEvent(markName);
}
}
/**
* Increments a counter with the specified name.
*
* @param counterName The name of the counter.
*/
export function increment(counterName: string) {
if (counters) {
counters[counterName] = (getProperty(counters, counterName) || 0) + 1;
}
}
/**
* Gets the value of the counter with the specified name.
*
* @param counterName The name of the counter.
*/
export function getCount(counterName: string) {
return counters && getProperty(counters, counterName) || 0;
}
/**
* Marks the start of a performance measurement.
*/
export function mark() {
return measures ? timestamp() : 0;
}
/**
* Adds a performance measurement with the specified name.
*
* @param measureName The name of the performance measurement.
* @param marker The timestamp of the starting mark.
* @param startMarkName The name of the starting mark. If not supplied, the point at which the
* profiler was enabled is used.
* @param endMarkName The name of the ending mark. If not supplied, the current timestamp is
* used.
*/
export function measure(measureName: string, marker: number) {
if (measures) {
measures[measureName] = (getProperty(measures, measureName) || 0) + (timestamp() - marker);
export function measure(measureName: string, startMarkName?: string, endMarkName?: string) {
if (enabled) {
const end = endMarkName && marks[endMarkName] || timestamp();
const start = startMarkName && marks[startMarkName] || profilerStart;
measures[measureName] = (measures[measureName] || 0) + (end - start);
}
}
/**
* Iterate over each measure, performing some action
*
* @param cb The action to perform for each measure
* Gets the number of times a marker was encountered.
*
* @param markName The name of the mark.
*/
export function forEachMeasure(cb: (measureName: string, duration: number) => void) {
return forEachKey(measures, key => cb(key, measures[key]));
export function getCount(markName: string) {
return counts && counts[markName] || 0;
}
/**
@ -79,31 +65,31 @@ namespace ts.performance {
* @param measureName The name of the measure whose durations should be accumulated.
*/
export function getDuration(measureName: string) {
return measures && getProperty(measures, measureName) || 0;
return measures && measures[measureName] || 0;
}
/**
* Iterate over each measure, performing some action
*
* @param cb The action to perform for each measure
*/
export function forEachMeasure(cb: (measureName: string, duration: number) => void) {
for (const key in measures) {
cb(key, measures[key]);
}
}
/** Enables (and resets) performance measurements for the compiler. */
export function enable() {
counters = { };
measures = {
"I/O Read": 0,
"I/O Write": 0,
"Program": 0,
"Parse": 0,
"Bind": 0,
"Check": 0,
"Emit": 0,
};
profilerEvent = typeof onProfilerEvent === "function" && onProfilerEvent.profiler === true
? onProfilerEvent
: undefined;
counts = createMap<number>();
marks = createMap<number>();
measures = createMap<number>();
enabled = true;
profilerStart = timestamp();
}
/** Disables (and clears) performance measurements for the compiler. */
/** Disables performance measurements for the compiler. */
export function disable() {
counters = undefined;
measures = undefined;
profilerEvent = undefined;
enabled = false;
}
}
}

View File

@ -119,49 +119,31 @@ namespace ts {
}
function tryReadTypesSection(packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string {
let jsonContent: { typings?: string, types?: string, main?: string };
try {
const jsonText = state.host.readFile(packageJsonPath);
jsonContent = jsonText ? <{ typings?: string, types?: string, main?: string }>JSON.parse(jsonText) : {};
}
catch (e) {
// gracefully handle if readFile fails or returns not JSON
jsonContent = {};
const jsonContent = readJson(packageJsonPath, state.host);
function tryReadFromField(fieldName: string) {
if (hasProperty(jsonContent, fieldName)) {
const typesFile = (<any>jsonContent)[fieldName];
if (typeof typesFile === "string") {
const typesFilePath = normalizePath(combinePaths(baseDirectory, typesFile));
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, typesFile, typesFilePath);
}
return typesFilePath;
}
else {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, fieldName, typeof typesFile);
}
}
}
}
let typesFile: string;
let fieldName: string;
// first try to read content of 'typings' section (backward compatibility)
if (jsonContent.typings) {
if (typeof jsonContent.typings === "string") {
fieldName = "typings";
typesFile = jsonContent.typings;
}
else {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, "typings", typeof jsonContent.typings);
}
}
}
// then read 'types'
if (!typesFile && jsonContent.types) {
if (typeof jsonContent.types === "string") {
fieldName = "types";
typesFile = jsonContent.types;
}
else {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, "types", typeof jsonContent.types);
}
}
}
if (typesFile) {
const typesFilePath = normalizePath(combinePaths(baseDirectory, typesFile));
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, typesFile, typesFilePath);
}
const typesFilePath = tryReadFromField("typings") || tryReadFromField("types");
if (typesFilePath) {
return typesFilePath;
}
// Use the main module for inferring types if no types package specified and the allowJs is set
if (state.compilerOptions.allowJs && jsonContent.main && typeof jsonContent.main === "string") {
if (state.traceEnabled) {
@ -173,6 +155,17 @@ namespace ts {
return undefined;
}
function readJson(path: string, host: ModuleResolutionHost): { typings?: string, types?: string, main?: string } {
try {
const jsonText = host.readFile(path);
return jsonText ? JSON.parse(jsonText) : {};
}
catch (e) {
// gracefully handle if readFile fails or returns not JSON
return {};
}
}
const typeReferenceExtensions = [".d.ts"];
function getEffectiveTypeRoots(options: CompilerOptions, host: ModuleResolutionHost) {
@ -508,7 +501,7 @@ namespace ts {
if (state.traceEnabled) {
trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName);
}
matchedPattern = matchPatternOrExact(getKeys(state.compilerOptions.paths), moduleName);
matchedPattern = matchPatternOrExact(getOwnKeys(state.compilerOptions.paths), moduleName);
}
if (matchedPattern) {
@ -717,7 +710,7 @@ namespace ts {
}
function loadNodeModuleFromDirectory(extensions: string[], candidate: string, failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string {
const packageJsonPath = combinePaths(candidate, "package.json");
const packageJsonPath = pathToPackageJson(candidate);
const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host);
if (directoryExists && state.host.fileExists(packageJsonPath)) {
if (state.traceEnabled) {
@ -747,6 +740,10 @@ namespace ts {
return loadModuleFromFile(combinePaths(candidate, "index"), extensions, failedLookupLocation, !directoryExists, state);
}
function pathToPackageJson(directory: string): string {
return combinePaths(directory, "package.json");
}
function loadModuleFromNodeModulesFolder(moduleName: string, directory: string, failedLookupLocations: string[], state: ModuleResolutionState): string {
const nodeModulesFolder = combinePaths(directory, "node_modules");
const nodeModulesFolderExists = directoryProbablyExists(nodeModulesFolder, state.host);
@ -831,14 +828,6 @@ namespace ts {
: { resolvedModule: undefined, failedLookupLocations };
}
/* @internal */
export const defaultInitCompilerOptions: CompilerOptions = {
module: ModuleKind.CommonJS,
target: ScriptTarget.ES5,
noImplicitAny: false,
sourceMap: false,
};
interface OutputFingerprint {
hash: string;
byteOrderMark: boolean;
@ -846,7 +835,7 @@ namespace ts {
}
export function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost {
const existingDirectories: Map<boolean> = {};
const existingDirectories = createMap<boolean>();
function getCanonicalFileName(fileName: string): string {
// if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
@ -860,9 +849,10 @@ namespace ts {
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile {
let text: string;
try {
const start = performance.mark();
performance.mark("beforeIORead");
text = sys.readFile(fileName, options.charset);
performance.measure("I/O Read", start);
performance.mark("afterIORead");
performance.measure("I/O Read", "beforeIORead", "afterIORead");
}
catch (e) {
if (onError) {
@ -877,7 +867,7 @@ namespace ts {
}
function directoryExists(directoryPath: string): boolean {
if (hasProperty(existingDirectories, directoryPath)) {
if (directoryPath in existingDirectories) {
return true;
}
if (sys.directoryExists(directoryPath)) {
@ -899,13 +889,13 @@ namespace ts {
function writeFileIfUpdated(fileName: string, data: string, writeByteOrderMark: boolean): void {
if (!outputFingerprints) {
outputFingerprints = {};
outputFingerprints = createMap<OutputFingerprint>();
}
const hash = sys.createHash(data);
const mtimeBefore = sys.getModifiedTime(fileName);
if (mtimeBefore && hasProperty(outputFingerprints, fileName)) {
if (mtimeBefore && fileName in outputFingerprints) {
const fingerprint = outputFingerprints[fileName];
// If output has not been changed, and the file has no external modification
@ -929,7 +919,7 @@ namespace ts {
function writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) {
try {
const start = performance.mark();
performance.mark("beforeIOWrite");
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
if (isWatchSet(options) && sys.createHash && sys.getModifiedTime) {
@ -939,7 +929,8 @@ namespace ts {
sys.writeFile(fileName, data, writeByteOrderMark);
}
performance.measure("I/O Write", start);
performance.mark("afterIOWrite");
performance.measure("I/O Write", "beforeIOWrite", "afterIOWrite");
}
catch (e) {
if (onError) {
@ -1040,47 +1031,47 @@ namespace ts {
return [];
}
const resolutions: T[] = [];
const cache: Map<T> = {};
const cache = createMap<T>();
for (const name of names) {
let result: T;
if (hasProperty(cache, name)) {
result = cache[name];
}
else {
result = loader(name, containingFile);
cache[name] = result;
}
const result = name in cache
? cache[name]
: cache[name] = loader(name, containingFile);
resolutions.push(result);
}
return resolutions;
}
function getInferredTypesRoot(options: CompilerOptions, rootFiles: string[], host: CompilerHost) {
return computeCommonSourceDirectoryOfFilenames(rootFiles, host.getCurrentDirectory(), f => host.getCanonicalFileName(f));
}
/**
* Given a set of options and a set of root files, returns the set of type directive names
* Given a set of options, returns the set of type directive names
* that should be included for this program automatically.
* This list could either come from the config file,
* or from enumerating the types root + initial secondary types lookup location.
* More type directives might appear in the program later as a result of loading actual source files;
* this list is only the set of defaults that are implicitly included.
*/
export function getAutomaticTypeDirectiveNames(options: CompilerOptions, rootFiles: string[], host: CompilerHost): string[] {
export function getAutomaticTypeDirectiveNames(options: CompilerOptions, host: ModuleResolutionHost): string[] {
// Use explicit type list from tsconfig.json
if (options.types) {
return options.types;
}
// Walk the primary type lookup locations
let result: string[] = [];
const result: string[] = [];
if (host.directoryExists && host.getDirectories) {
const typeRoots = getEffectiveTypeRoots(options, host);
if (typeRoots) {
for (const root of typeRoots) {
if (host.directoryExists(root)) {
result = result.concat(host.getDirectories(root));
for (const typeDirectivePath of host.getDirectories(root)) {
const normalized = normalizePath(typeDirectivePath);
const packageJsonPath = pathToPackageJson(combinePaths(root, normalized));
// tslint:disable-next-line:no-null-keyword
const isNotNeededPackage = host.fileExists(packageJsonPath) && readJson(packageJsonPath, host).typings === null;
if (!isNotNeededPackage) {
// Return just the type directive names
result.push(getBaseFileName(normalized));
}
}
}
}
}
@ -1096,7 +1087,7 @@ namespace ts {
let noDiagnosticsTypeChecker: TypeChecker;
let classifiableNames: Map<string>;
let resolvedTypeReferenceDirectives: Map<ResolvedTypeReferenceDirective> = {};
let resolvedTypeReferenceDirectives = createMap<ResolvedTypeReferenceDirective>();
let fileProcessingDiagnostics = createDiagnosticCollection();
// The below settings are to track if a .js file should be add to the program if loaded via searching under node_modules.
@ -1111,12 +1102,12 @@ namespace ts {
// If a module has some of its imports skipped due to being at the depth limit under node_modules, then track
// this, as it may be imported at a shallower depth later, and then it will need its skipped imports processed.
const modulesWithElidedImports: Map<boolean> = {};
const modulesWithElidedImports = createMap<boolean>();
// Track source files that are source files found by searching under node_modules, as these shouldn't be compiled.
const sourceFilesFoundSearchingNodeModules: Map<boolean> = {};
const sourceFilesFoundSearchingNodeModules = createMap<boolean>();
const start = performance.mark();
performance.mark("beforeProgram");
host = host || createCompilerHost(options);
@ -1155,11 +1146,11 @@ namespace ts {
forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false));
// load type declarations specified via 'types' argument or implicitly from types/ and node_modules/@types folders
const typeReferences: string[] = getAutomaticTypeDirectiveNames(options, rootNames, host);
const typeReferences: string[] = getAutomaticTypeDirectiveNames(options, host);
if (typeReferences) {
const inferredRoot = getInferredTypesRoot(options, rootNames, host);
const containingFilename = combinePaths(inferredRoot, "__inferred type names__.ts");
// This containingFilename needs to match with the one used in managed-side
const containingFilename = combinePaths(host.getCurrentDirectory(), "__inferred type names__.ts");
const resolutions = resolveTypeReferenceDirectiveNamesWorker(typeReferences, containingFilename);
for (let i = 0; i < typeReferences.length; i++) {
processTypeReferenceDirective(typeReferences[i], resolutions[i]);
@ -1214,8 +1205,8 @@ namespace ts {
};
verifyCompilerOptions();
performance.measure("Program", start);
performance.mark("afterProgram");
performance.measure("Program", "beforeProgram", "afterProgram");
return program;
@ -1242,10 +1233,10 @@ namespace ts {
if (!classifiableNames) {
// Initialize a checker so that all our files are bound.
getTypeChecker();
classifiableNames = {};
classifiableNames = createMap<string>();
for (const sourceFile of files) {
copyMap(sourceFile.classifiableNames, classifiableNames);
copyProperties(sourceFile.classifiableNames, classifiableNames);
}
}
@ -1273,7 +1264,7 @@ namespace ts {
(oldOptions.maxNodeModuleJsDepth !== options.maxNodeModuleJsDepth) ||
!arrayIsEqualTo(oldOptions.typeRoots, oldOptions.typeRoots) ||
!arrayIsEqualTo(oldOptions.rootDirs, options.rootDirs) ||
!mapIsEqualTo(oldOptions.paths, options.paths)) {
!equalOwnProperties(oldOptions.paths, options.paths)) {
return false;
}
@ -1395,7 +1386,7 @@ namespace ts {
getSourceFile: program.getSourceFile,
getSourceFileByPath: program.getSourceFileByPath,
getSourceFiles: program.getSourceFiles,
isSourceFileFromExternalLibrary: (file: SourceFile) => !!lookUp(sourceFilesFoundSearchingNodeModules, file.path),
isSourceFileFromExternalLibrary: (file: SourceFile) => !!sourceFilesFoundSearchingNodeModules[file.path],
writeFile: writeFileCallback || (
(fileName, data, writeByteOrderMark, onError, sourceFiles) => host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles)),
isEmitBlocked,
@ -1458,14 +1449,15 @@ namespace ts {
// checked is to not pass the file to getEmitResolver.
const emitResolver = getDiagnosticsProducingTypeChecker().getEmitResolver((options.outFile || options.out) ? undefined : sourceFile);
const start = performance.mark();
performance.mark("beforeEmit");
const emitResult = emitFiles(
emitResolver,
getEmitHost(writeFileCallback),
sourceFile);
performance.measure("Emit", start);
performance.mark("afterEmit");
performance.measure("Emit", "beforeEmit", "afterEmit");
return emitResult;
}
@ -1932,7 +1924,7 @@ namespace ts {
// If the file was previously found via a node_modules search, but is now being processed as a root file,
// then everything it sucks in may also be marked incorrectly, and needs to be checked again.
if (file && lookUp(sourceFilesFoundSearchingNodeModules, file.path) && currentNodeModulesDepth == 0) {
if (file && sourceFilesFoundSearchingNodeModules[file.path] && currentNodeModulesDepth == 0) {
sourceFilesFoundSearchingNodeModules[file.path] = false;
if (!options.noResolve) {
processReferencedFiles(file, getDirectoryPath(fileName), isDefaultLib);
@ -1943,7 +1935,7 @@ namespace ts {
processImportedModules(file, getDirectoryPath(fileName));
}
// See if we need to reprocess the imports due to prior skipped imports
else if (file && lookUp(modulesWithElidedImports, file.path)) {
else if (file && modulesWithElidedImports[file.path]) {
if (currentNodeModulesDepth < maxNodeModulesJsDepth) {
modulesWithElidedImports[file.path] = false;
processImportedModules(file, getDirectoryPath(fileName));
@ -2010,15 +2002,17 @@ namespace ts {
}
function processTypeReferenceDirectives(file: SourceFile) {
const typeDirectives = map(file.typeReferenceDirectives, l => l.fileName);
// We lower-case all type references because npm automatically lowercases all packages. See GH#9824.
const typeDirectives = map(file.typeReferenceDirectives, ref => ref.fileName.toLocaleLowerCase());
const resolutions = resolveTypeReferenceDirectiveNamesWorker(typeDirectives, file.fileName);
for (let i = 0; i < typeDirectives.length; i++) {
const ref = file.typeReferenceDirectives[i];
const resolvedTypeReferenceDirective = resolutions[i];
// store resolved type directive on the file
setResolvedTypeReferenceDirective(file, ref.fileName, resolvedTypeReferenceDirective);
processTypeReferenceDirective(ref.fileName, resolvedTypeReferenceDirective, file, ref.pos, ref.end);
const fileName = ref.fileName.toLocaleLowerCase();
setResolvedTypeReferenceDirective(file, fileName, resolvedTypeReferenceDirective);
processTypeReferenceDirective(fileName, resolvedTypeReferenceDirective, file, ref.pos, ref.end);
}
}
@ -2043,7 +2037,7 @@ namespace ts {
const otherFileText = host.readFile(resolvedTypeReferenceDirective.resolvedFileName);
if (otherFileText !== getSourceFile(previousResolution.resolvedFileName).text) {
fileProcessingDiagnostics.add(createDiagnostic(refFile, refPos, refEnd,
Diagnostics.Conflicting_library_definitions_for_0_found_at_1_and_2_Copy_the_correct_file_to_the_typings_folder_to_resolve_this_conflict,
Diagnostics.Conflicting_definitions_for_0_found_at_1_and_2_Consider_installing_a_specific_version_of_this_library_to_resolve_the_conflict,
typeReferenceDirective,
resolvedTypeReferenceDirective.resolvedFileName,
previousResolution.resolvedFileName
@ -2083,7 +2077,7 @@ namespace ts {
function processImportedModules(file: SourceFile, basePath: string) {
collectExternalModuleReferences(file);
if (file.imports.length || file.moduleAugmentations.length) {
file.resolvedModules = {};
file.resolvedModules = createMap<ResolvedModule>();
const moduleNames = map(concatenate(file.imports, file.moduleAugmentations), getTextOfLiteral);
const resolutions = resolveModuleNamesWorker(moduleNames, getNormalizedAbsolutePath(file.fileName, currentDirectory));
for (let i = 0; i < moduleNames.length; i++) {
@ -2200,6 +2194,9 @@ namespace ts {
programDiagnostics.add(createCompilerDiagnostic(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));
}
for (const subst of options.paths[key]) {
const typeOfSubst = typeof subst;
if (typeOfSubst === "string") {
@ -2252,7 +2249,7 @@ namespace ts {
const languageVersion = options.target || ScriptTarget.ES3;
const outFile = options.outFile || options.out;
const firstExternalModuleSourceFile = forEach(files, f => isExternalModule(f) ? f : undefined);
const firstNonAmbientExternalModuleSourceFile = forEach(files, f => isExternalModule(f) && !isDeclarationFile(f) ? f : undefined);
if (options.isolatedModules) {
if (options.module === ModuleKind.None && languageVersion < ScriptTarget.ES6) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher));
@ -2264,10 +2261,10 @@ namespace ts {
programDiagnostics.add(createFileDiagnostic(firstNonExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_namespaces_when_the_isolatedModules_flag_is_provided));
}
}
else if (firstExternalModuleSourceFile && languageVersion < ScriptTarget.ES6 && options.module === ModuleKind.None) {
else if (firstNonAmbientExternalModuleSourceFile && languageVersion < ScriptTarget.ES6 && options.module === ModuleKind.None) {
// We cannot use createDiagnosticFromNode because nodes do not have parents yet
const span = getErrorSpanForNode(firstExternalModuleSourceFile, firstExternalModuleSourceFile.externalModuleIndicator);
programDiagnostics.add(createFileDiagnostic(firstExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_use_imports_exports_or_module_augmentations_when_module_is_none));
const span = getErrorSpanForNode(firstNonAmbientExternalModuleSourceFile, firstNonAmbientExternalModuleSourceFile.externalModuleIndicator);
programDiagnostics.add(createFileDiagnostic(firstNonAmbientExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_use_imports_exports_or_module_augmentations_when_module_is_none));
}
// Cannot specify module gen that isn't amd or system with --out
@ -2275,9 +2272,9 @@ namespace ts {
if (options.module && !(options.module === ModuleKind.AMD || options.module === ModuleKind.System)) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Only_amd_and_system_modules_are_supported_alongside_0, options.out ? "out" : "outFile"));
}
else if (options.module === undefined && firstExternalModuleSourceFile) {
const span = getErrorSpanForNode(firstExternalModuleSourceFile, firstExternalModuleSourceFile.externalModuleIndicator);
programDiagnostics.add(createFileDiagnostic(firstExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_modules_using_option_0_unless_the_module_flag_is_amd_or_system, options.out ? "out" : "outFile"));
else if (options.module === undefined && firstNonAmbientExternalModuleSourceFile) {
const span = getErrorSpanForNode(firstNonAmbientExternalModuleSourceFile, firstNonAmbientExternalModuleSourceFile.externalModuleIndicator);
programDiagnostics.add(createFileDiagnostic(firstNonAmbientExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_modules_using_option_0_unless_the_module_flag_is_amd_or_system, options.out ? "out" : "outFile"));
}
}

View File

@ -55,7 +55,7 @@ namespace ts {
tryScan<T>(callback: () => T): T;
}
const textToToken: Map<SyntaxKind> = {
const textToToken = createMap({
"abstract": SyntaxKind.AbstractKeyword,
"any": SyntaxKind.AnyKeyword,
"as": SyntaxKind.AsKeyword,
@ -179,7 +179,7 @@ namespace ts {
"|=": SyntaxKind.BarEqualsToken,
"^=": SyntaxKind.CaretEqualsToken,
"@": SyntaxKind.AtToken,
};
});
/*
As per ECMAScript Language Specification 3th Edition, Section 7.6: Identifiers
@ -274,9 +274,7 @@ namespace ts {
function makeReverseMap(source: Map<number>): string[] {
const result: string[] = [];
for (const name in source) {
if (source.hasOwnProperty(name)) {
result[source[name]] = name;
}
result[source[name]] = name;
}
return result;
}

View File

@ -46,6 +46,7 @@ namespace ts {
export function createSourceMapWriter(host: EmitHost, writer: EmitTextWriter): SourceMapWriter {
const compilerOptions = host.getCompilerOptions();
const extendedDiagnostics = compilerOptions.extendedDiagnostics;
let currentSourceFile: SourceFile;
let sourceMapDir: string; // The directory in which sourcemap will be
let stopOverridingSpan = false;
@ -240,7 +241,9 @@ namespace ts {
return;
}
const start = performance.mark();
if (extendedDiagnostics) {
performance.mark("beforeSourcemap");
}
const sourceLinePos = getLineAndCharacterOfPosition(currentSourceFile, pos);
@ -282,7 +285,10 @@ namespace ts {
updateLastEncodedAndRecordedSpans();
performance.measure("Source Map", start);
if (extendedDiagnostics) {
performance.mark("afterSourcemap");
performance.measure("Source Map", "beforeSourcemap", "afterSourcemap");
}
}
function getStartPos(range: TextRange) {

View File

@ -233,15 +233,15 @@ namespace ts {
const useNonPollingWatchers = process.env["TSC_NONPOLLING_WATCHER"];
function createWatchedFileSet() {
const dirWatchers: Map<DirectoryWatcher> = {};
const dirWatchers = createMap<DirectoryWatcher>();
// One file can have multiple watchers
const fileWatcherCallbacks: Map<FileWatcherCallback[]> = {};
const fileWatcherCallbacks = createMap<FileWatcherCallback[]>();
return { addFile, removeFile };
function reduceDirWatcherRefCountForFile(fileName: string) {
const dirName = getDirectoryPath(fileName);
if (hasProperty(dirWatchers, dirName)) {
const watcher = dirWatchers[dirName];
const watcher = dirWatchers[dirName];
if (watcher) {
watcher.referenceCount -= 1;
if (watcher.referenceCount <= 0) {
watcher.close();
@ -251,13 +251,12 @@ namespace ts {
}
function addDirWatcher(dirPath: string): void {
if (hasProperty(dirWatchers, dirPath)) {
const watcher = dirWatchers[dirPath];
let watcher = dirWatchers[dirPath];
if (watcher) {
watcher.referenceCount += 1;
return;
}
const watcher: DirectoryWatcher = _fs.watch(
watcher = _fs.watch(
dirPath,
{ persistent: true },
(eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath)
@ -268,12 +267,7 @@ namespace ts {
}
function addFileWatcherCallback(filePath: string, callback: FileWatcherCallback): void {
if (hasProperty(fileWatcherCallbacks, filePath)) {
fileWatcherCallbacks[filePath].push(callback);
}
else {
fileWatcherCallbacks[filePath] = [callback];
}
(fileWatcherCallbacks[filePath] || (fileWatcherCallbacks[filePath] = [])).push(callback);
}
function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile {
@ -289,8 +283,9 @@ namespace ts {
}
function removeFileWatcherCallback(filePath: string, callback: FileWatcherCallback) {
if (hasProperty(fileWatcherCallbacks, filePath)) {
const newCallbacks = copyListRemovingItem(callback, fileWatcherCallbacks[filePath]);
const callbacks = fileWatcherCallbacks[filePath];
if (callbacks) {
const newCallbacks = copyListRemovingItem(callback, callbacks);
if (newCallbacks.length === 0) {
delete fileWatcherCallbacks[filePath];
}
@ -306,7 +301,7 @@ namespace ts {
? undefined
: ts.getNormalizedAbsolutePath(relativeFileName, baseDirPath);
// Some applications save a working file via rename operations
if ((eventName === "change" || eventName === "rename") && hasProperty(fileWatcherCallbacks, fileName)) {
if ((eventName === "change" || eventName === "rename") && fileWatcherCallbacks[fileName]) {
for (const fileCallback of fileWatcherCallbacks[fileName]) {
fileCallback(fileName);
}

View File

@ -122,11 +122,11 @@ namespace ts {
const gutterSeparator = " ";
const resetEscapeSequence = "\u001b[0m";
const ellipsis = "...";
const categoryFormatMap: Map<string> = {
const categoryFormatMap = createMap<string>({
[DiagnosticCategory.Warning]: yellowForegroundEscapeSequence,
[DiagnosticCategory.Error]: redForegroundEscapeSequence,
[DiagnosticCategory.Message]: blueForegroundEscapeSequence,
};
});
function formatAndReset(text: string, formatStyle: string) {
return formatStyle + text + resetEscapeSequence;
@ -432,7 +432,7 @@ namespace ts {
}
// reset the cache of existing files
cachedExistingFiles = {};
cachedExistingFiles = createMap<boolean>();
const compileResult = compile(rootFileNames, compilerOptions, compilerHost);
@ -445,10 +445,9 @@ namespace ts {
}
function cachedFileExists(fileName: string): boolean {
if (hasProperty(cachedExistingFiles, fileName)) {
return cachedExistingFiles[fileName];
}
return cachedExistingFiles[fileName] = hostFileExists(fileName);
return fileName in cachedExistingFiles
? cachedExistingFiles[fileName]
: cachedExistingFiles[fileName] = hostFileExists(fileName);
}
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void) {
@ -676,7 +675,7 @@ namespace ts {
const usageColumn: string[] = []; // Things like "-d, --declaration" go in here.
const descriptionColumn: string[] = [];
const optionsDescriptionMap: Map<string[]> = {}; // Map between option.description and list of option.type if it is a kind
const optionsDescriptionMap = createMap<string[]>(); // Map between option.description and list of option.type if it is a kind
for (let i = 0; i < optsList.length; i++) {
const option = optsList[i];
@ -704,9 +703,10 @@ namespace ts {
description = getDiagnosticText(option.description);
const options: string[] = [];
const element = (<CommandLineOptionOfListType>option).element;
forEachKey(<Map<number | string>>element.type, key => {
const typeMap = <Map<number | string>>element.type;
for (const key in typeMap) {
options.push(`'${key}'`);
});
}
optionsDescriptionMap[description] = options;
}
else {
@ -763,68 +763,11 @@ namespace ts {
reportDiagnostic(createCompilerDiagnostic(Diagnostics.A_tsconfig_json_file_is_already_defined_at_Colon_0, file), /* host */ undefined);
}
else {
const compilerOptions = extend(options, defaultInitCompilerOptions);
const configurations: any = {
compilerOptions: serializeCompilerOptions(compilerOptions)
};
if (fileNames && fileNames.length) {
// only set the files property if we have at least one file
configurations.files = fileNames;
}
else {
configurations.exclude = ["node_modules"];
if (compilerOptions.outDir) {
configurations.exclude.push(compilerOptions.outDir);
}
}
sys.writeFile(file, JSON.stringify(configurations, undefined, 4));
sys.writeFile(file, JSON.stringify(generateTSConfig(options, fileNames), undefined, 4));
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Successfully_created_a_tsconfig_json_file), /* host */ undefined);
}
return;
function serializeCompilerOptions(options: CompilerOptions): Map<string | number | boolean> {
const result: Map<string | number | boolean> = {};
const optionsNameMap = getOptionNameMap().optionNameMap;
for (const name in options) {
if (hasProperty(options, name)) {
// tsconfig only options cannot be specified via command line,
// so we can assume that only types that can appear here string | number | boolean
const value = <string | number | boolean>options[name];
switch (name) {
case "init":
case "watch":
case "version":
case "help":
case "project":
break;
default:
let optionDefinition = optionsNameMap[name.toLowerCase()];
if (optionDefinition) {
if (typeof optionDefinition.type === "string") {
// string, number or boolean
result[name] = value;
}
else {
// Enum
const typeMap = <Map<number>>optionDefinition.type;
for (const key in typeMap) {
if (hasProperty(typeMap, key)) {
if (typeMap[key] === value)
result[name] = key;
}
}
}
}
break;
}
}
}
return result;
}
}
}

View File

@ -1,9 +1,13 @@
namespace ts {
export interface Map<T> {
export interface MapLike<T> {
[index: string]: T;
}
export interface Map<T> extends MapLike<T> {
__mapBrand: any;
}
// branded string type used to store absolute, normalized and canonicalized paths
// arbitrary file name can be converted to Path via toPath function
export type Path = string & { __pathBrand: any };
@ -210,7 +214,7 @@ namespace ts {
IntersectionType,
ParenthesizedType,
ThisType,
StringLiteralType,
LiteralType,
// Binding patterns
ObjectBindingPattern,
ArrayBindingPattern,
@ -346,6 +350,7 @@ namespace ts {
JSDocTypedefTag,
JSDocPropertyTag,
JSDocTypeLiteral,
JSDocLiteralType,
// Synthesized list
SyntaxList,
@ -361,7 +366,7 @@ namespace ts {
FirstFutureReservedWord = ImplementsKeyword,
LastFutureReservedWord = YieldKeyword,
FirstTypeNode = TypePredicate,
LastTypeNode = StringLiteralType,
LastTypeNode = LiteralType,
FirstPunctuation = OpenBraceToken,
LastPunctuation = CaretEqualsToken,
FirstToken = Unknown,
@ -376,9 +381,9 @@ namespace ts {
LastBinaryOperator = CaretEqualsToken,
FirstNode = QualifiedName,
FirstJSDocNode = JSDocTypeExpression,
LastJSDocNode = JSDocTypeLiteral,
LastJSDocNode = JSDocLiteralType,
FirstJSDocTagNode = JSDocComment,
LastJSDocTagNode = JSDocTypeLiteral
LastJSDocTagNode = JSDocLiteralType
}
export const enum NodeFlags {
@ -794,8 +799,9 @@ namespace ts {
}
// @kind(SyntaxKind.StringLiteralType)
export interface StringLiteralTypeNode extends LiteralLikeNode, TypeNode {
export interface LiteralTypeNode extends TypeNode {
_stringLiteralTypeBrand: any;
literal: Expression;
}
// @kind(SyntaxKind.StringLiteral)
@ -981,13 +987,19 @@ namespace ts {
multiLine?: boolean;
}
export type EntityNameExpression = Identifier | PropertyAccessEntityNameExpression;
export type EntityNameOrEntityNameExpression = EntityName | EntityNameExpression;
// @kind(SyntaxKind.PropertyAccessExpression)
export interface PropertyAccessExpression extends MemberExpression, Declaration {
expression: LeftHandSideExpression;
name: Identifier;
}
export type IdentifierOrPropertyAccess = Identifier | PropertyAccessExpression;
/** Brand for a PropertyAccessExpression which, like a QualifiedName, consists of a sequence of identifiers separated by dots. */
export interface PropertyAccessEntityNameExpression extends PropertyAccessExpression {
_propertyAccessExpressionLikeQualifiedNameBrand?: any;
expression: EntityNameExpression;
}
// @kind(SyntaxKind.ElementAccessExpression)
export interface ElementAccessExpression extends MemberExpression {
@ -1491,6 +1503,10 @@ namespace ts {
type: JSDocType;
}
export interface JSDocLiteralType extends JSDocType {
literal: LiteralTypeNode;
}
export type JSDocTypeReferencingNode = JSDocThisType | JSDocConstructorType | JSDocVariadicType | JSDocOptionalType | JSDocNullableType | JSDocNonNullableType;
// @kind(SyntaxKind.JSDocRecordMember)
@ -1605,6 +1621,16 @@ namespace ts {
antecedent: FlowNode;
}
export type FlowType = Type | IncompleteType;
// Incomplete types occur during control flow analysis of loops. An IncompleteType
// is distinguished from a regular type by a flags value of zero. Incomplete type
// objects are internal to the getFlowTypeOfRefecence function and never escape it.
export interface IncompleteType {
flags: TypeFlags; // No flags set
type: Type; // The type marked incomplete
}
export interface AmdDependency {
path: string;
name: string;
@ -1916,6 +1942,7 @@ namespace ts {
InElementType = 0x00000040, // Writing an array or union element type
UseFullyQualifiedType = 0x00000080, // Write out the fully qualified type name (eg. Module.Type, instead of Type)
InFirstTypeArgument = 0x00000100, // Writing first type argument of the instantiated type
InTypeAlias = 0x00000200, // Writing type in type alias declaration
}
export const enum SymbolFormatFlags {
@ -2019,7 +2046,7 @@ namespace ts {
writeTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
writeBaseConstructorTypeOfClass(node: ClassLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessibilityResult;
isEntityNameVisible(entityName: EntityName | Expression, enclosingDeclaration: Node): SymbolVisibilityResult;
isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult;
// Returns the constant value this property access resolves to, or 'undefined' for a non-constant
getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number;
getReferencedValueDeclaration(reference: Identifier): Declaration;
@ -2028,7 +2055,7 @@ namespace ts {
moduleExportsSomeValue(moduleReferenceExpression: Expression): boolean;
isArgumentsLocalBinding(node: Identifier): boolean;
getExternalModuleFileFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration): SourceFile;
getTypeReferenceDirectivesForEntityName(name: EntityName | PropertyAccessExpression): string[];
getTypeReferenceDirectivesForEntityName(name: EntityNameOrEntityNameExpression): string[];
getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): string[];
}
@ -2069,8 +2096,8 @@ namespace ts {
Enum = RegularEnum | ConstEnum,
Variable = FunctionScopedVariable | BlockScopedVariable,
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor,
Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias,
Namespace = ValueModule | NamespaceModule,
Type = Class | Interface | Enum | EnumMember | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias,
Namespace = ValueModule | NamespaceModule | Enum,
Module = ValueModule | NamespaceModule,
Accessor = GetAccessor | SetAccessor,
@ -2084,7 +2111,7 @@ namespace ts {
ParameterExcludes = Value,
PropertyExcludes = None,
EnumMemberExcludes = Value,
EnumMemberExcludes = Value | Type,
FunctionExcludes = Value & ~(Function | ValueModule),
ClassExcludes = (Value | Type) & ~(ValueModule | Interface), // class-interface mergability done in checker.ts
InterfaceExcludes = Type & ~(Interface | Class),
@ -2135,6 +2162,8 @@ namespace ts {
/* @internal */ exportSymbol?: Symbol; // Exported symbol associated with this symbol
/* @internal */ constEnumOnlyModule?: boolean; // True if module contains only const enums or other modules with only const enums
/* @internal */ isReferenced?: boolean; // True if the symbol is referenced elsewhere
/* @internal */ isReplaceableByMethod?: boolean; // Can this Javascript class property be replaced by a method symbol?
/* @internal */ isAssigned?: boolean; // True if the symbol is a parameter with assignments
}
/* @internal */
@ -2148,6 +2177,8 @@ namespace ts {
mapper?: TypeMapper; // Type mapper for instantiation alias
referenced?: boolean; // True if alias symbol has been referenced as a value
containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property
hasCommonType?: boolean; // True if constituents of synthetic property all have same type
isDiscriminantProperty?: boolean; // True if discriminant synthetic property
resolvedExports?: SymbolTable; // Resolved exports of module
exportsChecked?: boolean; // True if exports of external module have been checked
isDeclarationWithCollidingName?: boolean; // True if symbol is block scoped redeclaration
@ -2158,9 +2189,7 @@ namespace ts {
/* @internal */
export interface TransientSymbol extends Symbol, SymbolLinks { }
export interface SymbolTable {
[index: string]: Symbol;
}
export type SymbolTable = Map<Symbol>;
/** Represents a "prefix*suffix" pattern. */
/* @internal */
@ -2187,23 +2216,24 @@ namespace ts {
AsyncMethodWithSuper = 0x00000800, // An async method that reads a value from a member of 'super'.
AsyncMethodWithSuperBinding = 0x00001000, // An async method that assigns a value to a member of 'super'.
CaptureArguments = 0x00002000, // Lexical 'arguments' used in body (for async functions)
EnumValuesComputed = 0x00004000, // Values for enum members have been computed, and any errors have been reported for them.
LexicalModuleMergesWithClass = 0x00008000, // Instantiated lexical module declaration is merged with a previous class declaration.
LoopWithCapturedBlockScopedBinding = 0x00010000, // Loop that contains block scoped variable captured in closure
CapturedBlockScopedBinding = 0x00020000, // Block-scoped binding that is captured in some function
BlockScopedBindingInLoop = 0x00040000, // Block-scoped binding with declaration nested inside iteration statement
ClassWithBodyScopedClassBinding = 0x00080000, // Decorated class that contains a binding to itself inside of the class body.
BodyScopedClassBinding = 0x00100000, // Binding to a decorated class inside of the class's body.
NeedsLoopOutParameter = 0x00200000, // Block scoped binding whose value should be explicitly copied outside of the converted loop
EnumValuesComputed = 0x00004000, // Values for enum members have been computed, and any errors have been reported for them.
LexicalModuleMergesWithClass = 0x00008000, // Instantiated lexical module declaration is merged with a previous class declaration.
LoopWithCapturedBlockScopedBinding = 0x00010000, // Loop that contains block scoped variable captured in closure
CapturedBlockScopedBinding = 0x00020000, // Block-scoped binding that is captured in some function
BlockScopedBindingInLoop = 0x00040000, // Block-scoped binding with declaration nested inside iteration statement
ClassWithBodyScopedClassBinding = 0x00080000, // Decorated class that contains a binding to itself inside of the class body.
BodyScopedClassBinding = 0x00100000, // Binding to a decorated class inside of the class's body.
NeedsLoopOutParameter = 0x00200000, // Block scoped binding whose value should be explicitly copied outside of the converted loop
AssignmentsMarked = 0x00400000, // Parameter assignments have been marked
}
/* @internal */
export interface NodeLinks {
flags?: NodeCheckFlags; // Set of flags specific to Node
resolvedType?: Type; // Cached type of type node
resolvedSignature?: Signature; // Cached signature of signature node or call expression
resolvedSymbol?: Symbol; // Cached name resolution result
resolvedIndexInfo?: IndexInfo; // Cached indexing info resolution result
flags?: NodeCheckFlags; // Set of flags specific to Node
enumMemberValue?: number; // Constant value of enum member
isVisible?: boolean; // Is this node visible
hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context
@ -2215,57 +2245,65 @@ namespace ts {
}
export const enum TypeFlags {
Any = 0x00000001,
String = 0x00000002,
Number = 0x00000004,
Boolean = 0x00000008,
Void = 0x00000010,
Undefined = 0x00000020,
Null = 0x00000040,
Enum = 0x00000080, // Enum type
StringLiteral = 0x00000100, // String literal type
TypeParameter = 0x00000200, // Type parameter
Class = 0x00000400, // Class
Interface = 0x00000800, // Interface
Reference = 0x00001000, // Generic type reference
Tuple = 0x00002000, // Tuple
Union = 0x00004000, // Union (T | U)
Intersection = 0x00008000, // Intersection (T & U)
Anonymous = 0x00010000, // Anonymous
Instantiated = 0x00020000, // Instantiated anonymous type
Any = 1 << 0,
String = 1 << 1,
Number = 1 << 2,
Boolean = 1 << 3,
Enum = 1 << 4,
StringLiteral = 1 << 5,
NumberLiteral = 1 << 6,
BooleanLiteral = 1 << 7,
EnumLiteral = 1 << 8,
ESSymbol = 1 << 9, // Type of symbol primitive introduced in ES6
Void = 1 << 10,
Undefined = 1 << 11,
Null = 1 << 12,
Never = 1 << 13, // Never type
TypeParameter = 1 << 14, // Type parameter
Class = 1 << 15, // Class
Interface = 1 << 16, // Interface
Reference = 1 << 17, // Generic type reference
Tuple = 1 << 18, // Tuple
Union = 1 << 19, // Union (T | U)
Intersection = 1 << 20, // Intersection (T & U)
Anonymous = 1 << 21, // Anonymous
Instantiated = 1 << 22, // Instantiated anonymous type
/* @internal */
FromSignature = 0x00040000, // Created for signature assignment check
ObjectLiteral = 0x00080000, // Originates in an object literal
ObjectLiteral = 1 << 23, // Originates in an object literal
/* @internal */
FreshObjectLiteral = 0x00100000, // Fresh object literal type
FreshObjectLiteral = 1 << 24, // Fresh object literal type
/* @internal */
ContainsWideningType = 0x00200000, // Type is or contains undefined or null widening type
ContainsWideningType = 1 << 25, // Type is or contains undefined or null widening type
/* @internal */
ContainsObjectLiteral = 0x00400000, // Type is or contains object literal type
ContainsObjectLiteral = 1 << 26, // Type is or contains object literal type
/* @internal */
ContainsAnyFunctionType = 0x00800000, // Type is or contains object literal type
ESSymbol = 0x01000000, // Type of symbol primitive introduced in ES6
ThisType = 0x02000000, // This type
ObjectLiteralPatternWithComputedProperties = 0x04000000, // Object literal type implied by binding pattern has computed properties
Never = 0x08000000, // Never type
ContainsAnyFunctionType = 1 << 27, // Type is or contains object literal type
ThisType = 1 << 28, // This type
ObjectLiteralPatternWithComputedProperties = 1 << 29, // Object literal type implied by binding pattern has computed properties
/* @internal */
Nullable = Undefined | Null,
Literal = StringLiteral | NumberLiteral | BooleanLiteral | EnumLiteral,
/* @internal */
Falsy = Void | Undefined | Null, // TODO: Add false, 0, and ""
DefinitelyFalsy = StringLiteral | NumberLiteral | BooleanLiteral | Void | Undefined | Null,
PossiblyFalsy = DefinitelyFalsy | String | Number | Boolean,
/* @internal */
Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null | Never,
Intrinsic = Any | String | Number | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never,
/* @internal */
Primitive = String | Number | Boolean | ESSymbol | Void | Undefined | Null | StringLiteral | Enum,
Primitive = String | Number | Boolean | Enum | ESSymbol | Void | Undefined | Null | Literal,
StringLike = String | StringLiteral,
NumberLike = Number | Enum,
NumberLike = Number | NumberLiteral | Enum | EnumLiteral,
BooleanLike = Boolean | BooleanLiteral,
EnumLike = Enum | EnumLiteral,
ObjectType = Class | Interface | Reference | Tuple | Anonymous,
UnionOrIntersection = Union | Intersection,
StructuredType = ObjectType | Union | Intersection,
StructuredOrTypeParameter = StructuredType | TypeParameter,
// 'Narrowable' types are types where narrowing actually narrows.
// This *should* be every type other than null, undefined, void, and never
Narrowable = Any | StructuredType | TypeParameter | StringLike | NumberLike | Boolean | ESSymbol,
Narrowable = Any | StructuredType | TypeParameter | StringLike | NumberLike | BooleanLike | ESSymbol,
NotUnionOrUnit = Any | String | Number | ESSymbol | ObjectType,
/* @internal */
RequiresWidening = ContainsWideningType | ContainsObjectLiteral,
/* @internal */
@ -2280,6 +2318,8 @@ namespace ts {
/* @internal */ id: number; // Unique ID
symbol?: Symbol; // Symbol associated with type (if any)
pattern?: DestructuringPattern; // Destructuring pattern represented by type (if any)
aliasSymbol?: Symbol; // Alias associated with type
aliasTypeArguments?: Type[]; // Alias type arguments (if any)
}
/* @internal */
@ -2289,10 +2329,20 @@ namespace ts {
}
// String literal types (TypeFlags.StringLiteral)
export interface StringLiteralType extends Type {
export interface LiteralType extends Type {
text: string; // Text of string literal
}
// Enum types (TypeFlags.Enum)
export interface EnumType extends Type {
memberTypes: Map<EnumLiteralType>;
}
// Enum types (TypeFlags.EnumLiteral)
export interface EnumLiteralType extends LiteralType {
baseType: EnumType & UnionType;
}
// Object types (TypeFlags.ObjectType)
export interface ObjectType extends Type { }
@ -2337,14 +2387,15 @@ namespace ts {
export interface TupleType extends ObjectType {
elementTypes: Type[]; // Element types
thisType?: Type; // This-type of tuple (only needed for tuples that are constraints of type parameters)
}
export interface UnionOrIntersectionType extends Type {
types: Type[]; // Constituent types
/* @internal */
reducedType: Type; // Reduced union type (all subtypes removed)
/* @internal */
resolvedProperties: SymbolTable; // Cache of resolved properties
/* @internal */
couldContainTypeParameters: boolean;
}
export interface UnionType extends UnionOrIntersectionType { }
@ -2413,7 +2464,7 @@ namespace ts {
/* @internal */
hasRestParameter: boolean; // True if last parameter is rest parameter
/* @internal */
hasStringLiterals: boolean; // True if specialized
hasLiteralTypes: boolean; // True if specialized
/* @internal */
target?: Signature; // Instantiation target
/* @internal */
@ -2443,6 +2494,7 @@ namespace ts {
export interface TypeMapper {
(t: TypeParameter): Type;
mappedTypes?: Type[]; // Types mapped by this mapper
targetTypes?: Type[]; // Types substituted for mapped types
instantiations?: Type[]; // Cache of instantiations created using this type mapper.
context?: InferenceContext; // The inference context this mapper was created from.
// Only inference mappers have this set (in createInferenceMapper).
@ -2522,7 +2574,7 @@ namespace ts {
}
export type RootPaths = string[];
export type PathSubstitutions = Map<string[]>;
export type PathSubstitutions = MapLike<string[]>;
export type TsConfigOnlyOptions = RootPaths | PathSubstitutions;
export type CompilerOptionsValue = string | number | boolean | (string | number)[] | TsConfigOnlyOptions;
@ -2682,7 +2734,7 @@ namespace ts {
fileNames: string[];
raw?: any;
errors: Diagnostic[];
wildcardDirectories?: Map<WatchDirectoryFlags>;
wildcardDirectories?: MapLike<WatchDirectoryFlags>;
}
export const enum WatchDirectoryFlags {
@ -2692,7 +2744,7 @@ namespace ts {
export interface ExpandResult {
fileNames: string[];
wildcardDirectories: Map<WatchDirectoryFlags>;
wildcardDirectories: MapLike<WatchDirectoryFlags>;
}
/* @internal */
@ -2714,7 +2766,7 @@ namespace ts {
/* @internal */
export interface CommandLineOptionOfCustomType extends CommandLineOptionBase {
type: Map<number | string>; // an object literal mapping named values to actual values
type: Map<number | string>; // an object literal mapping named values to actual values
}
/* @internal */
@ -2877,6 +2929,7 @@ namespace ts {
directoryExists?(directoryName: string): boolean;
realpath?(path: string): string;
getCurrentDirectory?(): string;
getDirectories?(path: string): string[];
}
export interface ResolvedModule {

View File

@ -87,25 +87,6 @@ namespace ts {
return node.end - node.pos;
}
export function mapIsEqualTo<T>(map1: Map<T>, map2: Map<T>): boolean {
if (!map1 || !map2) {
return map1 === map2;
}
return containsAll(map1, map2) && containsAll(map2, map1);
}
function containsAll<T>(map: Map<T>, other: Map<T>): boolean {
for (const key in map) {
if (!hasProperty(map, key)) {
continue;
}
if (!hasProperty(other, key) || map[key] !== other[key]) {
return false;
}
}
return true;
}
export function arrayIsEqualTo<T>(array1: T[], array2: T[], equaler?: (a: T, b: T) => boolean): boolean {
if (!array1 || !array2) {
return array1 === array2;
@ -126,7 +107,7 @@ namespace ts {
}
export function hasResolvedModule(sourceFile: SourceFile, moduleNameText: string): boolean {
return sourceFile.resolvedModules && hasProperty(sourceFile.resolvedModules, moduleNameText);
return !!(sourceFile.resolvedModules && sourceFile.resolvedModules[moduleNameText]);
}
export function getResolvedModule(sourceFile: SourceFile, moduleNameText: string): ResolvedModule {
@ -135,7 +116,7 @@ namespace ts {
export function setResolvedModule(sourceFile: SourceFile, moduleNameText: string, resolvedModule: ResolvedModule): void {
if (!sourceFile.resolvedModules) {
sourceFile.resolvedModules = {};
sourceFile.resolvedModules = createMap<ResolvedModule>();
}
sourceFile.resolvedModules[moduleNameText] = resolvedModule;
@ -143,7 +124,7 @@ namespace ts {
export function setResolvedTypeReferenceDirective(sourceFile: SourceFile, typeReferenceDirectiveName: string, resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective): void {
if (!sourceFile.resolvedTypeReferenceDirectiveNames) {
sourceFile.resolvedTypeReferenceDirectiveNames = {};
sourceFile.resolvedTypeReferenceDirectiveNames = createMap<ResolvedTypeReferenceDirective>();
}
sourceFile.resolvedTypeReferenceDirectiveNames[typeReferenceDirectiveName] = resolvedTypeReferenceDirective;
@ -166,7 +147,7 @@ namespace ts {
}
for (let i = 0; i < names.length; i++) {
const newResolution = newResolutions[i];
const oldResolution = oldResolutions && hasProperty(oldResolutions, names[i]) ? oldResolutions[names[i]] : undefined;
const oldResolution = oldResolutions && oldResolutions[names[i]];
const changed =
oldResolution
? !newResolution || !comparer(oldResolution, newResolution)
@ -1033,14 +1014,14 @@ namespace ts {
&& (<PropertyAccessExpression | ElementAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword;
}
export function getEntityNameFromTypeNode(node: TypeNode): EntityName | Expression {
export function getEntityNameFromTypeNode(node: TypeNode): EntityNameOrEntityNameExpression {
if (node) {
switch (node.kind) {
case SyntaxKind.TypeReference:
return (<TypeReferenceNode>node).typeName;
case SyntaxKind.ExpressionWithTypeArguments:
return (<ExpressionWithTypeArguments>node).expression;
Debug.assert(isEntityNameExpression((<ExpressionWithTypeArguments>node).expression));
return <EntityNameExpression>(<ExpressionWithTypeArguments>node).expression;
case SyntaxKind.Identifier:
case SyntaxKind.QualifiedName:
return (<EntityName><Node>node);
@ -1523,7 +1504,7 @@ namespace ts {
continue;
}
return parent.kind === SyntaxKind.BinaryExpression &&
(<BinaryExpression>parent).operatorToken.kind === SyntaxKind.EqualsToken &&
isAssignmentOperator((<BinaryExpression>parent).operatorToken.kind) &&
(<BinaryExpression>parent).left === node ||
(parent.kind === SyntaxKind.ForInStatement || parent.kind === SyntaxKind.ForOfStatement) &&
(<ForInStatement | ForOfStatement>parent).initializer === node;
@ -1569,6 +1550,7 @@ namespace ts {
case SyntaxKind.MethodSignature:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.NamespaceImport:
case SyntaxKind.NamespaceExportDeclaration:
case SyntaxKind.Parameter:
case SyntaxKind.PropertyAssignment:
case SyntaxKind.PropertyDeclaration:
@ -1693,8 +1675,8 @@ namespace ts {
// import * as <symbol> from ...
// import { x as <symbol> } from ...
// export { x as <symbol> } from ...
// export = ...
// export default ...
// export = <EntityNameExpression>
// export default <EntityNameExpression>
export function isAliasSymbolDeclaration(node: Node): boolean {
return node.kind === SyntaxKind.ImportEqualsDeclaration ||
node.kind === SyntaxKind.NamespaceExportDeclaration ||
@ -1702,7 +1684,11 @@ namespace ts {
node.kind === SyntaxKind.NamespaceImport ||
node.kind === SyntaxKind.ImportSpecifier ||
node.kind === SyntaxKind.ExportSpecifier ||
node.kind === SyntaxKind.ExportAssignment && (<ExportAssignment>node).expression.kind === SyntaxKind.Identifier;
node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(<ExportAssignment>node);
}
export function exportAssignmentIsAlias(node: ExportAssignment): boolean {
return isEntityNameExpression(node.expression);
}
export function getClassExtendsHeritageClauseElement(node: ClassLikeDeclaration | InterfaceDeclaration) {
@ -1965,7 +1951,7 @@ namespace ts {
export function createDiagnosticCollection(): DiagnosticCollection {
let nonFileDiagnostics: Diagnostic[] = [];
const fileDiagnostics: Map<Diagnostic[]> = {};
const fileDiagnostics = createMap<Diagnostic[]>();
let diagnosticsModified = false;
let modificationCount = 0;
@ -1983,12 +1969,11 @@ namespace ts {
}
function reattachFileDiagnostics(newFile: SourceFile): void {
if (!hasProperty(fileDiagnostics, newFile.fileName)) {
return;
}
for (const diagnostic of fileDiagnostics[newFile.fileName]) {
diagnostic.file = newFile;
const diagnostics = fileDiagnostics[newFile.fileName];
if (diagnostics) {
for (const diagnostic of diagnostics) {
diagnostic.file = newFile;
}
}
}
@ -2029,9 +2014,7 @@ namespace ts {
forEach(nonFileDiagnostics, pushDiagnostic);
for (const key in fileDiagnostics) {
if (hasProperty(fileDiagnostics, key)) {
forEach(fileDiagnostics[key], pushDiagnostic);
}
forEach(fileDiagnostics[key], pushDiagnostic);
}
return sortAndDeduplicateDiagnostics(allDiagnostics);
@ -2046,9 +2029,7 @@ namespace ts {
nonFileDiagnostics = sortAndDeduplicateDiagnostics(nonFileDiagnostics);
for (const key in fileDiagnostics) {
if (hasProperty(fileDiagnostics, key)) {
fileDiagnostics[key] = sortAndDeduplicateDiagnostics(fileDiagnostics[key]);
}
fileDiagnostics[key] = sortAndDeduplicateDiagnostics(fileDiagnostics[key]);
}
}
}
@ -2059,7 +2040,7 @@ namespace ts {
// the map below must be updated. Note that this regexp *does not* include the 'delete' character.
// There is no reason for this other than that JSON.stringify does not handle it either.
const escapedCharsRegExp = /[\\\"\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
const escapedCharsMap: Map<string> = {
const escapedCharsMap = createMap({
"\0": "\\0",
"\t": "\\t",
"\v": "\\v",
@ -2072,7 +2053,7 @@ namespace ts {
"\u2028": "\\u2028", // lineSeparator
"\u2029": "\\u2029", // paragraphSeparator
"\u0085": "\\u0085" // nextLine
};
});
/**
@ -2680,22 +2661,9 @@ namespace ts {
isClassLike(node.parent.parent);
}
// Returns false if this heritage clause element's expression contains something unsupported
// (i.e. not a name or dotted name).
export function isSupportedExpressionWithTypeArguments(node: ExpressionWithTypeArguments): boolean {
return isSupportedExpressionWithTypeArgumentsRest(node.expression);
}
function isSupportedExpressionWithTypeArgumentsRest(node: Expression): boolean {
if (node.kind === SyntaxKind.Identifier) {
return true;
}
else if (isPropertyAccessExpression(node)) {
return isSupportedExpressionWithTypeArgumentsRest(node.expression);
}
else {
return false;
}
export function isEntityNameExpression(node: Expression): node is EntityNameExpression {
return node.kind === SyntaxKind.Identifier ||
node.kind === SyntaxKind.PropertyAccessExpression && isEntityNameExpression((<PropertyAccessExpression>node).expression);
}
export function isRightSideOfQualifiedNameOrPropertyAccess(node: Node) {
@ -2805,7 +2773,7 @@ namespace ts {
}
function stringifyObject(value: any) {
return `{${reduceProperties(value, stringifyProperty, "")}}`;
return `{${reduceOwnProperties(value, stringifyProperty, "")}}`;
}
function stringifyProperty(memo: string, value: any, key: string) {

View File

@ -52,7 +52,7 @@ class CompilerBaselineRunner extends RunnerBase {
private makeUnitName(name: string, root: string) {
const path = ts.toPath(name, root, (fileName) => Harness.Compiler.getCanonicalFileName(fileName));
const pathStart = ts.toPath(Harness.IO.getCurrentDirectory(), "", (fileName) => Harness.Compiler.getCanonicalFileName(fileName));
return path.replace(pathStart, "/");
return pathStart ? path.replace(pathStart, "/") : path;
};
public checkTestCodeOutput(fileName: string) {
@ -291,8 +291,8 @@ class CompilerBaselineRunner extends RunnerBase {
const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true);
const fullResults: ts.Map<TypeWriterResult[]> = {};
const pullResults: ts.Map<TypeWriterResult[]> = {};
const fullResults = ts.createMap<TypeWriterResult[]>();
const pullResults = ts.createMap<TypeWriterResult[]>();
for (const sourceFile of allFiles) {
fullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName);

View File

@ -95,14 +95,14 @@ namespace FourSlash {
export import IndentStyle = ts.IndentStyle;
const entityMap: ts.Map<string> = {
const entityMap = ts.createMap({
"&": "&amp;",
"\"": "&quot;",
"'": "&#39;",
"/": "&#47;",
"<": "&lt;",
">": "&gt;"
};
});
export function escapeXmlAttributeValue(s: string) {
return s.replace(/[&<>"'\/]/g, ch => entityMap[ch]);
@ -204,7 +204,7 @@ namespace FourSlash {
public formatCodeOptions: ts.FormatCodeOptions;
private inputFiles: ts.Map<string> = {}; // Map between inputFile's fileName and its content for easily looking up when resolving references
private inputFiles = ts.createMap<string>(); // Map between inputFile's fileName and its content for easily looking up when resolving references
// Add input file which has matched file name with the given reference-file path.
// This is necessary when resolveReference flag is specified
@ -249,6 +249,7 @@ namespace FourSlash {
if (compilationOptions.typeRoots) {
compilationOptions.typeRoots = compilationOptions.typeRoots.map(p => ts.getNormalizedAbsolutePath(p, this.basePath));
}
compilationOptions.skipDefaultLibCheck = true;
const languageServiceAdapter = this.getLanguageServiceAdapter(testType, this.cancellationToken, compilationOptions);
this.languageServiceAdapterHost = languageServiceAdapter.getHost();
@ -300,11 +301,11 @@ namespace FourSlash {
}
else {
// resolveReference file-option is not specified then do not resolve any files and include all inputFiles
ts.forEachKey(this.inputFiles, fileName => {
for (const fileName in this.inputFiles) {
if (!Harness.isDefaultLibraryFile(fileName)) {
this.languageServiceAdapterHost.addScript(fileName, this.inputFiles[fileName], /*isRootFile*/ true);
}
});
}
this.languageServiceAdapterHost.addScript(Harness.Compiler.defaultLibFileName,
Harness.Compiler.getDefaultLibrarySourceFile().text, /*isRootFile*/ false);
}
@ -376,7 +377,7 @@ namespace FourSlash {
public verifyErrorExistsBetweenMarkers(startMarkerName: string, endMarkerName: string, negative: boolean) {
const startMarker = this.getMarkerByName(startMarkerName);
const endMarker = this.getMarkerByName(endMarkerName);
const predicate = function (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) {
const predicate = function(errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) {
return ((errorMinChar === startPos) && (errorLimChar === endPos)) ? true : false;
};
@ -428,12 +429,12 @@ namespace FourSlash {
let predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean;
if (after) {
predicate = function (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) {
predicate = function(errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) {
return ((errorMinChar >= startPos) && (errorLimChar >= startPos)) ? true : false;
};
}
else {
predicate = function (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) {
predicate = function(errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) {
return ((errorMinChar <= startPos) && (errorLimChar <= startPos)) ? true : false;
};
}
@ -458,7 +459,7 @@ namespace FourSlash {
endPos = endMarker.position;
}
errors.forEach(function (error: ts.Diagnostic) {
errors.forEach(function(error: ts.Diagnostic) {
if (predicate(error.start, error.start + error.length, startPos, endPos)) {
exists = true;
}
@ -475,7 +476,7 @@ namespace FourSlash {
Harness.IO.log("Unexpected error(s) found. Error list is:");
}
errors.forEach(function (error: ts.Diagnostic) {
errors.forEach(function(error: ts.Diagnostic) {
Harness.IO.log(" minChar: " + error.start +
", limChar: " + (error.start + error.length) +
", message: " + ts.flattenDiagnosticMessageText(error.messageText, Harness.IO.newLine()) + "\n");
@ -593,9 +594,9 @@ namespace FourSlash {
public noItemsWithSameNameButDifferentKind(): void {
const completions = this.getCompletionListAtCaret();
const uniqueItems: ts.Map<string> = {};
const uniqueItems = ts.createMap<string>();
for (const item of completions.entries) {
if (!ts.hasProperty(uniqueItems, item.name)) {
if (!(item.name in uniqueItems)) {
uniqueItems[item.name] = item.kind;
}
else {
@ -773,7 +774,7 @@ namespace FourSlash {
}
public verifyRangesWithSameTextReferenceEachOther() {
ts.forEachValue(this.rangesByText(), ranges => this.verifyRangesReferenceEachOther(ranges));
ts.forEachProperty(this.rangesByText(), ranges => this.verifyRangesReferenceEachOther(ranges));
}
private verifyReferencesWorker(references: ts.ReferenceEntry[], fileName: string, start: number, end: number, isWriteAccess?: boolean, isDefinition?: boolean) {
@ -1348,14 +1349,7 @@ namespace FourSlash {
}
// Enters lines of text at the current caret position
public type(text: string) {
return this.typeHighFidelity(text);
}
// Enters lines of text at the current caret position, invoking
// language service APIs to mimic Visual Studio's behavior
// as much as possible
private typeHighFidelity(text: string) {
public type(text: string, highFidelity = false) {
let offset = this.currentCaretPosition;
const prevChar = " ";
const checkCadence = (text.length >> 2) + 1;
@ -1364,24 +1358,26 @@ namespace FourSlash {
// Make the edit
const ch = text.charAt(i);
this.languageServiceAdapterHost.editScript(this.activeFile.fileName, offset, offset, ch);
this.languageService.getBraceMatchingAtPosition(this.activeFile.fileName, offset);
if (highFidelity) {
this.languageService.getBraceMatchingAtPosition(this.activeFile.fileName, offset);
}
this.updateMarkersForEdit(this.activeFile.fileName, offset, offset, ch);
offset++;
if (ch === "(" || ch === ",") {
/* Signature help*/
this.languageService.getSignatureHelpItems(this.activeFile.fileName, offset);
}
else if (prevChar === " " && /A-Za-z_/.test(ch)) {
/* Completions */
this.languageService.getCompletionsAtPosition(this.activeFile.fileName, offset);
}
if (highFidelity) {
if (ch === "(" || ch === ",") {
/* Signature help*/
this.languageService.getSignatureHelpItems(this.activeFile.fileName, offset);
}
else if (prevChar === " " && /A-Za-z_/.test(ch)) {
/* Completions */
this.languageService.getCompletionsAtPosition(this.activeFile.fileName, offset);
}
if (i % checkCadence === 0) {
this.checkPostEditInvariants();
// this.languageService.getSyntacticDiagnostics(this.activeFile.fileName);
// this.languageService.getSemanticDiagnostics(this.activeFile.fileName);
if (i % checkCadence === 0) {
this.checkPostEditInvariants();
}
}
// Handle post-keystroke formatting
@ -1389,14 +1385,12 @@ namespace FourSlash {
const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, offset, ch, this.formatCodeOptions);
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();
}
@ -1415,7 +1409,6 @@ namespace FourSlash {
const edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, offset, this.formatCodeOptions);
if (edits.length) {
offset += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true);
this.checkPostEditInvariants();
}
}
@ -1639,10 +1632,11 @@ namespace FourSlash {
}
public rangesByText(): ts.Map<Range[]> {
const result: ts.Map<Range[]> = {};
const result = ts.createMap<Range[]>();
for (const range of this.getRanges()) {
const text = this.rangeText(range);
(ts.getProperty(result, text) || (result[text] = [])).push(range);
const ranges = result[text] || (result[text] = []);
ranges.push(range);
}
return result;
}
@ -1897,7 +1891,7 @@ namespace FourSlash {
public verifyBraceCompletionAtPosition(negative: boolean, openingBrace: string) {
const openBraceMap: ts.Map<ts.CharacterCodes> = {
const openBraceMap = ts.createMap<ts.CharacterCodes>({
"(": ts.CharacterCodes.openParen,
"{": ts.CharacterCodes.openBrace,
"[": ts.CharacterCodes.openBracket,
@ -1905,7 +1899,7 @@ namespace FourSlash {
'"': ts.CharacterCodes.doubleQuote,
"`": ts.CharacterCodes.backtick,
"<": ts.CharacterCodes.lessThan
};
});
const charCode = openBraceMap[openingBrace];
@ -2269,40 +2263,12 @@ namespace FourSlash {
export function runFourSlashTestContent(basePath: string, testType: FourSlashTestType, content: string, fileName: string): void {
// Parse out the files and their metadata
const testData = parseTestData(basePath, content, fileName);
const state = new TestState(basePath, testType, testData);
let result = "";
const fourslashFile: Harness.Compiler.TestFile = {
unitName: Harness.Compiler.fourslashFileName,
content: undefined,
};
const testFile: Harness.Compiler.TestFile = {
unitName: fileName,
content: content
};
const host = Harness.Compiler.createCompilerHost(
[fourslashFile, testFile],
(fn, contents) => result = contents,
ts.ScriptTarget.Latest,
Harness.IO.useCaseSensitiveFileNames(),
Harness.IO.getCurrentDirectory());
const program = ts.createProgram([Harness.Compiler.fourslashFileName, fileName], { outFile: "fourslashTestOutput.js", noResolve: true, target: ts.ScriptTarget.ES3 }, host);
const sourceFile = host.getSourceFile(fileName, ts.ScriptTarget.ES3);
const diagnostics = ts.getPreEmitDiagnostics(program, sourceFile);
if (diagnostics.length > 0) {
throw new Error(`Error compiling ${fileName}: ` +
diagnostics.map(e => ts.flattenDiagnosticMessageText(e.messageText, Harness.IO.newLine())).join("\r\n"));
const output = ts.transpileModule(content, { reportDiagnostics: true });
if (output.diagnostics.length > 0) {
throw new Error(`Syntax error in ${basePath}: ${output.diagnostics[0].messageText}`);
}
program.emit(sourceFile);
ts.Debug.assert(!!result);
runCode(result, state);
runCode(output.outputText, state);
}
function runCode(code: string, state: TestState): void {
@ -2395,13 +2361,14 @@ ${code}
// Comment line, check for global/file @options and record them
const match = optionRegex.exec(line.substr(2));
if (match) {
const fileMetadataNamesIndex = fileMetadataNames.indexOf(match[1]);
const [key, value] = match.slice(1);
const fileMetadataNamesIndex = fileMetadataNames.indexOf(key);
if (fileMetadataNamesIndex === -1) {
// Check if the match is already existed in the global options
if (globalOptions[match[1]] !== undefined) {
throw new Error("Global Option : '" + match[1] + "' is already existed");
if (globalOptions[key] !== undefined) {
throw new Error(`Global option '${key}' already exists`);
}
globalOptions[match[1]] = match[2];
globalOptions[key] = value;
}
else {
if (fileMetadataNamesIndex === fileMetadataNames.indexOf(metadataOptionNames.fileName)) {
@ -2416,12 +2383,12 @@ ${code}
resetLocalData();
}
currentFileName = basePath + "/" + match[2];
currentFileOptions[match[1]] = match[2];
currentFileName = basePath + "/" + value;
currentFileOptions[key] = value;
}
else {
// Add other fileMetadata flag
currentFileOptions[match[1]] = match[2];
currentFileOptions[key] = value;
}
}
}
@ -2509,7 +2476,7 @@ ${code}
}
const marker: Marker = {
fileName: fileName,
fileName,
position: location.position,
data: markerValue
};
@ -2526,7 +2493,7 @@ ${code}
function recordMarker(fileName: string, location: LocationInformation, name: string, markerMap: MarkerMap, markers: Marker[]): Marker {
const marker: Marker = {
fileName: fileName,
fileName,
position: location.position
};

View File

@ -750,7 +750,7 @@ namespace Harness {
export function readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[]) {
const fs = new Utils.VirtualFileSystem(path, useCaseSensitiveFileNames());
for (const file in listFiles(path)) {
for (const file of listFiles(path)) {
fs.addFile(file);
}
return ts.matchFiles(path, extension, exclude, include, useCaseSensitiveFileNames(), getCurrentDirectory(), path => {
@ -848,9 +848,9 @@ namespace Harness {
export const defaultLibFileName = "lib.d.ts";
export const es2015DefaultLibFileName = "lib.es2015.d.ts";
const libFileNameSourceFileMap: ts.Map<ts.SourceFile> = {
const libFileNameSourceFileMap= ts.createMap<ts.SourceFile>({
[defaultLibFileName]: createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + "lib.es5.d.ts"), /*languageVersion*/ ts.ScriptTarget.Latest)
};
});
export function getDefaultLibrarySourceFile(fileName = defaultLibFileName): ts.SourceFile {
if (!isDefaultLibraryFile(fileName)) {
@ -1005,13 +1005,13 @@ namespace Harness {
let optionsIndex: ts.Map<ts.CommandLineOption>;
function getCommandLineOption(name: string): ts.CommandLineOption {
if (!optionsIndex) {
optionsIndex = {};
optionsIndex = ts.createMap<ts.CommandLineOption>();
const optionDeclarations = harnessOptionDeclarations.concat(ts.optionDeclarations);
for (const option of optionDeclarations) {
optionsIndex[option.name.toLowerCase()] = option;
}
}
return ts.lookUp(optionsIndex, name.toLowerCase());
return optionsIndex[name.toLowerCase()];
}
export function setCompilerOptionsFromHarnessSetting(settings: Harness.TestCaseParser.CompilerSettings, options: ts.CompilerOptions & HarnessOptions): void {
@ -1210,18 +1210,7 @@ namespace Harness {
}
export function minimalDiagnosticsToString(diagnostics: ts.Diagnostic[]) {
// This is basically copied from tsc.ts's reportError to replicate what tsc does
let errorOutput = "";
ts.forEach(diagnostics, diagnostic => {
if (diagnostic.file) {
const lineAndCharacter = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
errorOutput += diagnostic.file.fileName + "(" + (lineAndCharacter.line + 1) + "," + (lineAndCharacter.character + 1) + "): ";
}
errorOutput += ts.DiagnosticCategory[diagnostic.category].toLowerCase() + " TS" + diagnostic.code + ": " + ts.flattenDiagnosticMessageText(diagnostic.messageText, Harness.IO.newLine()) + Harness.IO.newLine();
});
return errorOutput;
return ts.formatDiagnostics(diagnostics, { getCanonicalFileName, getCurrentDirectory: () => "", getNewLine: () => Harness.IO.newLine() });
}
export function getErrorBaseline(inputFiles: TestFile[], diagnostics: ts.Diagnostic[]) {
@ -1580,6 +1569,7 @@ namespace Harness {
/** Support class for baseline files */
export namespace Baseline {
const NoContent = "<no content>";
export interface BaselineOptions {
Subfolder?: string;
@ -1646,14 +1636,6 @@ namespace Harness {
throw new Error("The generated content was \"undefined\". Return \"null\" if no baselining is required.\"");
}
// Store the content in the 'local' folder so we
// can accept it later (manually)
/* tslint:disable:no-null-keyword */
if (actual !== null) {
/* tslint:enable:no-null-keyword */
IO.writeFile(actualFileName, actual);
}
return actual;
}
@ -1670,7 +1652,7 @@ namespace Harness {
/* tslint:disable:no-null-keyword */
if (actual === null) {
/* tslint:enable:no-null-keyword */
actual = "<no content>";
actual = NoContent;
}
let expected = "<no content>";
@ -1683,13 +1665,20 @@ namespace Harness {
function writeComparison(expected: string, actual: string, relativeFileName: string, actualFileName: string, descriptionForDescribe: string) {
const encoded_actual = Utils.encodeString(actual);
if (expected != encoded_actual) {
if (expected !== encoded_actual) {
if (actual === NoContent) {
IO.writeFile(localPath(relativeFileName + ".delete"), "");
}
else {
IO.writeFile(localPath(relativeFileName), actual);
}
// Overwrite & issue error
const errMsg = "The baseline file " + relativeFileName + " has changed.";
throw new Error(errMsg);
}
}
export function runBaseline(
descriptionForDescribe: string,
relativeFileName: string,

View File

@ -123,7 +123,7 @@ namespace Harness.LanguageService {
}
export class LanguageServiceAdapterHost {
protected fileNameToScript: ts.Map<ScriptInfo> = {};
protected fileNameToScript = ts.createMap<ScriptInfo>();
constructor(protected cancellationToken = DefaultHostCancellationToken.Instance,
protected settings = ts.getDefaultCompilerOptions()) {
@ -135,7 +135,7 @@ namespace Harness.LanguageService {
public getFilenames(): string[] {
const fileNames: string[] = [];
ts.forEachValue(this.fileNameToScript, (scriptInfo) => {
ts.forEachProperty(this.fileNameToScript, (scriptInfo) => {
if (scriptInfo.isRootFile) {
// only include root files here
// usually it means that we won't include lib.d.ts in the list of root files so it won't mess the computation of compilation root dir.
@ -146,7 +146,7 @@ namespace Harness.LanguageService {
}
public getScriptInfo(fileName: string): ScriptInfo {
return ts.lookUp(this.fileNameToScript, fileName);
return this.fileNameToScript[fileName];
}
public addScript(fileName: string, content: string, isRootFile: boolean): void {
@ -235,7 +235,7 @@ namespace Harness.LanguageService {
this.getModuleResolutionsForFile = (fileName) => {
const scriptInfo = this.getScriptInfo(fileName);
const preprocessInfo = ts.preProcessFile(scriptInfo.content, /*readImportFiles*/ true);
const imports: ts.Map<string> = {};
const imports = ts.createMap<string>();
for (const module of preprocessInfo.importedFiles) {
const resolutionInfo = ts.resolveModuleName(module.fileName, fileName, compilerOptions, moduleResolutionHost);
if (resolutionInfo.resolvedModule) {
@ -248,7 +248,7 @@ namespace Harness.LanguageService {
const scriptInfo = this.getScriptInfo(fileName);
if (scriptInfo) {
const preprocessInfo = ts.preProcessFile(scriptInfo.content, /*readImportFiles*/ false);
const resolutions: ts.Map<ts.ResolvedTypeReferenceDirective> = {};
const resolutions = ts.createMap<ts.ResolvedTypeReferenceDirective>();
const settings = this.nativeHost.getCompilationSettings();
for (const typeReferenceDirective of preprocessInfo.typeReferenceDirectives) {
const resolutionInfo = ts.resolveTypeReferenceDirective(typeReferenceDirective.fileName, fileName, settings, moduleResolutionHost);

View File

@ -209,7 +209,7 @@ namespace Playback {
memoize(path => findResultByFields(replayLog.pathsResolved, { path }, !ts.isRootedDiskPath(ts.normalizeSlashes(path)) && replayLog.currentDirectory ? replayLog.currentDirectory + "/" + path : ts.normalizeSlashes(path))));
wrapper.readFile = recordReplay(wrapper.readFile, underlying)(
path => {
(path: string) => {
const result = underlying.readFile(path);
const logEntry = { path, codepage: 0, result: { contents: result, codepage: 0 } };
recordLog.filesRead.push(logEntry);

View File

@ -253,18 +253,15 @@ class ProjectRunner extends RunnerBase {
moduleResolution: ts.ModuleResolutionKind.Classic, // currently all tests use classic module resolution kind, this will change in the future
};
// Set the values specified using json
const optionNameMap: ts.Map<ts.CommandLineOption> = {};
ts.forEach(ts.optionDeclarations, option => {
optionNameMap[option.name] = option;
});
const optionNameMap = ts.arrayToMap(ts.optionDeclarations, option => option.name);
for (const name in testCase) {
if (name !== "mapRoot" && name !== "sourceRoot" && ts.hasProperty(optionNameMap, name)) {
if (name !== "mapRoot" && name !== "sourceRoot" && name in optionNameMap) {
const option = optionNameMap[name];
const optType = option.type;
let value = <any>testCase[name];
if (typeof optType !== "string") {
const key = value.toLowerCase();
if (ts.hasProperty(optType, key)) {
if (key in optType) {
value = optType[key];
}
}

View File

@ -198,7 +198,8 @@ namespace RWC {
}
// Do not include the library in the baselines to avoid noise
const baselineFiles = inputFiles.concat(otherFiles).filter(f => !Harness.isDefaultLibraryFile(f.unitName));
return Harness.Compiler.getErrorBaseline(baselineFiles, compilerResult.errors);
const errors = compilerResult.errors.filter(e => !Harness.isDefaultLibraryFile(e.file.fileName));
return Harness.Compiler.getErrorBaseline(baselineFiles, errors);
}, false, baselineOpts);
});

View File

@ -89,6 +89,7 @@
"./unittests/convertCompilerOptionsFromJson.ts",
"./unittests/convertTypingOptionsFromJson.ts",
"./unittests/tsserverProjectSystem.ts",
"./unittests/matchFiles.ts"
"./unittests/matchFiles.ts",
"./unittests/initializeTSConfig.ts"
]
}

View File

@ -7,16 +7,16 @@ namespace ts {
}
function createDefaultServerHost(fileMap: Map<File>): server.ServerHost {
const existingDirectories: Map<boolean> = {};
forEachValue(fileMap, v => {
let dir = getDirectoryPath(v.name);
const existingDirectories = createMap<boolean>();
for (const name in fileMap) {
let dir = getDirectoryPath(name);
let previous: string;
do {
existingDirectories[dir] = true;
previous = dir;
dir = getDirectoryPath(dir);
} while (dir !== previous);
});
}
return {
args: <string[]>[],
newLine: "\r\n",
@ -24,7 +24,7 @@ namespace ts {
write: (s: string) => {
},
readFile: (path: string, encoding?: string): string => {
return hasProperty(fileMap, path) && fileMap[path].content;
return path in fileMap ? fileMap[path].content : undefined;
},
writeFile: (path: string, data: string, writeByteOrderMark?: boolean) => {
throw new Error("NYI");
@ -33,10 +33,10 @@ namespace ts {
throw new Error("NYI");
},
fileExists: (path: string): boolean => {
return hasProperty(fileMap, path);
return path in fileMap;
},
directoryExists: (path: string): boolean => {
return hasProperty(existingDirectories, path);
return existingDirectories[path] || false;
},
createDirectory: (path: string) => {
},
@ -101,7 +101,7 @@ namespace ts {
content: `foo()`
};
const serverHost = createDefaultServerHost({ [root.name]: root, [imported.name]: imported });
const serverHost = createDefaultServerHost(createMap({ [root.name]: root, [imported.name]: imported }));
const { project, rootScriptInfo } = createProject(root.name, serverHost);
// ensure that imported file was found
@ -193,7 +193,7 @@ namespace ts {
content: `export var y = 1`
};
const fileMap: Map<File> = { [root.name]: root };
const fileMap = createMap({ [root.name]: root });
const serverHost = createDefaultServerHost(fileMap);
const originalFileExists = serverHost.fileExists;

View File

@ -0,0 +1,44 @@
/// <reference path="..\harness.ts" />
/// <reference path="..\..\compiler\commandLineParser.ts" />
namespace ts {
describe("initTSConfig", () => {
function initTSConfigCorrectly(name: string, commandLinesArgs: string[]) {
describe(name, () => {
const commandLine = parseCommandLine(commandLinesArgs);
const initResult = generateTSConfig(commandLine.options, commandLine.fileNames);
const outputFileName = `tsConfig/${name.replace(/[^a-z0-9\-. ]/ig, "")}/tsconfig.json`;
it(`Correct output for ${outputFileName}`, () => {
Harness.Baseline.runBaseline("Correct output", outputFileName, () => {
if (initResult) {
return JSON.stringify(initResult, undefined, 4);
}
else {
// This can happen if compiler recieve invalid compiler-options
/* tslint:disable:no-null-keyword */
return null;
/* tslint:enable:no-null-keyword */
}
});
});
});
}
initTSConfigCorrectly("Default initialized TSConfig", ["--init"]);
initTSConfigCorrectly("Initialized TSConfig with files options", ["--init", "file0.st", "file1.ts", "file2.ts"]);
initTSConfigCorrectly("Initialized TSConfig with boolean value compiler options", ["--init", "--noUnusedLocals"]);
initTSConfigCorrectly("Initialized TSConfig with enum value compiler options", ["--init", "--target", "es5", "--jsx", "react"]);
initTSConfigCorrectly("Initialized TSConfig with list compiler options", ["--init", "--types", "jquery,mocha"]);
initTSConfigCorrectly("Initialized TSConfig with list compiler options with enum value", ["--init", "--lib", "es5,es2015.core"]);
initTSConfigCorrectly("Initialized TSConfig with incorrect compiler option", ["--init", "--someNonExistOption"]);
initTSConfigCorrectly("Initialized TSConfig with incorrect compiler option value", ["--init", "--lib", "nonExistLib,es5,es2015.promise"]);
});
}

View File

@ -23,6 +23,8 @@ namespace ts {
"c:/dev/x/y/b.ts",
"c:/dev/js/a.js",
"c:/dev/js/b.js",
"c:/dev/js/d.min.js",
"c:/dev/js/ab.min.js",
"c:/ext/ext.ts",
"c:/ext/b/a..b.ts"
]);
@ -75,6 +77,17 @@ namespace ts {
"c:/dev/jspm_packages/a.ts"
]);
const caseInsensitiveDottedFoldersHost = new Utils.MockParseConfigHost(caseInsensitiveBasePath, /*useCaseSensitiveFileNames*/ false, [
"c:/dev/x/d.ts",
"c:/dev/x/y/d.ts",
"c:/dev/x/y/.e.ts",
"c:/dev/x/.y/a.ts",
"c:/dev/.z/.b.ts",
"c:/dev/.z/c.ts",
"c:/dev/w/.u/e.ts",
"c:/dev/g.min.js/.g/g.ts"
]);
describe("matchFiles", () => {
describe("with literal file list", () => {
it("without exclusions", () => {
@ -726,6 +739,33 @@ namespace ts {
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
it("include explicitly listed .min.js files when allowJs=true", () => {
const json = {
compilerOptions: {
allowJs: true
},
include: [
"js/*.min.js"
]
};
const expected: ts.ParsedCommandLine = {
options: {
allowJs: true
},
errors: [],
fileNames: [
"c:/dev/js/ab.min.js",
"c:/dev/js/d.min.js"
],
wildcardDirectories: {
"c:/dev/js": ts.WatchDirectoryFlags.None
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
it("include paths outside of the project", () => {
const json = {
include: [
@ -951,6 +991,35 @@ namespace ts {
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
it("exclude .min.js files using wildcards", () => {
const json = {
compilerOptions: {
allowJs: true
},
include: [
"js/*.min.js"
],
exclude: [
"js/a*"
]
};
const expected: ts.ParsedCommandLine = {
options: {
allowJs: true
},
errors: [],
fileNames: [
"c:/dev/js/d.min.js"
],
wildcardDirectories: {
"c:/dev/js": ts.WatchDirectoryFlags.None
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
describe("with trailing recursive directory", () => {
it("in includes", () => {
const json = {
@ -1145,5 +1214,122 @@ namespace ts {
});
});
});
describe("with files or folders that begin with a .", () => {
it("that are not explicitly included", () => {
const json = {
include: [
"x/**/*",
"w/*/*"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [
"c:/dev/x/d.ts",
"c:/dev/x/y/d.ts",
],
wildcardDirectories: {
"c:/dev/x": ts.WatchDirectoryFlags.Recursive,
"c:/dev/w": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
describe("that are explicitly included", () => {
it("without wildcards", () => {
const json = {
include: [
"x/.y/a.ts",
"c:/dev/.z/.b.ts"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [
"c:/dev/.z/.b.ts",
"c:/dev/x/.y/a.ts"
],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
it("with recursive wildcards that match directories", () => {
const json = {
include: [
"**/.*/*"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [
"c:/dev/.z/c.ts",
"c:/dev/g.min.js/.g/g.ts",
"c:/dev/w/.u/e.ts",
"c:/dev/x/.y/a.ts"
],
wildcardDirectories: {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
it("with recursive wildcards that match nothing", () => {
const json = {
include: [
"x/**/.y/*",
".z/**/.*"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [
"c:/dev/.z/.b.ts",
"c:/dev/x/.y/a.ts"
],
wildcardDirectories: {
"c:/dev/.z": ts.WatchDirectoryFlags.Recursive,
"c:/dev/x": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
it("with wildcard excludes that implicitly exclude dotted files", () => {
const json = {
include: [
"**/.*/*"
],
exclude: [
"**/*"
]
};
const expected: ts.ParsedCommandLine = {
options: {},
errors: [],
fileNames: [],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
});
});
});
});
}

View File

@ -1,21 +1,6 @@
/// <reference path="..\harness.ts" />
namespace ts {
function diagnosticToString(diagnostic: Diagnostic) {
let output = "";
if (diagnostic.file) {
const loc = getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start);
output += `${diagnostic.file.fileName}(${loc.line + 1},${loc.character + 1}): `;
}
const category = DiagnosticCategory[diagnostic.category].toLowerCase();
output += `${category} TS${diagnostic.code}: ${flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine)}${sys.newLine}`;
return output;
}
interface File {
name: string;
content?: string;
@ -25,7 +10,7 @@ namespace ts {
const map = arrayToMap(files, f => f.name);
if (hasDirectoryExists) {
const directories: Map<string> = {};
const directories = createMap<string>();
for (const f of files) {
let name = getDirectoryPath(f.name);
while (true) {
@ -40,19 +25,19 @@ namespace ts {
return {
readFile,
directoryExists: path => {
return hasProperty(directories, path);
return path in directories;
},
fileExists: path => {
assert.isTrue(hasProperty(directories, getDirectoryPath(path)), `'fileExists' '${path}' request in non-existing directory`);
return hasProperty(map, path);
assert.isTrue(getDirectoryPath(path) in directories, `'fileExists' '${path}' request in non-existing directory`);
return path in map;
}
};
}
else {
return { readFile, fileExists: path => hasProperty(map, path), };
return { readFile, fileExists: path => path in map, };
}
function readFile(path: string): string {
return hasProperty(map, path) ? map[path].content : undefined;
return path in map ? map[path].content : undefined;
}
}
@ -302,7 +287,7 @@ namespace ts {
const host: CompilerHost = {
getSourceFile: (fileName: string, languageVersion: ScriptTarget) => {
const path = normalizePath(combinePaths(currentDirectory, fileName));
return hasProperty(files, path) ? createSourceFile(fileName, files[path], languageVersion) : undefined;
return path in files ? createSourceFile(fileName, files[path], languageVersion) : undefined;
},
getDefaultLibFileName: () => "lib.d.ts",
writeFile: (fileName, content): void => { throw new Error("NotImplemented"); },
@ -313,7 +298,7 @@ namespace ts {
useCaseSensitiveFileNames: () => false,
fileExists: fileName => {
const path = normalizePath(combinePaths(currentDirectory, fileName));
return hasProperty(files, path);
return path in files;
},
readFile: (fileName): string => { throw new Error("NotImplemented"); }
};
@ -322,9 +307,9 @@ namespace ts {
assert.equal(program.getSourceFiles().length, expectedFilesCount);
const syntacticDiagnostics = program.getSyntacticDiagnostics();
assert.equal(syntacticDiagnostics.length, 0, `expect no syntactic diagnostics, got: ${JSON.stringify(syntacticDiagnostics.map(diagnosticToString))}`);
assert.equal(syntacticDiagnostics.length, 0, `expect no syntactic diagnostics, got: ${JSON.stringify(Harness.Compiler.minimalDiagnosticsToString(syntacticDiagnostics))}`);
const semanticDiagnostics = program.getSemanticDiagnostics();
assert.equal(semanticDiagnostics.length, 0, `expect no semantic diagnostics, got: ${JSON.stringify(semanticDiagnostics.map(diagnosticToString))}`);
assert.equal(semanticDiagnostics.length, 0, `expect no semantic diagnostics, got: ${JSON.stringify(Harness.Compiler.minimalDiagnosticsToString(semanticDiagnostics))}`);
// try to get file using a relative name
for (const relativeFileName of relativeNamesToCheck) {
@ -333,7 +318,7 @@ namespace ts {
}
it("should find all modules", () => {
const files: Map<string> = {
const files = createMap({
"/a/b/c/first/shared.ts": `
class A {}
export = A`,
@ -347,23 +332,23 @@ import Shared = require('../first/shared');
class C {}
export = C;
`
};
});
test(files, "/a/b/c/first/second", ["class_a.ts"], 3, ["../../../c/third/class_c.ts"]);
});
it("should find modules in node_modules", () => {
const files: Map<string> = {
const files = createMap({
"/parent/node_modules/mod/index.d.ts": "export var x",
"/parent/app/myapp.ts": `import {x} from "mod"`
};
});
test(files, "/parent/app", ["myapp.ts"], 2, []);
});
it("should find file referenced via absolute and relative names", () => {
const files: Map<string> = {
const files = createMap({
"/a/b/c.ts": `/// <reference path="b.ts"/>`,
"/a/b/b.ts": "var x"
};
});
test(files, "/a/b", ["c.ts", "/a/b/b.ts"], 2, []);
});
});
@ -373,11 +358,7 @@ export = C;
function test(files: Map<string>, options: CompilerOptions, currentDirectory: string, useCaseSensitiveFileNames: boolean, rootFiles: string[], diagnosticCodes: number[]): void {
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
if (!useCaseSensitiveFileNames) {
const f: Map<string> = {};
for (const fileName in files) {
f[getCanonicalFileName(fileName)] = files[fileName];
}
files = f;
files = reduceProperties(files, (files, file, fileName) => (files[getCanonicalFileName(fileName)] = file, files), createMap<string>());
}
const host: CompilerHost = {
@ -386,7 +367,7 @@ export = C;
return library;
}
const path = getCanonicalFileName(normalizePath(combinePaths(currentDirectory, fileName)));
return hasProperty(files, path) ? createSourceFile(fileName, files[path], languageVersion) : undefined;
return path in files ? createSourceFile(fileName, files[path], languageVersion) : undefined;
},
getDefaultLibFileName: () => "lib.d.ts",
writeFile: (fileName, content): void => { throw new Error("NotImplemented"); },
@ -397,70 +378,70 @@ export = C;
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
fileExists: fileName => {
const path = getCanonicalFileName(normalizePath(combinePaths(currentDirectory, fileName)));
return hasProperty(files, path);
return path in files;
},
readFile: (fileName): string => { throw new Error("NotImplemented"); }
};
const program = createProgram(rootFiles, options, host);
const diagnostics = sortAndDeduplicateDiagnostics(program.getSemanticDiagnostics().concat(program.getOptionsDiagnostics()));
assert.equal(diagnostics.length, diagnosticCodes.length, `Incorrect number of expected diagnostics, expected ${diagnosticCodes.length}, got '${map(diagnostics, diagnosticToString).join("\r\n")}'`);
assert.equal(diagnostics.length, diagnosticCodes.length, `Incorrect number of expected diagnostics, expected ${diagnosticCodes.length}, got '${Harness.Compiler.minimalDiagnosticsToString(diagnostics)}'`);
for (let i = 0; i < diagnosticCodes.length; i++) {
assert.equal(diagnostics[i].code, diagnosticCodes[i], `Expected diagnostic code ${diagnosticCodes[i]}, got '${diagnostics[i].code}': '${diagnostics[i].messageText}'`);
}
}
it("should succeed when the same file is referenced using absolute and relative names", () => {
const files: Map<string> = {
const files = createMap({
"/a/b/c.ts": `/// <reference path="d.ts"/>`,
"/a/b/d.ts": "var x"
};
});
test(files, { module: ts.ModuleKind.AMD }, "/a/b", /*useCaseSensitiveFileNames*/ false, ["c.ts", "/a/b/d.ts"], []);
});
it("should fail when two files used in program differ only in casing (tripleslash references)", () => {
const files: Map<string> = {
const files = createMap({
"/a/b/c.ts": `/// <reference path="D.ts"/>`,
"/a/b/d.ts": "var x"
};
});
test(files, { module: ts.ModuleKind.AMD, forceConsistentCasingInFileNames: true }, "/a/b", /*useCaseSensitiveFileNames*/ false, ["c.ts", "d.ts"], [1149]);
});
it("should fail when two files used in program differ only in casing (imports)", () => {
const files: Map<string> = {
const files = createMap({
"/a/b/c.ts": `import {x} from "D"`,
"/a/b/d.ts": "export var x"
};
});
test(files, { module: ts.ModuleKind.AMD, forceConsistentCasingInFileNames: true }, "/a/b", /*useCaseSensitiveFileNames*/ false, ["c.ts", "d.ts"], [1149]);
});
it("should fail when two files used in program differ only in casing (imports, relative module names)", () => {
const files: Map<string> = {
const files = createMap({
"moduleA.ts": `import {x} from "./ModuleB"`,
"moduleB.ts": "export var x"
};
});
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "", /*useCaseSensitiveFileNames*/ false, ["moduleA.ts", "moduleB.ts"], [1149]);
});
it("should fail when two files exist on disk that differs only in casing", () => {
const files: Map<string> = {
const files = createMap({
"/a/b/c.ts": `import {x} from "D"`,
"/a/b/D.ts": "export var x",
"/a/b/d.ts": "export var y"
};
});
test(files, { module: ts.ModuleKind.AMD }, "/a/b", /*useCaseSensitiveFileNames*/ true, ["c.ts", "d.ts"], [1149]);
});
it("should fail when module name in 'require' calls has inconsistent casing", () => {
const files: Map<string> = {
const files = createMap({
"moduleA.ts": `import a = require("./ModuleC")`,
"moduleB.ts": `import a = require("./moduleC")`,
"moduleC.ts": "export var x"
};
});
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "", /*useCaseSensitiveFileNames*/ false, ["moduleA.ts", "moduleB.ts", "moduleC.ts"], [1149, 1149]);
});
it("should fail when module names in 'require' calls has inconsistent casing and current directory has uppercase chars", () => {
const files: Map<string> = {
const files = createMap({
"/a/B/c/moduleA.ts": `import a = require("./ModuleC")`,
"/a/B/c/moduleB.ts": `import a = require("./moduleC")`,
"/a/B/c/moduleC.ts": "export var x",
@ -468,11 +449,11 @@ export = C;
import a = require("./moduleA.ts");
import b = require("./moduleB.ts");
`
};
});
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "/a/B/c", /*useCaseSensitiveFileNames*/ false, ["moduleD.ts"], [1149]);
});
it("should not fail when module names in 'require' calls has consistent casing and current directory has uppercase chars", () => {
const files: Map<string> = {
const files = createMap({
"/a/B/c/moduleA.ts": `import a = require("./moduleC")`,
"/a/B/c/moduleB.ts": `import a = require("./moduleC")`,
"/a/B/c/moduleC.ts": "export var x",
@ -480,7 +461,7 @@ import b = require("./moduleB.ts");
import a = require("./moduleA.ts");
import b = require("./moduleB.ts");
`
};
});
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "/a/B/c", /*useCaseSensitiveFileNames*/ false, ["moduleD.ts"], []);
});
});
@ -1038,7 +1019,7 @@ import b = require("./moduleB.ts");
const names = map(files, f => f.name);
const sourceFiles = arrayToMap(map(files, f => createSourceFile(f.name, f.content, ScriptTarget.ES6)), f => f.fileName);
const compilerHost: CompilerHost = {
fileExists : fileName => hasProperty(sourceFiles, fileName),
fileExists : fileName => fileName in sourceFiles,
getSourceFile: fileName => sourceFiles[fileName],
getDefaultLibFileName: () => "lib.d.ts",
writeFile(file, text) {
@ -1049,7 +1030,7 @@ import b = require("./moduleB.ts");
getCanonicalFileName: f => f.toLowerCase(),
getNewLine: () => "\r\n",
useCaseSensitiveFileNames: () => false,
readFile: fileName => hasProperty(sourceFiles, fileName) ? sourceFiles[fileName].text : undefined
readFile: fileName => fileName in sourceFiles ? sourceFiles[fileName].text : undefined
};
const program1 = createProgram(names, {}, compilerHost);
const diagnostics1 = program1.getFileProcessingDiagnostics().getDiagnostics();

View File

@ -95,13 +95,14 @@ namespace ts {
}
}
function createSourceFileWithText(fileName: string, sourceText: SourceText, target: ScriptTarget) {
const file = <SourceFileWithText>createSourceFile(fileName, sourceText.getFullText(), target);
file.sourceText = sourceText;
return file;
}
function createTestCompilerHost(texts: NamedSourceText[], target: ScriptTarget): CompilerHost {
const files: Map<SourceFileWithText> = {};
for (const t of texts) {
const file = <SourceFileWithText>createSourceFile(t.name, t.text.getFullText(), target);
file.sourceText = t.text;
files[t.name] = file;
}
const files = arrayToMap(texts, t => t.name, t => createSourceFileWithText(t.name, t.text, target));
return {
getSourceFile(fileName): SourceFile {
@ -128,10 +129,9 @@ namespace ts {
getNewLine(): string {
return sys ? sys.newLine : newLine;
},
fileExists: fileName => hasProperty(files, fileName),
fileExists: fileName => fileName in files,
readFile: fileName => {
const file = lookUp(files, fileName);
return file && file.text;
return fileName in files ? files[fileName].text : undefined;
}
};
}
@ -152,29 +152,29 @@ namespace ts {
return program;
}
function getSizeOfMap(map: Map<any>): number {
let size = 0;
for (const id in map) {
if (hasProperty(map, id)) {
size++;
function checkResolvedModule(expected: ResolvedModule, actual: ResolvedModule): 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.isExternalLibraryImport === actual.isExternalLibraryImport, `'isExternalLibraryImport': expected '${expected.isExternalLibraryImport}' to be equal to '${actual.isExternalLibraryImport}'`);
}
return true;
}
return size;
return false;
}
function checkResolvedModule(expected: ResolvedModule, actual: ResolvedModule): void {
assert.isTrue(actual !== undefined);
assert.isTrue(expected.resolvedFileName === actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
assert.isTrue(expected.isExternalLibraryImport === actual.isExternalLibraryImport, `'isExternalLibraryImport': expected '${expected.isExternalLibraryImport}' to be equal to '${actual.isExternalLibraryImport}'`);
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}'`);
}
return true;
}
return false;
}
function checkResolvedTypeDirective(expected: ResolvedTypeReferenceDirective, actual: ResolvedTypeReferenceDirective): void {
assert.isTrue(actual !== undefined);
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}'`);
}
function checkCache<T>(caption: string, program: Program, fileName: string, expectedContent: Map<T>, getCache: (f: SourceFile) => Map<T>, entryChecker: (expected: T, original: T) => void): void {
function checkCache<T>(caption: string, program: Program, fileName: string, expectedContent: Map<T>, getCache: (f: SourceFile) => Map<T>, entryChecker: (expected: T, original: T) => boolean): void {
const file = program.getSourceFile(fileName);
assert.isTrue(file !== undefined, `cannot find file ${fileName}`);
const cache = getCache(file);
@ -183,23 +183,7 @@ namespace ts {
}
else {
assert.isTrue(cache !== undefined, `expected ${caption} to be set`);
const actualCacheSize = getSizeOfMap(cache);
const expectedSize = getSizeOfMap(expectedContent);
assert.isTrue(actualCacheSize === expectedSize, `expected actual size: ${actualCacheSize} to be equal to ${expectedSize}`);
for (const id in expectedContent) {
if (hasProperty(expectedContent, id)) {
if (expectedContent[id]) {
const expected = expectedContent[id];
const actual = cache[id];
entryChecker(expected, actual);
}
}
else {
assert.isTrue(cache[id] === undefined);
}
}
assert.isTrue(equalOwnProperties(expectedContent, cache, entryChecker), `contents of ${caption} did not match the expected contents.`);
}
}
@ -313,6 +297,8 @@ namespace ts {
});
it("resolution cache follows imports", () => {
(<any>Error).stackTraceLimit = Infinity;
const files = [
{ name: "a.ts", text: SourceText.New("", "import {_} from 'b'", "var x = 1") },
{ name: "b.ts", text: SourceText.New("", "", "var y = 2") },
@ -320,7 +306,7 @@ namespace ts {
const options: CompilerOptions = { target };
const program_1 = newProgram(files, ["a.ts"], options);
checkResolvedModulesCache(program_1, "a.ts", { "b": { resolvedFileName: "b.ts" } });
checkResolvedModulesCache(program_1, "a.ts", createMap({ "b": { resolvedFileName: "b.ts" } }));
checkResolvedModulesCache(program_1, "b.ts", undefined);
const program_2 = updateProgram(program_1, ["a.ts"], options, files => {
@ -329,7 +315,7 @@ namespace ts {
assert.isTrue(program_1.structureIsReused);
// content of resolution cache should not change
checkResolvedModulesCache(program_1, "a.ts", { "b": { resolvedFileName: "b.ts" } });
checkResolvedModulesCache(program_1, "a.ts", createMap({ "b": { resolvedFileName: "b.ts" } }));
checkResolvedModulesCache(program_1, "b.ts", undefined);
// imports has changed - program is not reused
@ -346,7 +332,7 @@ namespace ts {
files[0].text = files[0].text.updateImportsAndExports(newImports);
});
assert.isTrue(!program_3.structureIsReused);
checkResolvedModulesCache(program_4, "a.ts", { "b": { resolvedFileName: "b.ts" }, "c": undefined });
checkResolvedModulesCache(program_4, "a.ts", createMap({ "b": { resolvedFileName: "b.ts" }, "c": undefined }));
});
it("resolved type directives cache follows type directives", () => {
@ -357,7 +343,7 @@ namespace ts {
const options: CompilerOptions = { target, typeRoots: ["/types"] };
const program_1 = newProgram(files, ["/a.ts"], options);
checkResolvedTypeDirectivesCache(program_1, "/a.ts", { "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } });
checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMap({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
checkResolvedTypeDirectivesCache(program_1, "/types/typedefs/index.d.ts", undefined);
const program_2 = updateProgram(program_1, ["/a.ts"], options, files => {
@ -366,7 +352,7 @@ namespace ts {
assert.isTrue(program_1.structureIsReused);
// content of resolution cache should not change
checkResolvedTypeDirectivesCache(program_1, "/a.ts", { "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } });
checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMap({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
checkResolvedTypeDirectivesCache(program_1, "/types/typedefs/index.d.ts", undefined);
// type reference directives has changed - program is not reused
@ -384,7 +370,7 @@ namespace ts {
files[0].text = files[0].text.updateReferences(newReferences);
});
assert.isTrue(!program_3.structureIsReused);
checkResolvedTypeDirectivesCache(program_1, "/a.ts", { "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } });
checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMap({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
});
});

View File

@ -106,7 +106,7 @@ namespace ts.server {
describe("onMessage", () => {
it("should not throw when commands are executed with invalid arguments", () => {
let i = 0;
for (name in CommandNames) {
for (const name in CommandNames) {
if (!Object.prototype.hasOwnProperty.call(CommandNames, name)) {
continue;
}
@ -362,13 +362,13 @@ namespace ts.server {
class InProcClient {
private server: InProcSession;
private seq = 0;
private callbacks: ts.Map<(resp: protocol.Response) => void> = {};
private eventHandlers: ts.Map<(args: any) => void> = {};
private callbacks = createMap<(resp: protocol.Response) => void>();
private eventHandlers = createMap<(args: any) => void>();
handle(msg: protocol.Message): void {
if (msg.type === "response") {
const response = <protocol.Response>msg;
if (this.callbacks[response.request_seq]) {
if (response.request_seq in this.callbacks) {
this.callbacks[response.request_seq](response);
delete this.callbacks[response.request_seq];
}
@ -380,7 +380,7 @@ namespace ts.server {
}
emit(name: string, args: any): void {
if (this.eventHandlers[name]) {
if (name in this.eventHandlers) {
this.eventHandlers[name](args);
}
}

View File

@ -1,185 +1,185 @@
/// <reference path="..\harness.ts" />
/// <reference path="..\..\compiler\commandLineParser.ts" />
namespace ts {
describe("parseConfigFileTextToJson", () => {
function assertParseResult(jsonText: string, expectedConfigObject: { config?: any; error?: Diagnostic }) {
const parsed = ts.parseConfigFileTextToJson("/apath/tsconfig.json", jsonText);
assert.equal(JSON.stringify(parsed), JSON.stringify(expectedConfigObject));
}
function assertParseError(jsonText: string) {
const parsed = ts.parseConfigFileTextToJson("/apath/tsconfig.json", jsonText);
assert.isTrue(undefined === parsed.config);
assert.isTrue(undefined !== parsed.error);
}
function assertParseErrorWithExcludesKeyword(jsonText: string) {
const parsed = ts.parseConfigFileTextToJson("/apath/tsconfig.json", jsonText);
const parsedCommand = ts.parseJsonConfigFileContent(parsed.config, ts.sys, "tests/cases/unittests");
assert.isTrue(parsedCommand.errors && parsedCommand.errors.length === 1 &&
parsedCommand.errors[0].code === ts.Diagnostics.Unknown_option_excludes_Did_you_mean_exclude.code);
}
function assertParseFileList(jsonText: string, configFileName: string, basePath: string, allFileList: string[], expectedFileList: string[]) {
const json = JSON.parse(jsonText);
const host: ParseConfigHost = new Utils.MockParseConfigHost(basePath, true, allFileList);
const parsed = ts.parseJsonConfigFileContent(json, host, basePath, /*existingOptions*/ undefined, configFileName);
assert.isTrue(arrayIsEqualTo(parsed.fileNames.sort(), expectedFileList.sort()));
}
it("returns empty config for file with only whitespaces", () => {
assertParseResult("", { config : {} });
assertParseResult(" ", { config : {} });
});
it("returns empty config for file with comments only", () => {
assertParseResult("// Comment", { config: {} });
assertParseResult("/* Comment*/", { config: {} });
});
it("returns empty config when config is empty object", () => {
assertParseResult("{}", { config: {} });
});
it("returns config object without comments", () => {
assertParseResult(
`{ // Excluded files
"exclude": [
// Exclude d.ts
"file.d.ts"
]
}`, { config: { exclude: ["file.d.ts"] } });
assertParseResult(
`{
/* Excluded
Files
*/
"exclude": [
/* multiline comments can be in the middle of a line */"file.d.ts"
]
}`, { config: { exclude: ["file.d.ts"] } });
});
it("keeps string content untouched", () => {
assertParseResult(
`{
"exclude": [
"xx//file.d.ts"
]
}`, { config: { exclude: ["xx//file.d.ts"] } });
assertParseResult(
`{
"exclude": [
"xx/*file.d.ts*/"
]
}`, { config: { exclude: ["xx/*file.d.ts*/"] } });
});
it("handles escaped characters in strings correctly", () => {
assertParseResult(
`{
"exclude": [
"xx\\"//files"
]
}`, { config: { exclude: ["xx\"//files"] } });
assertParseResult(
`{
"exclude": [
"xx\\\\" // end of line comment
]
}`, { config: { exclude: ["xx\\"] } });
});
it("returns object with error when json is invalid", () => {
assertParseError("invalid");
});
it("returns object when users correctly specify library", () => {
assertParseResult(
`{
"compilerOptions": {
"lib": ["es5"]
}
}`, {
config: { compilerOptions: { lib: ["es5"] } }
});
assertParseResult(
`{
"compilerOptions": {
"lib": ["es5", "es6"]
}
}`, {
config: { compilerOptions: { lib: ["es5", "es6"] } }
});
});
it("returns error when tsconfig have excludes", () => {
assertParseErrorWithExcludesKeyword(
`{
"compilerOptions": {
"lib": ["es5"]
},
"excludes": [
"foge.ts"
]
}`);
});
it("ignore dotted files and folders", () => {
assertParseFileList(
`{}`,
"tsconfig.json",
"/apath",
["/apath/test.ts", "/apath/.git/a.ts", "/apath/.b.ts", "/apath/..c.ts"],
["/apath/test.ts"]
);
});
it("allow dotted files and folders when explicitly requested", () => {
assertParseFileList(
`{
"files": ["/apath/.git/a.ts", "/apath/.b.ts", "/apath/..c.ts"]
}`,
"tsconfig.json",
"/apath",
["/apath/test.ts", "/apath/.git/a.ts", "/apath/.b.ts", "/apath/..c.ts"],
["/apath/.git/a.ts", "/apath/.b.ts", "/apath/..c.ts"]
);
});
it("always exclude outDir", () => {
const tsconfigWithoutExclude =
`{
"compilerOptions": {
"outDir": "bin"
}
}`;
const tsconfigWithExclude =
`{
"compilerOptions": {
"outDir": "bin"
},
"exclude": [ "obj" ]
}`;
const rootDir = "/";
const allFiles = ["/bin/a.ts", "/b.ts"];
const expectedFiles = ["/b.ts"];
assertParseFileList(tsconfigWithoutExclude, "tsconfig.json", rootDir, allFiles, expectedFiles);
assertParseFileList(tsconfigWithExclude, "tsconfig.json", rootDir, allFiles, expectedFiles);
});
it("implicitly exclude common package folders", () => {
assertParseFileList(
`{}`,
"tsconfig.json",
"/",
["/node_modules/a.ts", "/bower_components/b.ts", "/jspm_packages/c.ts", "/d.ts", "/folder/e.ts"],
["/d.ts", "/folder/e.ts"]
);
});
});
}
/// <reference path="..\harness.ts" />
/// <reference path="..\..\compiler\commandLineParser.ts" />
namespace ts {
describe("parseConfigFileTextToJson", () => {
function assertParseResult(jsonText: string, expectedConfigObject: { config?: any; error?: Diagnostic }) {
const parsed = ts.parseConfigFileTextToJson("/apath/tsconfig.json", jsonText);
assert.equal(JSON.stringify(parsed), JSON.stringify(expectedConfigObject));
}
function assertParseError(jsonText: string) {
const parsed = ts.parseConfigFileTextToJson("/apath/tsconfig.json", jsonText);
assert.isTrue(undefined === parsed.config);
assert.isTrue(undefined !== parsed.error);
}
function assertParseErrorWithExcludesKeyword(jsonText: string) {
const parsed = ts.parseConfigFileTextToJson("/apath/tsconfig.json", jsonText);
const parsedCommand = ts.parseJsonConfigFileContent(parsed.config, ts.sys, "tests/cases/unittests");
assert.isTrue(parsedCommand.errors && parsedCommand.errors.length === 1 &&
parsedCommand.errors[0].code === ts.Diagnostics.Unknown_option_excludes_Did_you_mean_exclude.code);
}
function assertParseFileList(jsonText: string, configFileName: string, basePath: string, allFileList: string[], expectedFileList: string[]) {
const json = JSON.parse(jsonText);
const host: ParseConfigHost = new Utils.MockParseConfigHost(basePath, true, allFileList);
const parsed = ts.parseJsonConfigFileContent(json, host, basePath, /*existingOptions*/ undefined, configFileName);
assert.isTrue(arrayIsEqualTo(parsed.fileNames.sort(), expectedFileList.sort()));
}
it("returns empty config for file with only whitespaces", () => {
assertParseResult("", { config : {} });
assertParseResult(" ", { config : {} });
});
it("returns empty config for file with comments only", () => {
assertParseResult("// Comment", { config: {} });
assertParseResult("/* Comment*/", { config: {} });
});
it("returns empty config when config is empty object", () => {
assertParseResult("{}", { config: {} });
});
it("returns config object without comments", () => {
assertParseResult(
`{ // Excluded files
"exclude": [
// Exclude d.ts
"file.d.ts"
]
}`, { config: { exclude: ["file.d.ts"] } });
assertParseResult(
`{
/* Excluded
Files
*/
"exclude": [
/* multiline comments can be in the middle of a line */"file.d.ts"
]
}`, { config: { exclude: ["file.d.ts"] } });
});
it("keeps string content untouched", () => {
assertParseResult(
`{
"exclude": [
"xx//file.d.ts"
]
}`, { config: { exclude: ["xx//file.d.ts"] } });
assertParseResult(
`{
"exclude": [
"xx/*file.d.ts*/"
]
}`, { config: { exclude: ["xx/*file.d.ts*/"] } });
});
it("handles escaped characters in strings correctly", () => {
assertParseResult(
`{
"exclude": [
"xx\\"//files"
]
}`, { config: { exclude: ["xx\"//files"] } });
assertParseResult(
`{
"exclude": [
"xx\\\\" // end of line comment
]
}`, { config: { exclude: ["xx\\"] } });
});
it("returns object with error when json is invalid", () => {
assertParseError("invalid");
});
it("returns object when users correctly specify library", () => {
assertParseResult(
`{
"compilerOptions": {
"lib": ["es5"]
}
}`, {
config: { compilerOptions: { lib: ["es5"] } }
});
assertParseResult(
`{
"compilerOptions": {
"lib": ["es5", "es6"]
}
}`, {
config: { compilerOptions: { lib: ["es5", "es6"] } }
});
});
it("returns error when tsconfig have excludes", () => {
assertParseErrorWithExcludesKeyword(
`{
"compilerOptions": {
"lib": ["es5"]
},
"excludes": [
"foge.ts"
]
}`);
});
it("ignore dotted files and folders", () => {
assertParseFileList(
`{}`,
"tsconfig.json",
"/apath",
["/apath/test.ts", "/apath/.git/a.ts", "/apath/.b.ts", "/apath/..c.ts"],
["/apath/test.ts"]
);
});
it("allow dotted files and folders when explicitly requested", () => {
assertParseFileList(
`{
"files": ["/apath/.git/a.ts", "/apath/.b.ts", "/apath/..c.ts"]
}`,
"tsconfig.json",
"/apath",
["/apath/test.ts", "/apath/.git/a.ts", "/apath/.b.ts", "/apath/..c.ts"],
["/apath/.git/a.ts", "/apath/.b.ts", "/apath/..c.ts"]
);
});
it("always exclude outDir", () => {
const tsconfigWithoutExclude =
`{
"compilerOptions": {
"outDir": "bin"
}
}`;
const tsconfigWithExclude =
`{
"compilerOptions": {
"outDir": "bin"
},
"exclude": [ "obj" ]
}`;
const rootDir = "/";
const allFiles = ["/bin/a.ts", "/b.ts"];
const expectedFiles = ["/b.ts"];
assertParseFileList(tsconfigWithoutExclude, "tsconfig.json", rootDir, allFiles, expectedFiles);
assertParseFileList(tsconfigWithExclude, "tsconfig.json", rootDir, allFiles, expectedFiles);
});
it("implicitly exclude common package folders", () => {
assertParseFileList(
`{}`,
"tsconfig.json",
"/",
["/node_modules/a.ts", "/bower_components/b.ts", "/jspm_packages/c.ts", "/d.ts", "/folder/e.ts"],
["/d.ts", "/folder/e.ts"]
);
});
});
}

View File

@ -68,20 +68,10 @@ namespace ts {
return entry;
}
function sizeOfMap(map: Map<any>): number {
let n = 0;
for (const name in map) {
if (hasProperty(map, name)) {
n++;
}
}
return n;
}
function checkMapKeys(caption: string, map: Map<any>, expectedKeys: string[]) {
assert.equal(sizeOfMap(map), expectedKeys.length, `${caption}: incorrect size of map`);
assert.equal(reduceProperties(map, count => count + 1, 0), expectedKeys.length, `${caption}: incorrect size of map`);
for (const name of expectedKeys) {
assert.isTrue(hasProperty(map, name), `${caption} is expected to contain ${name}, actual keys: ${getKeys(map)}`);
assert.isTrue(name in map, `${caption} is expected to contain ${name}, actual keys: ${Object.keys(map)}`);
}
}
@ -126,8 +116,8 @@ namespace ts {
private getCanonicalFileName: (s: string) => string;
private toPath: (f: string) => Path;
private callbackQueue: TimeOutCallback[] = [];
readonly watchedDirectories: Map<{ cb: DirectoryWatcherCallback, recursive: boolean }[]> = {};
readonly watchedFiles: Map<FileWatcherCallback[]> = {};
readonly watchedDirectories = createMap<{ cb: DirectoryWatcherCallback, recursive: boolean }[]>();
readonly watchedFiles = createMap<FileWatcherCallback[]>();
constructor(public useCaseSensitiveFileNames: boolean, private executingFilePath: string, private currentDirectory: string, fileOrFolderList: FileOrFolder[]) {
this.getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
@ -208,7 +198,7 @@ namespace ts {
watchDirectory(directoryName: string, callback: DirectoryWatcherCallback, recursive: boolean): DirectoryWatcher {
const path = this.toPath(directoryName);
const callbacks = lookUp(this.watchedDirectories, path) || (this.watchedDirectories[path] = []);
const callbacks = this.watchedDirectories[path] || (this.watchedDirectories[path] = []);
callbacks.push({ cb: callback, recursive });
return {
referenceCount: 0,
@ -229,7 +219,7 @@ namespace ts {
triggerDirectoryWatcherCallback(directoryName: string, fileName: string): void {
const path = this.toPath(directoryName);
const callbacks = lookUp(this.watchedDirectories, path);
const callbacks = this.watchedDirectories[path];
if (callbacks) {
for (const callback of callbacks) {
callback.cb(fileName);
@ -239,7 +229,7 @@ namespace ts {
triggerFileWatcherCallback(fileName: string, removed?: boolean): void {
const path = this.toPath(fileName);
const callbacks = lookUp(this.watchedFiles, path);
const callbacks = this.watchedFiles[path];
if (callbacks) {
for (const callback of callbacks) {
callback(path, removed);
@ -249,7 +239,7 @@ namespace ts {
watchFile(fileName: string, callback: FileWatcherCallback) {
const path = this.toPath(fileName);
const callbacks = lookUp(this.watchedFiles, path) || (this.watchedFiles[path] = []);
const callbacks = this.watchedFiles[path] || (this.watchedFiles[path] = []);
callbacks.push(callback);
return {
close: () => {
@ -594,7 +584,7 @@ namespace ts {
content: `{
"compilerOptions": {
"target": "es6"
},
},
"files": [ "main.ts" ]
}`
};
@ -621,7 +611,7 @@ namespace ts {
content: `{
"compilerOptions": {
"target": "es6"
},
},
"files": [ "main.ts" ]
}`
};

View File

@ -68,6 +68,10 @@ interface ArrayConstructor {
of<T>(...items: T[]): Array<T>;
}
interface DateConstructor {
new (value: Date): Date;
}
interface Function {
/**
* Returns the name of the function. Function names are read-only and can not be changed.
@ -226,7 +230,7 @@ interface NumberConstructor {
/**
* The value of the largest integer n such that n and n + 1 are both exactly representable as
* a Number value.
* The value of Number.MIN_SAFE_INTEGER is 9007199254740991 2^53 1.
* The value of Number.MAX_SAFE_INTEGER is 9007199254740991 2^53 1.
*/
readonly MAX_SAFE_INTEGER: number;
@ -343,6 +347,30 @@ interface ObjectConstructor {
defineProperty(o: any, propertyKey: PropertyKey, attributes: PropertyDescriptor): any;
}
interface ReadonlyArray<T> {
/**
* Returns the value of the first element in the array where predicate is true, and undefined
* otherwise.
* @param predicate find calls predicate once for each element of the array, in ascending
* order, until it finds one where predicate returns true. If such an element is found, find
* immediately returns that element value. Otherwise, find returns undefined.
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
find(predicate: (value: T, index: number, obj: ReadonlyArray<T>) => boolean, thisArg?: any): T | undefined;
/**
* Returns the index of the first element in the array where predicate is true, and undefined
* otherwise.
* @param predicate find calls predicate once for each element of the array, in ascending
* order, until it finds one where predicate returns true. If such an element is found,
* findIndex immediately returns that element index. Otherwise, findIndex returns -1.
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: T) => boolean, thisArg?: any): number;
}
interface RegExp {
/**
* Returns a string indicating the flags of the regular expression in question. This field is read-only.

View File

@ -63,6 +63,26 @@ interface ArrayConstructor {
from<T>(iterable: Iterable<T>): Array<T>;
}
interface ReadonlyArray<T> {
/** Iterator */
[Symbol.iterator](): IterableIterator<T>;
/**
* Returns an array of key, value pairs for every entry in the array
*/
entries(): IterableIterator<[number, T]>;
/**
* Returns an list of keys in the array
*/
keys(): IterableIterator<number>;
/**
* Returns an list of values in the array
*/
values(): IterableIterator<T>;
}
interface IArguments {
/** Iterator */
[Symbol.iterator](): IterableIterator<any>;

12
src/lib/es5.d.ts vendored
View File

@ -1006,7 +1006,12 @@ interface ReadonlyArray<T> {
* Combines two or more arrays.
* @param items Additional items to add to the end of array1.
*/
concat(...items: T[]): T[];
concat(...items: T[][]): T[];
/**
* Combines two or more arrays.
* @param items Additional items to add to the end of array1.
*/
concat(...items: (T | T[])[]): T[];
/**
* Adds all the elements of an array separated by the specified separator string.
* @param separator A string used to separate one element of an array from the next in the resulting String. If omitted, the array elements are separated with a comma.
@ -1108,6 +1113,11 @@ interface Array<T> {
* Removes the last element from an array and returns it.
*/
pop(): T | undefined;
/**
* Combines two or more arrays.
* @param items Additional items to add to the end of array1.
*/
concat(...items: T[][]): T[];
/**
* Combines two or more arrays.
* @param items Additional items to add to the end of array1.

View File

@ -21,7 +21,7 @@ namespace ts.server {
export class SessionClient implements LanguageService {
private sequence: number = 0;
private lineMaps: ts.Map<number[]> = {};
private lineMaps: ts.Map<number[]> = ts.createMap<number[]>();
private messages: string[] = [];
private lastRenameEntry: RenameEntry;
@ -37,7 +37,7 @@ namespace ts.server {
}
private getLineMap(fileName: string): number[] {
let lineMap = ts.lookUp(this.lineMaps, fileName);
let lineMap = this.lineMaps[fileName];
if (!lineMap) {
const scriptSnapshot = this.host.getScriptSnapshot(fileName);
lineMap = this.lineMaps[fileName] = ts.computeLineStarts(scriptSnapshot.getText(0, scriptSnapshot.getLength()));

View File

@ -115,6 +115,9 @@ namespace ts.server {
readFile: fileName => this.host.readFile(fileName),
directoryExists: directoryName => this.host.directoryExists(directoryName)
};
if (this.host.realpath) {
this.moduleResolutionHost.realpath = path => this.host.realpath(path);
}
}
private resolveNamesWithLocalCache<T extends Timestamped & { failedLookupLocations: string[] }, R>(
@ -127,15 +130,15 @@ namespace ts.server {
const path = toPath(containingFile, this.host.getCurrentDirectory(), this.getCanonicalFileName);
const currentResolutionsInFile = cache.get(path);
const newResolutions: Map<T> = {};
const newResolutions = createMap<T>();
const resolvedModules: R[] = [];
const compilerOptions = this.getCompilationSettings();
for (const name of names) {
// check if this is a duplicate entry in the list
let resolution = lookUp(newResolutions, name);
let resolution = newResolutions[name];
if (!resolution) {
const existingResolution = currentResolutionsInFile && ts.lookUp(currentResolutionsInFile, name);
const existingResolution = currentResolutionsInFile && currentResolutionsInFile[name];
if (moduleResolutionIsValid(existingResolution)) {
// ok, it is safe to use existing name resolution results
resolution = existingResolution;
@ -375,7 +378,7 @@ namespace ts.server {
export interface ProjectOptions {
// these fields can be present in the project file
files?: string[];
wildcardDirectories?: ts.Map<ts.WatchDirectoryFlags>;
wildcardDirectories?: ts.MapLike<ts.WatchDirectoryFlags>;
compilerOptions?: ts.CompilerOptions;
}
@ -388,7 +391,7 @@ namespace ts.server {
// Used to keep track of what directories are watched for this project
directoriesWatchedForTsconfig: string[] = [];
program: ts.Program;
filenameToSourceFile: ts.Map<ts.SourceFile> = {};
filenameToSourceFile = ts.createMap<ts.SourceFile>();
updateGraphSeq = 0;
/** Used for configured projects which may have multiple open roots */
openRefCount = 0;
@ -501,7 +504,7 @@ namespace ts.server {
return;
}
this.filenameToSourceFile = {};
this.filenameToSourceFile = createMap<SourceFile>();
const sourceFiles = this.program.getSourceFiles();
for (let i = 0, len = sourceFiles.length; i < len; i++) {
const normFilename = ts.normalizePath(sourceFiles[i].fileName);
@ -560,7 +563,7 @@ namespace ts.server {
}
let strBuilder = "";
ts.forEachValue(this.filenameToSourceFile,
ts.forEachProperty(this.filenameToSourceFile,
sourceFile => { strBuilder += sourceFile.fileName + "\n"; });
return strBuilder;
}
@ -610,7 +613,7 @@ namespace ts.server {
}
export class ProjectService {
filenameToScriptInfo: ts.Map<ScriptInfo> = {};
filenameToScriptInfo = ts.createMap<ScriptInfo>();
// open, non-configured root files
openFileRoots: ScriptInfo[] = [];
// projects built from openFileRoots
@ -622,12 +625,12 @@ namespace ts.server {
// open files that are roots of a configured project
openFileRootsConfigured: ScriptInfo[] = [];
// a path to directory watcher map that detects added tsconfig files
directoryWatchersForTsconfig: ts.Map<FileWatcher> = {};
directoryWatchersForTsconfig = ts.createMap<FileWatcher>();
// count of how many projects are using the directory watcher. If the
// number becomes 0 for a watcher, then we should close it.
directoryWatchersRefCount: ts.Map<number> = {};
directoryWatchersRefCount = ts.createMap<number>();
hostConfiguration: HostConfiguration;
timerForDetectingProjectFileListChanges: Map<any> = {};
timerForDetectingProjectFileListChanges = createMap<any>();
constructor(public host: ServerHost, public psLogger: Logger, public eventHandler?: ProjectServiceEventHandler) {
// ts.disableIncrementalParsing = true;
@ -854,7 +857,7 @@ namespace ts.server {
if (project.isConfiguredProject()) {
project.projectFileWatcher.close();
project.directoryWatcher.close();
forEachValue(project.directoriesWatchedForWildcards, watcher => { watcher.close(); });
forEachProperty(project.directoriesWatchedForWildcards, watcher => { watcher.close(); });
delete project.directoriesWatchedForWildcards;
this.configuredProjects = copyListRemovingItem(project, this.configuredProjects);
}
@ -1121,7 +1124,7 @@ namespace ts.server {
getScriptInfo(filename: string) {
filename = ts.normalizePath(filename);
return ts.lookUp(this.filenameToScriptInfo, filename);
return this.filenameToScriptInfo[filename];
}
/**
@ -1130,7 +1133,7 @@ namespace ts.server {
*/
openFile(fileName: string, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind) {
fileName = ts.normalizePath(fileName);
let info = ts.lookUp(this.filenameToScriptInfo, fileName);
let info = this.filenameToScriptInfo[fileName];
if (!info) {
let content: string;
if (this.host.fileExists(fileName)) {
@ -1243,7 +1246,7 @@ namespace ts.server {
* @param filename is absolute pathname
*/
closeClientFile(filename: string) {
const info = ts.lookUp(this.filenameToScriptInfo, filename);
const info = this.filenameToScriptInfo[filename];
if (info) {
this.closeOpenFile(info);
info.isOpen = false;
@ -1252,14 +1255,14 @@ namespace ts.server {
}
getProjectForFile(filename: string) {
const scriptInfo = ts.lookUp(this.filenameToScriptInfo, filename);
const scriptInfo = this.filenameToScriptInfo[filename];
if (scriptInfo) {
return scriptInfo.defaultProject;
}
}
printProjectsForFile(filename: string) {
const scriptInfo = ts.lookUp(this.filenameToScriptInfo, filename);
const scriptInfo = this.filenameToScriptInfo[filename];
if (scriptInfo) {
this.psLogger.startGroup();
this.psLogger.info("Projects for " + filename);
@ -1416,7 +1419,7 @@ namespace ts.server {
/*recursive*/ true
);
project.directoriesWatchedForWildcards = reduceProperties(projectOptions.wildcardDirectories, (watchers, flag, directory) => {
project.directoriesWatchedForWildcards = reduceProperties(createMap(projectOptions.wildcardDirectories), (watchers, flag, directory) => {
if (comparePaths(configDirectoryPath, directory, ".", !this.host.useCaseSensitiveFileNames) !== Comparison.EqualTo) {
const recursive = (flag & WatchDirectoryFlags.Recursive) !== 0;
this.log(`Add ${ recursive ? "recursive " : ""}watcher for: ${directory}`);

View File

@ -1061,7 +1061,7 @@ namespace ts.server {
return { response, responseRequired: true };
}
private handlers: Map<(request: protocol.Request) => { response?: any, responseRequired?: boolean }> = {
private handlers = createMap<(request: protocol.Request) => { response?: any, responseRequired?: boolean }>({
[CommandNames.Exit]: () => {
this.exit();
return { responseRequired: false };
@ -1198,9 +1198,10 @@ namespace ts.server {
this.reloadProjects();
return { responseRequired: false };
}
};
});
public addProtocolHandler(command: string, handler: (request: protocol.Request) => { response?: any, responseRequired: boolean }) {
if (this.handlers[command]) {
if (command in this.handlers) {
throw new Error(`Protocol handler already exists for command "${command}"`);
}
this.handlers[command] = handler;

View File

@ -10,6 +10,8 @@
"types": []
},
"files": [
"../services/shims.ts",
"../services/utilities.ts",
"editorServices.ts",
"protocol.d.ts",
"session.ts"

View File

@ -453,9 +453,9 @@ namespace ts.formatting {
case SyntaxKind.MethodDeclaration:
if ((<MethodDeclaration>node).asteriskToken) {
return SyntaxKind.AsteriskToken;
}
// fall-through
}/*
fall-through
*/
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.Parameter:
return (<Declaration>node).name.kind;
@ -732,7 +732,7 @@ namespace ts.formatting {
else {
// indent token only if end line of previous range does not match start line of the token
const prevEndLine = savePreviousRange && sourceFile.getLineAndCharacterOfPosition(savePreviousRange.end).line;
indentToken = lastTriviaWasNewLine && tokenStart.line !== prevEndLine;
indentToken = lastTriviaWasNewLine && tokenStart.line !== prevEndLine;
}
}
}
@ -892,7 +892,7 @@ namespace ts.formatting {
}
function indentationIsDifferent(indentationString: string, startLinePosition: number): boolean {
return indentationString !== sourceFile.text.substr(startLinePosition , indentationString.length);
return indentationString !== sourceFile.text.substr(startLinePosition, indentationString.length);
}
function indentMultilineComment(commentRange: TextRange, indentation: number, firstLineIsIndented: boolean) {
@ -936,7 +936,7 @@ namespace ts.formatting {
// shift all parts on the delta size
const delta = indentation - nonWhitespaceColumnInFirstPart.column;
for (let i = startIndex, len = parts.length; i < len; i++, startLine++) {
for (let i = startIndex, len = parts.length; i < len; i++ , startLine++) {
const startLinePos = getStartPositionOfLine(startLine, sourceFile);
const nonWhitespaceCharacterAndColumn =
i === 0

View File

@ -231,6 +231,13 @@ namespace ts.formatting {
public NoSpaceBeforeCloseBraceInJsxExpression: Rule;
public SpaceBeforeCloseBraceInJsxExpression: Rule;
// JSX opening elements
public SpaceBeforeJsxAttribute: Rule;
public SpaceBeforeSlashInJsxOpeningElement: Rule;
public NoSpaceBeforeGreaterThanTokenInJsxOpeningElement: Rule;
public NoSpaceBeforeEqualInJsxAttribute: Rule;
public NoSpaceAfterEqualInJsxAttribute: Rule;
constructor() {
///
/// Common Rules
@ -322,7 +329,7 @@ namespace ts.formatting {
// Add a space between statements. All keywords except (do,else,case) has open/close parens after them.
// So, we have a rule to add a space for [),Any], [do,Any], [else,Any], and [case,Any]
this.SpaceBetweenStatements = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.DoKeyword, SyntaxKind.ElseKeyword, SyntaxKind.CaseKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.isNonJsxElementContext, Rules.IsNotForContext), RuleAction.Space));
this.SpaceBetweenStatements = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.DoKeyword, SyntaxKind.ElseKeyword, SyntaxKind.CaseKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNonJsxElementContext, Rules.IsNotForContext), RuleAction.Space));
// This low-pri rule takes care of "try {" and "finally {" in case the rule SpaceBeforeOpenBraceInControl didn't execute on FormatOnEnter.
this.SpaceAfterTryFinally = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.TryKeyword, SyntaxKind.FinallyKeyword]), SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
@ -386,6 +393,13 @@ namespace ts.formatting {
// template string
this.NoSpaceBetweenTagAndTemplateString = new Rule(RuleDescriptor.create3(SyntaxKind.Identifier, Shared.TokenRange.FromTokens([SyntaxKind.NoSubstitutionTemplateLiteral, SyntaxKind.TemplateHead])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
// jsx opening element
this.SpaceBeforeJsxAttribute = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.Identifier), RuleOperation.create2(new RuleOperationContext(Rules.IsNextTokenParentJsxAttribute, Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
this.SpaceBeforeSlashInJsxOpeningElement = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.SlashToken), RuleOperation.create2(new RuleOperationContext(Rules.IsJsxSelfClosingElementContext, Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
this.NoSpaceBeforeGreaterThanTokenInJsxOpeningElement = new Rule(RuleDescriptor.create1(SyntaxKind.SlashToken, SyntaxKind.GreaterThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsJsxSelfClosingElementContext, Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
this.NoSpaceBeforeEqualInJsxAttribute = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.EqualsToken), RuleOperation.create2(new RuleOperationContext(Rules.IsJsxAttributeContext, Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
this.NoSpaceAfterEqualInJsxAttribute = new Rule(RuleDescriptor.create3(SyntaxKind.EqualsToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsJsxAttributeContext, Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
// These rules are higher in priority than user-configurable rules.
this.HighPriorityCommonRules = [
this.IgnoreBeforeComment, this.IgnoreAfterLineComment,
@ -413,6 +427,8 @@ namespace ts.formatting {
this.SpaceAfterVoidOperator,
this.SpaceBetweenAsyncAndOpenParen, this.SpaceBetweenAsyncAndFunctionKeyword,
this.NoSpaceBetweenTagAndTemplateString,
this.SpaceBeforeJsxAttribute, this.SpaceBeforeSlashInJsxOpeningElement, this.NoSpaceBeforeGreaterThanTokenInJsxOpeningElement,
this.NoSpaceBeforeEqualInJsxAttribute, this.NoSpaceAfterEqualInJsxAttribute,
// TypeScript-specific rules
this.NoSpaceAfterConstructor, this.NoSpaceAfterModuleImport,
@ -450,8 +466,8 @@ namespace ts.formatting {
///
// Insert space after comma delimiter
this.SpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.isNonJsxElementContext, Rules.IsNextTokenNotCloseBracket), RuleAction.Space));
this.NoSpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.isNonJsxElementContext), RuleAction.Delete));
this.SpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNonJsxElementContext, Rules.IsNextTokenNotCloseBracket), RuleAction.Space));
this.NoSpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNonJsxElementContext), RuleAction.Delete));
// Insert space before and after binary operators
this.SpaceBeforeBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
@ -498,10 +514,10 @@ namespace ts.formatting {
this.SpaceBeforeTemplateMiddleAndTail = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
// No space after { and before } in JSX expression
this.NoSpaceAfterOpenBraceInJsxExpression = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.isJsxExpressionContext), RuleAction.Delete));
this.SpaceAfterOpenBraceInJsxExpression = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.isJsxExpressionContext), RuleAction.Space));
this.NoSpaceBeforeCloseBraceInJsxExpression = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.isJsxExpressionContext), RuleAction.Delete));
this.SpaceBeforeCloseBraceInJsxExpression = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.isJsxExpressionContext), RuleAction.Space));
this.NoSpaceAfterOpenBraceInJsxExpression = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsJsxExpressionContext), RuleAction.Delete));
this.SpaceAfterOpenBraceInJsxExpression = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsJsxExpressionContext), RuleAction.Space));
this.NoSpaceBeforeCloseBraceInJsxExpression = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsJsxExpressionContext), RuleAction.Delete));
this.SpaceBeforeCloseBraceInJsxExpression = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsJsxExpressionContext), RuleAction.Space));
// Insert space after function keyword for anonymous functions
this.SpaceAfterAnonymousFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space));
@ -741,14 +757,26 @@ namespace ts.formatting {
return context.TokensAreOnSameLine() && context.contextNode.kind !== SyntaxKind.JsxText;
}
static isNonJsxElementContext(context: FormattingContext): boolean {
static IsNonJsxElementContext(context: FormattingContext): boolean {
return context.contextNode.kind !== SyntaxKind.JsxElement;
}
static isJsxExpressionContext(context: FormattingContext): boolean {
static IsJsxExpressionContext(context: FormattingContext): boolean {
return context.contextNode.kind === SyntaxKind.JsxExpression;
}
static IsNextTokenParentJsxAttribute(context: FormattingContext): boolean {
return context.nextTokenParent.kind === SyntaxKind.JsxAttribute;
}
static IsJsxAttributeContext(context: FormattingContext): boolean {
return context.contextNode.kind === SyntaxKind.JsxAttribute;
}
static IsJsxSelfClosingElementContext(context: FormattingContext): boolean {
return context.contextNode.kind === SyntaxKind.JsxSelfClosingElement;
}
static IsNotBeforeBlockInFunctionDeclarationContext(context: FormattingContext): boolean {
return !Rules.IsFunctionDeclContext(context) && !Rules.IsBeforeBlockContext(context);
}

View File

@ -19,7 +19,7 @@ namespace ts.formatting {
public Initialize(rules: Rule[]) {
this.mapRowLength = SyntaxKind.LastToken + 1;
this.map = <any> new Array(this.mapRowLength * this.mapRowLength); // new Array<RulesBucket>(this.mapRowLength * this.mapRowLength);
this.map = <any>new Array(this.mapRowLength * this.mapRowLength); // new Array<RulesBucket>(this.mapRowLength * this.mapRowLength);
// This array is used only during construction of the rulesbucket in the map
const rulesBucketConstructionStateList: RulesBucketConstructionState[] = <any>new Array(this.map.length); // new Array<RulesBucketConstructionState>(this.map.length);

View File

@ -47,7 +47,7 @@ namespace ts.JsTyping {
{ cachedTypingPaths: string[], newTypingNames: string[], filesToWatch: string[] } {
// A typing name to typing file path mapping
const inferredTypings: Map<string> = {};
const inferredTypings = createMap<string>();
if (!typingOptions || !typingOptions.enableAutoDiscovery) {
return { cachedTypingPaths: [], newTypingNames: [], filesToWatch: [] };
@ -58,12 +58,7 @@ namespace ts.JsTyping {
if (!safeList) {
const result = readConfigFile(safeListPath, (path: string) => host.readFile(path));
if (result.config) {
safeList = result.config;
}
else {
safeList = {};
};
safeList = createMap<string>(result.config);
}
const filesToWatch: string[] = [];
@ -93,7 +88,7 @@ namespace ts.JsTyping {
// Add the cached typing locations for inferred typings that are already installed
for (const name in packageNameToTypingLocation) {
if (hasProperty(inferredTypings, name) && !inferredTypings[name]) {
if (name in inferredTypings && !inferredTypings[name]) {
inferredTypings[name] = packageNameToTypingLocation[name];
}
}
@ -124,7 +119,7 @@ namespace ts.JsTyping {
}
for (const typing of typingNames) {
if (!hasProperty(inferredTypings, typing)) {
if (!(typing in inferredTypings)) {
inferredTypings[typing] = undefined;
}
}
@ -139,16 +134,16 @@ namespace ts.JsTyping {
const jsonConfig: PackageJson = result.config;
filesToWatch.push(jsonPath);
if (jsonConfig.dependencies) {
mergeTypings(getKeys(jsonConfig.dependencies));
mergeTypings(getOwnKeys(jsonConfig.dependencies));
}
if (jsonConfig.devDependencies) {
mergeTypings(getKeys(jsonConfig.devDependencies));
mergeTypings(getOwnKeys(jsonConfig.devDependencies));
}
if (jsonConfig.optionalDependencies) {
mergeTypings(getKeys(jsonConfig.optionalDependencies));
mergeTypings(getOwnKeys(jsonConfig.optionalDependencies));
}
if (jsonConfig.peerDependencies) {
mergeTypings(getKeys(jsonConfig.peerDependencies));
mergeTypings(getOwnKeys(jsonConfig.peerDependencies));
}
}
}
@ -167,7 +162,7 @@ namespace ts.JsTyping {
mergeTypings(cleanedTypingNames);
}
else {
mergeTypings(filter(cleanedTypingNames, f => hasProperty(safeList, f)));
mergeTypings(filter(cleanedTypingNames, f => f in safeList));
}
const hasJsxFile = forEach(fileNames, f => scriptKindIs(f, /*LanguageServiceHost*/ undefined, ScriptKind.JSX));

View File

@ -15,7 +15,7 @@ namespace ts.NavigateTo {
const nameToDeclarations = sourceFile.getNamedDeclarations();
for (const name in nameToDeclarations) {
const declarations = getProperty(nameToDeclarations, name);
const declarations = nameToDeclarations[name];
if (declarations) {
// First do a quick check to see if the name of the declaration matches the
// last portion of the (possibly) dotted name they're searching for.

View File

@ -234,7 +234,7 @@ namespace ts.NavigationBar {
/** Merge declarations of the same kind. */
function mergeChildren(children: NavigationBarNode[]): void {
const nameToItems: Map<NavigationBarNode | NavigationBarNode[]> = {};
const nameToItems = createMap<NavigationBarNode | NavigationBarNode[]>();
filterMutate(children, child => {
const decl = <Declaration>child.node;
const name = decl.name && nodeText(decl.name);
@ -243,7 +243,7 @@ namespace ts.NavigationBar {
return true;
}
const itemsWithSameName = getProperty(nameToItems, name);
const itemsWithSameName = nameToItems[name];
if (!itemsWithSameName) {
nameToItems[name] = child;
return true;
@ -506,7 +506,7 @@ namespace ts.NavigationBar {
function convertToTopLevelItem(n: NavigationBarNode): NavigationBarItem {
return {
text: getItemName(n.node),
kind: nodeKind(n.node),
kind: getNodeKind(n.node),
kindModifiers: getNodeModifiers(n.node),
spans: getSpans(n),
childItems: map(n.children, convertToChildItem) || emptyChildItemArray,
@ -518,7 +518,7 @@ namespace ts.NavigationBar {
function convertToChildItem(n: NavigationBarNode): NavigationBarItem {
return {
text: getItemName(n.node),
kind: nodeKind(n.node),
kind: getNodeKind(n.node),
kindModifiers: getNodeModifiers(n.node),
spans: getSpans(n),
childItems: emptyChildItemArray,
@ -539,57 +539,6 @@ namespace ts.NavigationBar {
}
}
// TODO: GH#9145: We should just use getNodeKind. No reason why navigationBar and navigateTo should have different behaviors.
function nodeKind(node: Node): string {
switch (node.kind) {
case SyntaxKind.SourceFile:
return ScriptElementKind.moduleElement;
case SyntaxKind.EnumMember:
return ScriptElementKind.memberVariableElement;
case SyntaxKind.VariableDeclaration:
case SyntaxKind.BindingElement:
let variableDeclarationNode: Node;
let name: Node;
if (node.kind === SyntaxKind.BindingElement) {
name = (<BindingElement>node).name;
variableDeclarationNode = node;
// binding elements are added only for variable declarations
// bubble up to the containing variable declaration
while (variableDeclarationNode && variableDeclarationNode.kind !== SyntaxKind.VariableDeclaration) {
variableDeclarationNode = variableDeclarationNode.parent;
}
Debug.assert(!!variableDeclarationNode);
}
else {
Debug.assert(!isBindingPattern((<VariableDeclaration>node).name));
variableDeclarationNode = node;
name = (<VariableDeclaration>node).name;
}
if (isConst(variableDeclarationNode)) {
return ts.ScriptElementKind.constElement;
}
else if (isLet(variableDeclarationNode)) {
return ts.ScriptElementKind.letElement;
}
else {
return ts.ScriptElementKind.variableElement;
}
case SyntaxKind.ArrowFunction:
return ts.ScriptElementKind.functionElement;
case SyntaxKind.JSDocTypedefTag:
return ScriptElementKind.typeElement;
default:
return getNodeKind(node);
}
}
function getModuleName(moduleDeclaration: ModuleDeclaration): string {
// We want to maintain quotation marks.
if (isAmbientModule(moduleDeclaration)) {

View File

@ -113,7 +113,7 @@ namespace ts {
// we see the name of a module that is used everywhere, or the name of an overload). As
// such, we cache the information we compute about the candidate for the life of this
// pattern matcher so we don't have to compute it multiple times.
const stringToWordSpans: Map<TextSpan[]> = {};
const stringToWordSpans = createMap<TextSpan[]>();
pattern = pattern.trim();
@ -188,7 +188,7 @@ namespace ts {
}
function getWordSpans(word: string): TextSpan[] {
if (!hasProperty(stringToWordSpans, word)) {
if (!(word in stringToWordSpans)) {
stringToWordSpans[word] = breakIntoWordSpans(word);
}

View File

@ -871,7 +871,7 @@ namespace ts {
resolvedReturnType: Type;
minArgumentCount: number;
hasRestParameter: boolean;
hasStringLiterals: boolean;
hasLiteralTypes: boolean;
// Undefined is used to indicate the value has not been computed. If, after computing, the
// symbol has no doc comment, then the empty string will be returned.
@ -975,7 +975,7 @@ namespace ts {
}
private computeNamedDeclarations(): Map<Declaration[]> {
const result: Map<Declaration[]> = {};
const result = createMap<Declaration[]>();
forEachChild(this, visit);
@ -990,7 +990,7 @@ namespace ts {
}
function getDeclarations(name: string) {
return getProperty(result, name) || (result[name] = []);
return result[name] || (result[name] = []);
}
function getDeclarationName(declaration: Declaration) {
@ -1082,7 +1082,7 @@ namespace ts {
// fall through
case SyntaxKind.VariableDeclaration:
case SyntaxKind.BindingElement: {
const decl = <VariableDeclaration> node;
const decl = <VariableDeclaration>node;
if (isBindingPattern(decl.name)) {
forEachChild(decl.name, visit);
break;
@ -1690,6 +1690,8 @@ namespace ts {
/** enum E */
export const enumElement = "enum";
// TODO: GH#9983
export const enumMemberElement = "const";
/**
* Inside module and script only
@ -1884,7 +1886,7 @@ namespace ts {
};
}
// Cache host information about scrip Should be refreshed
// Cache host information about script should be refreshed
// at each language service public entry point, since we don't know when
// set of scripts handled by the host changes.
class HostCache {
@ -2023,7 +2025,7 @@ namespace ts {
fileName?: string;
reportDiagnostics?: boolean;
moduleName?: string;
renamedDependencies?: Map<string>;
renamedDependencies?: MapLike<string>;
}
export interface TranspileOutput {
@ -2040,7 +2042,7 @@ namespace ts {
function fixupCompilerOptions(options: CompilerOptions, diagnostics: Diagnostic[]): CompilerOptions {
// Lazily create this value to fix module loading errors.
commandLineOptionsStringToEnum = commandLineOptionsStringToEnum || <CommandLineOptionOfCustomType[]>filter(optionDeclarations, o =>
typeof o.type === "object" && !forEachValue(<Map<any>> o.type, v => typeof v !== "number"));
typeof o.type === "object" && !forEachProperty(o.type, v => typeof v !== "number"));
options = clone(options);
@ -2056,7 +2058,7 @@ namespace ts {
options[opt.name] = parseCustomTypeOption(opt, value, diagnostics);
}
else {
if (!forEachValue(opt.type, v => v === value)) {
if (!forEachProperty(opt.type, v => v === value)) {
// Supplied value isn't a valid enum value.
diagnostics.push(createCompilerDiagnosticForInvalidCustomType(opt));
}
@ -2115,7 +2117,9 @@ namespace ts {
sourceFile.moduleName = transpileOptions.moduleName;
}
sourceFile.renamedDependencies = transpileOptions.renamedDependencies;
if (transpileOptions.renamedDependencies) {
sourceFile.renamedDependencies = createMap(transpileOptions.renamedDependencies);
}
const newLine = getNewLineCharacter(options);
@ -2241,7 +2245,7 @@ namespace ts {
export function createDocumentRegistry(useCaseSensitiveFileNames?: boolean, currentDirectory = ""): DocumentRegistry {
// Maps from compiler setting target (ES3, ES5, etc.) to all the cached documents we have
// for those settings.
const buckets: Map<FileMap<DocumentRegistryEntry>> = {};
const buckets = createMap<FileMap<DocumentRegistryEntry>>();
const getCanonicalFileName = createGetCanonicalFileName(!!useCaseSensitiveFileNames);
function getKeyForCompilationSettings(settings: CompilerOptions): DocumentRegistryBucketKey {
@ -2249,7 +2253,7 @@ namespace ts {
}
function getBucketForCompilationSettings(key: DocumentRegistryBucketKey, createIfMissing: boolean): FileMap<DocumentRegistryEntry> {
let bucket = lookUp(buckets, key);
let bucket = buckets[key];
if (!bucket && createIfMissing) {
buckets[key] = bucket = createFileMap<DocumentRegistryEntry>();
}
@ -2258,7 +2262,7 @@ namespace ts {
function reportStats() {
const bucketInfoArray = Object.keys(buckets).filter(name => name && name.charAt(0) === "_").map(name => {
const entries = lookUp(buckets, name);
const entries = buckets[name];
const sourceFiles: { name: string; refCount: number; references: string[]; }[] = [];
entries.forEachValue((key, entry) => {
sourceFiles.push({
@ -2947,7 +2951,10 @@ namespace ts {
/* @internal */ export function getNodeKind(node: Node): string {
switch (node.kind) {
case SyntaxKind.ModuleDeclaration: return ScriptElementKind.moduleElement;
case SyntaxKind.SourceFile:
return isExternalModule(<SourceFile>node) ? ScriptElementKind.moduleElement : ScriptElementKind.scriptElement;
case SyntaxKind.ModuleDeclaration:
return ScriptElementKind.moduleElement;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
return ScriptElementKind.classElement;
@ -2955,11 +2962,10 @@ namespace ts {
case SyntaxKind.TypeAliasDeclaration: return ScriptElementKind.typeElement;
case SyntaxKind.EnumDeclaration: return ScriptElementKind.enumElement;
case SyntaxKind.VariableDeclaration:
return isConst(node)
? ScriptElementKind.constElement
: isLet(node)
? ScriptElementKind.letElement
: ScriptElementKind.variableElement;
return getKindOfVariableDeclaration(<VariableDeclaration>node);
case SyntaxKind.BindingElement:
return getKindOfVariableDeclaration(<VariableDeclaration>getRootDeclaration(node));
case SyntaxKind.ArrowFunction:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
return ScriptElementKind.functionElement;
@ -2976,7 +2982,7 @@ namespace ts {
case SyntaxKind.CallSignature: return ScriptElementKind.callSignatureElement;
case SyntaxKind.Constructor: return ScriptElementKind.constructorImplementationElement;
case SyntaxKind.TypeParameter: return ScriptElementKind.typeParameterElement;
case SyntaxKind.EnumMember: return ScriptElementKind.variableElement;
case SyntaxKind.EnumMember: return ScriptElementKind.enumMemberElement;
case SyntaxKind.Parameter: return (node.flags & NodeFlags.ParameterPropertyModifier) ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement;
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.ImportSpecifier:
@ -2984,8 +2990,19 @@ namespace ts {
case SyntaxKind.ExportSpecifier:
case SyntaxKind.NamespaceImport:
return ScriptElementKind.alias;
case SyntaxKind.JSDocTypedefTag:
return ScriptElementKind.typeElement;
default:
return ScriptElementKind.unknown;
}
function getKindOfVariableDeclaration(v: VariableDeclaration): string {
return isConst(v)
? ScriptElementKind.constElement
: isLet(v)
? ScriptElementKind.letElement
: ScriptElementKind.variableElement;
}
return ScriptElementKind.unknown;
}
class CancellationTokenObject implements CancellationToken {
@ -3075,14 +3092,16 @@ namespace ts {
const oldSettings = program && program.getCompilerOptions();
const newSettings = hostCache.compilationSettings();
const changesInCompilationSettingsAffectSyntax = oldSettings &&
const shouldCreateNewSourceFiles = oldSettings &&
(oldSettings.target !== newSettings.target ||
oldSettings.module !== newSettings.module ||
oldSettings.moduleResolution !== newSettings.moduleResolution ||
oldSettings.noResolve !== newSettings.noResolve ||
oldSettings.jsx !== newSettings.jsx ||
oldSettings.allowJs !== newSettings.allowJs ||
oldSettings.disableSizeLimit !== oldSettings.disableSizeLimit);
oldSettings.disableSizeLimit !== oldSettings.disableSizeLimit ||
oldSettings.baseUrl !== newSettings.baseUrl ||
!equalOwnProperties(oldSettings.paths, newSettings.paths));
// Now create a new compiler
const compilerHost: CompilerHost = {
@ -3097,7 +3116,6 @@ namespace ts {
getCurrentDirectory: () => currentDirectory,
fileExists: (fileName): boolean => {
// stub missing host functionality
Debug.assert(!host.resolveModuleNames || !host.resolveTypeReferenceDirectives);
return hostCache.getOrCreateEntry(fileName) !== undefined;
},
readFile: (fileName): string => {
@ -3134,7 +3152,7 @@ namespace ts {
const oldSourceFiles = program.getSourceFiles();
const oldSettingsKey = documentRegistry.getKeyForCompilationSettings(oldSettings);
for (const oldSourceFile of oldSourceFiles) {
if (!newProgram.getSourceFile(oldSourceFile.fileName) || changesInCompilationSettingsAffectSyntax) {
if (!newProgram.getSourceFile(oldSourceFile.fileName) || shouldCreateNewSourceFiles) {
documentRegistry.releaseDocumentWithKey(oldSourceFile.path, oldSettingsKey);
}
}
@ -3168,7 +3186,7 @@ namespace ts {
// Check if the language version has changed since we last created a program; if they are the same,
// it is safe to reuse the sourceFiles; if not, then the shape of the AST can change, and the oldSourceFile
// can not be reused. we have to dump all syntax trees and create new ones.
if (!changesInCompilationSettingsAffectSyntax) {
if (!shouldCreateNewSourceFiles) {
// Check if the old program had this file already
const oldSourceFile = program && program.getSourceFileByPath(path);
if (oldSourceFile) {
@ -3731,7 +3749,6 @@ namespace ts {
function isInStringOrRegularExpressionOrTemplateLiteral(contextToken: Node): boolean {
if (contextToken.kind === SyntaxKind.StringLiteral
|| contextToken.kind === SyntaxKind.StringLiteralType
|| contextToken.kind === SyntaxKind.RegularExpressionLiteral
|| isTemplateLiteralKind(contextToken.kind)) {
const start = contextToken.getStart();
@ -3772,7 +3789,11 @@ namespace ts {
// other than those within the declared type.
isNewIdentifierLocation = true;
// If the object literal is being assigned to something of type 'null | { hello: string }',
// it clearly isn't trying to satisfy the 'null' type. So we grab the non-nullable type if possible.
typeForObject = typeChecker.getContextualType(<ObjectLiteralExpression>objectLikeContainer);
typeForObject = typeForObject && typeForObject.getNonNullableType();
existingMembers = (<ObjectLiteralExpression>objectLikeContainer).properties;
}
else if (objectLikeContainer.kind === SyntaxKind.ObjectBindingPattern) {
@ -3784,7 +3805,7 @@ namespace ts {
// We don't want to complete using the type acquired by the shape
// of the binding pattern; we are only interested in types acquired
// through type declaration or inference.
// Also proceed if rootDeclaration is parameter and if its containing function expression\arrow function is contextually typed -
// Also proceed if rootDeclaration is a parameter and if its containing function expression/arrow function is contextually typed -
// type of parameter will flow in from the contextual type of the function
let canGetType = !!(rootDeclaration.initializer || rootDeclaration.type);
if (!canGetType && rootDeclaration.kind === SyntaxKind.Parameter) {
@ -4086,7 +4107,7 @@ namespace ts {
* do not occur at the current position and have not otherwise been typed.
*/
function filterNamedImportOrExportCompletionItems(exportsOfModule: Symbol[], namedImportsOrExports: ImportOrExportSpecifier[]): Symbol[] {
const existingImportsOrExports: Map<boolean> = {};
const existingImportsOrExports = createMap<boolean>();
for (const element of namedImportsOrExports) {
// If this is the current item we are editing right now, do not filter it out
@ -4098,11 +4119,11 @@ namespace ts {
existingImportsOrExports[name.text] = true;
}
if (isEmpty(existingImportsOrExports)) {
if (!someProperties(existingImportsOrExports)) {
return filter(exportsOfModule, e => e.name !== "default");
}
return filter(exportsOfModule, e => e.name !== "default" && !lookUp(existingImportsOrExports, e.name));
return filter(exportsOfModule, e => e.name !== "default" && !existingImportsOrExports[e.name]);
}
/**
@ -4116,7 +4137,7 @@ namespace ts {
return contextualMemberSymbols;
}
const existingMemberNames: Map<boolean> = {};
const existingMemberNames = createMap<boolean>();
for (const m of existingMembers) {
// Ignore omitted expressions for missing members
if (m.kind !== SyntaxKind.PropertyAssignment &&
@ -4149,7 +4170,7 @@ namespace ts {
existingMemberNames[existingName] = true;
}
return filter(contextualMemberSymbols, m => !lookUp(existingMemberNames, m.name));
return filter(contextualMemberSymbols, m => !existingMemberNames[m.name]);
}
/**
@ -4159,7 +4180,7 @@ namespace ts {
* do not occur at the current position and have not otherwise been typed.
*/
function filterJsxAttributes(symbols: Symbol[], attributes: NodeArray<JsxAttribute | JsxSpreadAttribute>): Symbol[] {
const seenNames: Map<boolean> = {};
const seenNames = createMap<boolean>();
for (const attr of attributes) {
// If this is the current item we are editing right now, do not filter it out
if (attr.getStart() <= position && position <= attr.getEnd()) {
@ -4171,7 +4192,7 @@ namespace ts {
}
}
return filter(symbols, a => !lookUp(seenNames, a.name));
return filter(symbols, a => !seenNames[a.name]);
}
}
@ -4231,7 +4252,7 @@ namespace ts {
addRange(entries, keywordCompletions);
}
return { isMemberCompletion, isNewIdentifierLocation, entries };
return { isMemberCompletion, isNewIdentifierLocation: isNewIdentifierLocation || isSourceFileJavaScript(sourceFile), entries };
function getJavaScriptCompletionEntries(sourceFile: SourceFile, position: number, uniqueNames: Map<string>): CompletionEntry[] {
const entries: CompletionEntry[] = [];
@ -4296,17 +4317,18 @@ namespace ts {
kindModifiers: getSymbolModifiers(symbol),
sortText: "0",
};
}
function getCompletionEntriesFromSymbols(symbols: Symbol[], entries: CompletionEntry[], location: Node, performCharacterChecks: boolean): Map<string> {
const start = timestamp();
const uniqueNames: Map<string> = {};
const uniqueNames = createMap<string>();
if (symbols) {
for (const symbol of symbols) {
const entry = createCompletionEntry(symbol, location, performCharacterChecks);
if (entry) {
const id = escapeIdentifier(entry.name);
if (!lookUp(uniqueNames, id)) {
if (!uniqueNames[id]) {
entries.push(entry);
uniqueNames[id] = id;
}
@ -4324,22 +4346,58 @@ namespace ts {
return undefined;
}
const argumentInfo = SignatureHelp.getContainingArgumentInfo(node, position, sourceFile);
if (argumentInfo) {
// Get string literal completions from specialized signatures of the target
return getStringLiteralCompletionEntriesFromCallExpression(argumentInfo);
if (node.parent.kind === SyntaxKind.PropertyAssignment && node.parent.parent.kind === SyntaxKind.ObjectLiteralExpression) {
// Get quoted name of properties of the object literal expression
// i.e. interface ConfigFiles {
// 'jspm:dev': string
// }
// let files: ConfigFiles = {
// '/*completion position*/'
// }
//
// function foo(c: ConfigFiles) {}
// foo({
// '/*completion position*/'
// });
return getStringLiteralCompletionEntriesFromPropertyAssignment(<ObjectLiteralElement>node.parent);
}
else if (isElementAccessExpression(node.parent) && node.parent.argumentExpression === node) {
// Get all names of properties on the expression
// i.e. interface A {
// 'prop1': string
// }
// let a: A;
// a['/*completion position*/']
return getStringLiteralCompletionEntriesFromElementAccess(node.parent);
}
else {
// Otherwise, get the completions from the contextual type if one exists
const argumentInfo = SignatureHelp.getContainingArgumentInfo(node, position, sourceFile);
if (argumentInfo) {
// Get string literal completions from specialized signatures of the target
// i.e. declare function f(a: 'A');
// f("/*completion position*/")
return getStringLiteralCompletionEntriesFromCallExpression(argumentInfo, node);
}
// Get completion for string literal from string literal type
// i.e. var x: "hi" | "hello" = "/*completion position*/"
return getStringLiteralCompletionEntriesFromContextualType(<StringLiteral>node);
}
}
function getStringLiteralCompletionEntriesFromCallExpression(argumentInfo: SignatureHelp.ArgumentListInfo) {
function getStringLiteralCompletionEntriesFromPropertyAssignment(element: ObjectLiteralElement) {
const typeChecker = program.getTypeChecker();
const type = typeChecker.getContextualType((<ObjectLiteralExpression>element.parent));
const entries: CompletionEntry[] = [];
if (type) {
getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, element, /*performCharacterChecks*/false);
if (entries.length) {
return { isMemberCompletion: true, isNewIdentifierLocation: true, entries };
}
}
}
function getStringLiteralCompletionEntriesFromCallExpression(argumentInfo: SignatureHelp.ArgumentListInfo, location: Node) {
const typeChecker = program.getTypeChecker();
const candidates: Signature[] = [];
const entries: CompletionEntry[] = [];
@ -4396,7 +4454,7 @@ namespace ts {
else {
if (type.flags & TypeFlags.StringLiteral) {
result.push({
name: (<StringLiteralType>type).text,
name: (<LiteralType>type).text,
kindModifiers: ScriptElementKindModifier.none,
kind: ScriptElementKind.variableElement,
sortText: "0"
@ -4697,7 +4755,7 @@ namespace ts {
displayParts.push(spacePart());
displayParts.push(operatorPart(SyntaxKind.EqualsToken));
displayParts.push(spacePart());
addRange(displayParts, typeToDisplayParts(typeChecker, typeChecker.getDeclaredTypeOfSymbol(symbol), enclosingDeclaration));
addRange(displayParts, typeToDisplayParts(typeChecker, typeChecker.getDeclaredTypeOfSymbol(symbol), enclosingDeclaration, TypeFormatFlags.InTypeAlias));
}
if (symbolFlags & SymbolFlags.Enum) {
addNewLineIfDisplayPartsExist();
@ -4777,7 +4835,14 @@ namespace ts {
}
if (symbolFlags & SymbolFlags.Alias) {
addNewLineIfDisplayPartsExist();
displayParts.push(keywordPart(SyntaxKind.ImportKeyword));
if (symbol.declarations[0].kind === SyntaxKind.NamespaceExportDeclaration) {
displayParts.push(keywordPart(SyntaxKind.ExportKeyword));
displayParts.push(spacePart());
displayParts.push(keywordPart(SyntaxKind.NamespaceKeyword));
}
else {
displayParts.push(keywordPart(SyntaxKind.ImportKeyword));
}
displayParts.push(spacePart());
addFullSymbolName(symbol);
ts.forEach(symbol.declarations, declaration => {
@ -5091,7 +5156,7 @@ namespace ts {
// Type reference directives
const typeReferenceDirective = findReferenceInPosition(sourceFile.typeReferenceDirectives, position);
if (typeReferenceDirective) {
const referenceFile = lookUp(program.getResolvedTypeReferenceDirectives(), typeReferenceDirective.fileName);
const referenceFile = program.getResolvedTypeReferenceDirectives()[typeReferenceDirective.fileName];
if (referenceFile && referenceFile.resolvedFileName) {
return [getDefinitionInfoForFileReference(typeReferenceDirective.fileName, referenceFile.resolvedFileName)];
}
@ -5184,7 +5249,7 @@ namespace ts {
return undefined;
}
if (type.flags & TypeFlags.Union) {
if (type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Enum)) {
const result: DefinitionInfo[] = [];
forEach((<UnionType>type).types, t => {
if (t.symbol) {
@ -5258,12 +5323,12 @@ namespace ts {
return undefined;
}
const fileNameToDocumentHighlights: Map<DocumentHighlights> = {};
const fileNameToDocumentHighlights = createMap<DocumentHighlights>();
const result: DocumentHighlights[] = [];
for (const referencedSymbol of referencedSymbols) {
for (const referenceEntry of referencedSymbol.references) {
const fileName = referenceEntry.fileName;
let documentHighlights = getProperty(fileNameToDocumentHighlights, fileName);
let documentHighlights = fileNameToDocumentHighlights[fileName];
if (!documentHighlights) {
documentHighlights = { fileName, highlightSpans: [] };
@ -6008,7 +6073,7 @@ namespace ts {
const nameTable = getNameTable(sourceFile);
if (lookUp(nameTable, internedName) !== undefined) {
if (nameTable[internedName] !== undefined) {
result = result || [];
getReferencesInNode(sourceFile, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex);
}
@ -6653,7 +6718,7 @@ namespace ts {
// Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions
if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ {});
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ createMap<Symbol>());
}
});
@ -6685,7 +6750,7 @@ namespace ts {
// the function will add any found symbol of the property-name, then its sub-routine will call
// getPropertySymbolsFromBaseTypes again to walk up any base types to prevent revisiting already
// visited symbol, interface "C", the sub-routine will pass the current symbol as previousIterationSymbol.
if (hasProperty(previousIterationSymbolsCache, symbol.name)) {
if (symbol.name in previousIterationSymbolsCache) {
return;
}
@ -6774,7 +6839,7 @@ namespace ts {
// see if any is in the list
if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
const result: Symbol[] = [];
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ {});
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ createMap<Symbol>());
return forEach(result, s => searchSymbols.indexOf(s) >= 0 ? s : undefined);
}
@ -7098,7 +7163,6 @@ namespace ts {
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.QualifiedName:
case SyntaxKind.StringLiteral:
case SyntaxKind.StringLiteralType:
case SyntaxKind.FalseKeyword:
case SyntaxKind.TrueKeyword:
case SyntaxKind.NullKeyword:
@ -7602,7 +7666,7 @@ namespace ts {
else if (tokenKind === SyntaxKind.NumericLiteral) {
return ClassificationType.numericLiteral;
}
else if (tokenKind === SyntaxKind.StringLiteral || tokenKind === SyntaxKind.StringLiteralType) {
else if (tokenKind === SyntaxKind.StringLiteral) {
return token.parent.kind === SyntaxKind.JsxAttribute ? ClassificationType.jsxAttributeStringLiteralValue : ClassificationType.stringLiteral;
}
else if (tokenKind === SyntaxKind.RegularExpressionLiteral) {
@ -8097,11 +8161,11 @@ namespace ts {
}
}
function getStringLiteralTypeForNode(node: StringLiteral | StringLiteralTypeNode, typeChecker: TypeChecker): StringLiteralType {
const searchNode = node.parent.kind === SyntaxKind.StringLiteralType ? <StringLiteralTypeNode>node.parent : node;
function getStringLiteralTypeForNode(node: StringLiteral | LiteralTypeNode, typeChecker: TypeChecker): LiteralType {
const searchNode = node.parent.kind === SyntaxKind.LiteralType ? <LiteralTypeNode>node.parent : node;
const type = typeChecker.getTypeAtLocation(searchNode);
if (type && type.flags & TypeFlags.StringLiteral) {
return <StringLiteralType>type;
return <LiteralType>type;
}
return undefined;
}
@ -8259,7 +8323,7 @@ namespace ts {
}
function initializeNameTable(sourceFile: SourceFile): void {
const nameTable: Map<number> = {};
const nameTable = createMap<number>();
walk(sourceFile);
sourceFile.nameTable = nameTable;
@ -8588,7 +8652,7 @@ namespace ts {
addResult(start, end, classFromKind(token));
if (end >= text.length) {
if (token === SyntaxKind.StringLiteral || token === SyntaxKind.StringLiteralType) {
if (token === SyntaxKind.StringLiteral) {
// Check to see if we finished up on a multiline string literal.
const tokenText = scanner.getTokenText();
if (scanner.isUnterminated()) {
@ -8738,7 +8802,6 @@ namespace ts {
case SyntaxKind.NumericLiteral:
return ClassificationType.numericLiteral;
case SyntaxKind.StringLiteral:
case SyntaxKind.StringLiteralType:
return ClassificationType.stringLiteral;
case SyntaxKind.RegularExpressionLiteral:
return ClassificationType.regularExpressionLiteral;

View File

@ -72,8 +72,13 @@ namespace ts {
directoryExists(directoryName: string): boolean;
}
/** Public interface of the the of a config service shim instance.*/
export interface CoreServicesShimHost extends Logger, ModuleResolutionHost {
/** Public interface of the core-services host instance used in managed side */
export interface CoreServicesShimHost extends Logger {
directoryExists(directoryName: string): boolean;
fileExists(fileName: string): boolean;
getCurrentDirectory(): string;
getDirectories(path: string): string;
/**
* Returns a JSON-encoded value of the type: string[]
*
@ -81,9 +86,14 @@ namespace ts {
* when enumerating the directory.
*/
readDirectory(rootDir: string, extension: string, basePaths?: string, excludeEx?: string, includeFileEx?: string, includeDirEx?: string, depth?: number): string;
useCaseSensitiveFileNames?(): boolean;
getCurrentDirectory(): string;
/**
* Read arbitary text files on disk, i.e. when resolution procedure needs the content of 'package.json' to determine location of bundled typings for node modules
*/
readFile(fileName: string): string;
realpath?(path: string): string;
trace(s: string): void;
useCaseSensitiveFileNames?(): boolean;
}
///
@ -240,6 +250,7 @@ namespace ts {
}
export interface CoreServicesShim extends Shim {
getAutomaticTypeDirectiveNames(compilerOptionsJson: string): string;
getPreProcessedFileInfo(fileName: string, sourceText: IScriptSnapshot): string;
getTSConfigFileInfo(fileName: string, sourceText: IScriptSnapshot): string;
getDefaultCompilationSettings(): string;
@ -300,9 +311,9 @@ namespace ts {
// 'in' does not have this effect.
if ("getModuleResolutionsForFile" in this.shimHost) {
this.resolveModuleNames = (moduleNames: string[], containingFile: string) => {
const resolutionsInFile = <Map<string>>JSON.parse(this.shimHost.getModuleResolutionsForFile(containingFile));
const resolutionsInFile = <MapLike<string>>JSON.parse(this.shimHost.getModuleResolutionsForFile(containingFile));
return map(moduleNames, name => {
const result = lookUp(resolutionsInFile, name);
const result = getProperty(resolutionsInFile, name);
return result ? { resolvedFileName: result } : undefined;
});
};
@ -312,8 +323,8 @@ namespace ts {
}
if ("getTypeReferenceDirectiveResolutionsForFile" in this.shimHost) {
this.resolveTypeReferenceDirectives = (typeDirectiveNames: string[], containingFile: string) => {
const typeDirectivesForFile = <Map<ResolvedTypeReferenceDirective>>JSON.parse(this.shimHost.getTypeReferenceDirectiveResolutionsForFile(containingFile));
return map(typeDirectiveNames, name => lookUp(typeDirectivesForFile, name));
const typeDirectivesForFile = <MapLike<ResolvedTypeReferenceDirective>>JSON.parse(this.shimHost.getTypeReferenceDirectiveResolutionsForFile(containingFile));
return map(typeDirectiveNames, name => getProperty(typeDirectivesForFile, name));
};
}
}
@ -492,6 +503,10 @@ namespace ts {
private readDirectoryFallback(rootDir: string, extension: string, exclude: string[]) {
return JSON.parse(this.shimHost.readDirectory(rootDir, extension, JSON.stringify(exclude)));
}
public getDirectories(path: string): string[] {
return JSON.parse(this.shimHost.getDirectories(path));
}
}
function simpleForwardCall(logger: Logger, actionDescription: string, action: () => any, logPerformance: boolean): any {
@ -1003,7 +1018,7 @@ namespace ts {
public getPreProcessedFileInfo(fileName: string, sourceTextSnapshot: IScriptSnapshot): string {
return this.forwardJSONCall(
"getPreProcessedFileInfo('" + fileName + "')",
`getPreProcessedFileInfo('${fileName}')`,
() => {
// for now treat files as JavaScript
const result = preProcessFile(sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength()), /* readImportFiles */ true, /* detectJavaScriptImports */ true);
@ -1017,6 +1032,16 @@ namespace ts {
});
}
public getAutomaticTypeDirectiveNames(compilerOptionsJson: string): string {
return this.forwardJSONCall(
`getAutomaticTypeDirectiveNames('${compilerOptionsJson}')`,
() => {
const compilerOptions = <CompilerOptions>JSON.parse(compilerOptionsJson);
return getAutomaticTypeDirectiveNames(compilerOptions, this.host);
}
);
}
private convertFileReferences(refs: FileReference[]): IFileReference[] {
if (!refs) {
return undefined;

View File

@ -237,7 +237,7 @@ namespace ts.SignatureHelp {
const typeChecker = program.getTypeChecker();
for (const sourceFile of program.getSourceFiles()) {
const nameToDeclarations = sourceFile.getNamedDeclarations();
const declarations = getProperty(nameToDeclarations, name.text);
const declarations = nameToDeclarations[name.text];
if (declarations) {
for (const declaration of declarations) {

View File

@ -434,8 +434,7 @@ namespace ts {
export function isInString(sourceFile: SourceFile, position: number): boolean {
const previousToken = findPrecedingToken(position, sourceFile);
if (previousToken &&
(previousToken.kind === SyntaxKind.StringLiteral || previousToken.kind === SyntaxKind.StringLiteralType)) {
if (previousToken && previousToken.kind === SyntaxKind.StringLiteral) {
const start = previousToken.getStart();
const end = previousToken.getEnd();
@ -633,7 +632,6 @@ namespace ts {
export function isStringOrRegularExpressionOrTemplateLiteral(kind: SyntaxKind): boolean {
if (kind === SyntaxKind.StringLiteral
|| kind === SyntaxKind.StringLiteralType
|| kind === SyntaxKind.RegularExpressionLiteral
|| isTemplateLiteralKind(kind)) {
return true;
@ -922,7 +920,7 @@ namespace ts {
if (host && host.getScriptKind) {
scriptKind = host.getScriptKind(fileName);
}
if (!scriptKind || scriptKind === ScriptKind.Unknown) {
if (!scriptKind) {
scriptKind = getScriptKindFromFileName(fileName);
}
return ensureScriptKind(fileName, scriptKind);

View File

@ -20,7 +20,7 @@ declare var path: any;
import * as ts from "typescript";
function watch(rootFileNames: string[], options: ts.CompilerOptions) {
const files: ts.Map<{ version: number }> = {};
const files: ts.MapLike<{ version: number }> = {};
// initialize the list of files
rootFileNames.forEach(fileName => {

View File

@ -1,4 +1,4 @@
tests/cases/conformance/statements/for-ofStatements/ES5For-of30.ts(3,6): error TS2461: Type 'number | string' is not an array type.
tests/cases/conformance/statements/for-ofStatements/ES5For-of30.ts(3,6): error TS2461: Type 'string | number' is not an array type.
tests/cases/conformance/statements/for-ofStatements/ES5For-of30.ts(3,7): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/statements/for-ofStatements/ES5For-of30.ts(3,14): error TS2322: Type 'string' is not assignable to type 'number'.
@ -8,7 +8,7 @@ tests/cases/conformance/statements/for-ofStatements/ES5For-of30.ts(3,14): error
var tuple: [number, string] = [2, "3"];
for ([a = 1, b = ""] of tuple) {
~~~~~~~~~~~~~~~
!!! error TS2461: Type 'number | string' is not an array type.
!!! error TS2461: Type 'string | number' is not an array type.
~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
~

View File

@ -1,4 +1,4 @@
tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck11.ts(3,6): error TS2322: Type 'number | string' is not assignable to type 'string'.
tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck11.ts(3,6): error TS2322: Type 'string | number' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.
@ -7,5 +7,5 @@ tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck11.ts(3,6)
var v: string;
for (v of union) { }
~
!!! error TS2322: Type 'number | string' is not assignable to type 'string'.
!!! error TS2322: Type 'string | number' is not assignable to type 'string'.
!!! error TS2322: Type 'number' is not assignable to type 'string'.

View File

@ -3,6 +3,6 @@ var union: string | number[];
>union : string | number[]
for (var v of union) { }
>v : number | string
>v : string | number
>union : string | number[]

View File

@ -1,8 +1,8 @@
tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck9.ts(2,15): error TS2461: Type 'string[] | number | symbol' is not an array type.
tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck9.ts(2,15): error TS2461: Type 'number | symbol | string[]' is not an array type.
==== tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck9.ts (1 errors) ====
var union: string | string[] | number | symbol;
for (let v of union) { }
~~~~~
!!! error TS2461: Type 'string[] | number | symbol' is not an array type.
!!! error TS2461: Type 'number | symbol | string[]' is not an array type.

View File

@ -18,7 +18,7 @@ for (let num of array) {
if (sum === 0) {
>sum === 0 : boolean
>sum : number
>0 : number
>0 : 0
array = [4,5,6]
>array = [4,5,6] : number[]

View File

@ -6,15 +6,15 @@ enum Color { R, G, B }
>B : Color
function f1(x: Color | string) {
>f1 : (x: Color | string) => void
>x : Color | string
>f1 : (x: string | Color) => void
>x : string | Color
>Color : Color
if (typeof x === "number") {
>typeof x === "number" : boolean
>typeof x : string
>x : Color | string
>"number" : string
>x : string | Color
>"number" : "number"
var y = x;
>y : Color
@ -35,15 +35,15 @@ function f1(x: Color | string) {
}
function f2(x: Color | string | string[]) {
>f2 : (x: Color | string | string[]) => void
>x : Color | string | string[]
>f2 : (x: string | Color | string[]) => void
>x : string | Color | string[]
>Color : Color
if (typeof x === "object") {
>typeof x === "object" : boolean
>typeof x : string
>x : Color | string | string[]
>"object" : string
>x : string | Color | string[]
>"object" : "object"
var y = x;
>y : string[]
@ -55,8 +55,8 @@ function f2(x: Color | string | string[]) {
if (typeof x === "number") {
>typeof x === "number" : boolean
>typeof x : string
>x : string[] | Color | string
>"number" : string
>x : string | Color | string[]
>"number" : "number"
var z = x;
>z : Color
@ -68,17 +68,17 @@ function f2(x: Color | string | string[]) {
}
else {
var w = x;
>w : string[] | string
>x : string[] | string
>w : string | string[]
>x : string | string[]
var w: string | string[];
>w : string[] | string
>w : string | string[]
}
if (typeof x === "string") {
>typeof x === "string" : boolean
>typeof x : string
>x : Color | string[] | string
>"string" : string
>x : string | Color | string[]
>"string" : "string"
var a = x;
>a : string

View File

@ -0,0 +1,31 @@
//// [abstractClassInLocalScope.ts]
(() => {
abstract class A {}
class B extends A {}
new B();
return A;
})();
//// [abstractClassInLocalScope.js]
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function () {
var A = (function () {
function A() {
}
return A;
}());
var B = (function (_super) {
__extends(B, _super);
function B() {
_super.apply(this, arguments);
}
return B;
}(A));
new B();
return A;
})();

View File

@ -0,0 +1,17 @@
=== tests/cases/compiler/abstractClassInLocalScope.ts ===
(() => {
abstract class A {}
>A : Symbol(A, Decl(abstractClassInLocalScope.ts, 0, 8))
class B extends A {}
>B : Symbol(B, Decl(abstractClassInLocalScope.ts, 1, 23))
>A : Symbol(A, Decl(abstractClassInLocalScope.ts, 0, 8))
new B();
>B : Symbol(B, Decl(abstractClassInLocalScope.ts, 1, 23))
return A;
>A : Symbol(A, Decl(abstractClassInLocalScope.ts, 0, 8))
})();

View File

@ -0,0 +1,22 @@
=== tests/cases/compiler/abstractClassInLocalScope.ts ===
(() => {
>(() => { abstract class A {} class B extends A {} new B(); return A;})() : typeof A
>(() => { abstract class A {} class B extends A {} new B(); return A;}) : () => typeof A
>() => { abstract class A {} class B extends A {} new B(); return A;} : () => typeof A
abstract class A {}
>A : A
class B extends A {}
>B : B
>A : A
new B();
>new B() : B
>B : typeof B
return A;
>A : typeof A
})();

View File

@ -0,0 +1,13 @@
tests/cases/compiler/abstractClassInLocalScopeIsAbstract.ts(4,5): error TS2511: Cannot create an instance of the abstract class 'A'.
==== tests/cases/compiler/abstractClassInLocalScopeIsAbstract.ts (1 errors) ====
(() => {
abstract class A {}
class B extends A {}
new A();
~~~~~~~
!!! error TS2511: Cannot create an instance of the abstract class 'A'.
new B();
})()

View File

@ -0,0 +1,31 @@
//// [abstractClassInLocalScopeIsAbstract.ts]
(() => {
abstract class A {}
class B extends A {}
new A();
new B();
})()
//// [abstractClassInLocalScopeIsAbstract.js]
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function () {
var A = (function () {
function A() {
}
return A;
}());
var B = (function (_super) {
__extends(B, _super);
function B() {
_super.apply(this, arguments);
}
return B;
}(A));
new A();
new B();
})();

View File

@ -34,7 +34,7 @@ var d2: IHasVisualizationModel = i || moduleA;
var d2: IHasVisualizationModel = moduleA || i;
>d2 : IHasVisualizationModel
>IHasVisualizationModel : IHasVisualizationModel
>moduleA || i : typeof moduleA
>moduleA || i : IHasVisualizationModel
>moduleA : typeof moduleA
>i : IHasVisualizationModel

View File

@ -0,0 +1,17 @@
tests/cases/compiler/a.ts(2,5): error TS2339: Property 'default' does not exist on type 'typeof "tests/cases/compiler/b"'.
tests/cases/compiler/a.ts(3,5): error TS2339: Property 'default' does not exist on type 'typeof "tests/cases/compiler/b"'.
==== tests/cases/compiler/a.ts (2 errors) ====
import Foo = require("./b");
Foo.default.bar();
~~~~~~~
!!! error TS2339: Property 'default' does not exist on type 'typeof "tests/cases/compiler/b"'.
Foo.default.default.foo();
~~~~~~~
!!! error TS2339: Property 'default' does not exist on type 'typeof "tests/cases/compiler/b"'.
==== tests/cases/compiler/b.d.ts (0 errors) ====
export function foo();
export function bar();

View File

@ -0,0 +1,17 @@
//// [tests/cases/compiler/allowSyntheticDefaultImports10.ts] ////
//// [b.d.ts]
export function foo();
export function bar();
//// [a.ts]
import Foo = require("./b");
Foo.default.bar();
Foo.default.default.foo();
//// [a.js]
"use strict";
var Foo = require("./b");
Foo.default.bar();
Foo.default.default.foo();

View File

@ -0,0 +1,28 @@
//// [tests/cases/compiler/allowSyntheticDefaultImports7.ts] ////
//// [b.d.ts]
export function foo();
export function bar();
//// [a.ts]
import { default as Foo } from "./b";
Foo.bar();
Foo.foo();
//// [a.js]
System.register(["./b"], function(exports_1, context_1) {
"use strict";
var __moduleName = context_1 && context_1.id;
var b_1;
return {
setters:[
function (b_1_1) {
b_1 = b_1_1;
}],
execute: function() {
b_1["default"].bar();
b_1["default"].foo();
}
}
});

View File

@ -0,0 +1,22 @@
=== tests/cases/compiler/b.d.ts ===
export function foo();
>foo : Symbol(foo, Decl(b.d.ts, 0, 0))
export function bar();
>bar : Symbol(bar, Decl(b.d.ts, 0, 22))
=== tests/cases/compiler/a.ts ===
import { default as Foo } from "./b";
>default : Symbol(Foo, Decl(a.ts, 0, 8))
>Foo : Symbol(Foo, Decl(a.ts, 0, 8))
Foo.bar();
>Foo.bar : Symbol(Foo.bar, Decl(b.d.ts, 0, 22))
>Foo : Symbol(Foo, Decl(a.ts, 0, 8))
>bar : Symbol(Foo.bar, Decl(b.d.ts, 0, 22))
Foo.foo();
>Foo.foo : Symbol(Foo.foo, Decl(b.d.ts, 0, 0))
>Foo : Symbol(Foo, Decl(a.ts, 0, 8))
>foo : Symbol(Foo.foo, Decl(b.d.ts, 0, 0))

View File

@ -0,0 +1,24 @@
=== tests/cases/compiler/b.d.ts ===
export function foo();
>foo : () => any
export function bar();
>bar : () => any
=== tests/cases/compiler/a.ts ===
import { default as Foo } from "./b";
>default : typeof Foo
>Foo : typeof Foo
Foo.bar();
>Foo.bar() : any
>Foo.bar : () => any
>Foo : typeof Foo
>bar : () => any
Foo.foo();
>Foo.foo() : any
>Foo.foo : () => any
>Foo : typeof Foo
>foo : () => any

View File

@ -0,0 +1,14 @@
tests/cases/compiler/a.ts(1,10): error TS2305: Module '"tests/cases/compiler/b"' has no exported member 'default'.
==== tests/cases/compiler/b.d.ts (0 errors) ====
export function foo();
export function bar();
==== tests/cases/compiler/a.ts (1 errors) ====
import { default as Foo } from "./b";
~~~~~~~
!!! error TS2305: Module '"tests/cases/compiler/b"' has no exported member 'default'.
Foo.bar();
Foo.foo();

View File

@ -0,0 +1,28 @@
//// [tests/cases/compiler/allowSyntheticDefaultImports8.ts] ////
//// [b.d.ts]
export function foo();
export function bar();
//// [a.ts]
import { default as Foo } from "./b";
Foo.bar();
Foo.foo();
//// [a.js]
System.register(["./b"], function(exports_1, context_1) {
"use strict";
var __moduleName = context_1 && context_1.id;
var b_1;
return {
setters:[
function (b_1_1) {
b_1 = b_1_1;
}],
execute: function() {
b_1["default"].bar();
b_1["default"].foo();
}
}
});

View File

@ -0,0 +1,17 @@
//// [tests/cases/compiler/allowSyntheticDefaultImports9.ts] ////
//// [b.d.ts]
export function foo();
export function bar();
//// [a.ts]
import { default as Foo } from "./b";
Foo.bar();
Foo.foo();
//// [a.js]
"use strict";
var b_1 = require("./b");
b_1["default"].bar();
b_1["default"].foo();

View File

@ -0,0 +1,22 @@
=== tests/cases/compiler/b.d.ts ===
export function foo();
>foo : Symbol(foo, Decl(b.d.ts, 0, 0))
export function bar();
>bar : Symbol(bar, Decl(b.d.ts, 0, 22))
=== tests/cases/compiler/a.ts ===
import { default as Foo } from "./b";
>default : Symbol(Foo, Decl(a.ts, 0, 8))
>Foo : Symbol(Foo, Decl(a.ts, 0, 8))
Foo.bar();
>Foo.bar : Symbol(Foo.bar, Decl(b.d.ts, 0, 22))
>Foo : Symbol(Foo, Decl(a.ts, 0, 8))
>bar : Symbol(Foo.bar, Decl(b.d.ts, 0, 22))
Foo.foo();
>Foo.foo : Symbol(Foo.foo, Decl(b.d.ts, 0, 0))
>Foo : Symbol(Foo, Decl(a.ts, 0, 8))
>foo : Symbol(Foo.foo, Decl(b.d.ts, 0, 0))

View File

@ -0,0 +1,24 @@
=== tests/cases/compiler/b.d.ts ===
export function foo();
>foo : () => any
export function bar();
>bar : () => any
=== tests/cases/compiler/a.ts ===
import { default as Foo } from "./b";
>default : typeof Foo
>Foo : typeof Foo
Foo.bar();
>Foo.bar() : any
>Foo.bar : () => any
>Foo : typeof Foo
>bar : () => any
Foo.foo();
>Foo.foo() : any
>Foo.foo : () => any
>Foo : typeof Foo
>foo : () => any

View File

@ -0,0 +1,13 @@
=== tests/cases/compiler/a.d.ts ===
declare namespace ns {
>ns : Symbol(ns, Decl(a.d.ts, 0, 0))
class SecondNS extends FirstNS { }
>SecondNS : Symbol(SecondNS, Decl(a.d.ts, 1, 22))
>FirstNS : Symbol(FirstNS, Decl(a.d.ts, 2, 36))
class FirstNS { }
>FirstNS : Symbol(FirstNS, Decl(a.d.ts, 2, 36))
}

View File

@ -0,0 +1,13 @@
=== tests/cases/compiler/a.d.ts ===
declare namespace ns {
>ns : typeof ns
class SecondNS extends FirstNS { }
>SecondNS : SecondNS
>FirstNS : FirstNS
class FirstNS { }
>FirstNS : FirstNS
}

View File

@ -1,8 +0,0 @@
tests/cases/conformance/ambient/ambientShorthand_isImplicitAny.ts(1,16): error TS7005: Variable '"jquery"' implicitly has an 'any' type.
==== tests/cases/conformance/ambient/ambientShorthand_isImplicitAny.ts (1 errors) ====
declare module "jquery";
~~~~~~~~
!!! error TS7005: Variable '"jquery"' implicitly has an 'any' type.

View File

@ -1,5 +0,0 @@
//// [ambientShorthand_isImplicitAny.ts]
declare module "jquery";
//// [ambientShorthand_isImplicitAny.js]

View File

@ -4,12 +4,12 @@ import foo = require("./foo_0");
if(foo.E1.A === 0){
>foo.E1.A === 0 : boolean
>foo.E1.A : foo.E1
>foo.E1.A : foo.E1.A
>foo.E1 : typeof foo.E1
>foo : typeof foo
>E1 : typeof foo.E1
>A : foo.E1
>0 : number
>A : foo.E1.A
>0 : 0
// Should cause runtime import - interesting optimization possibility, as gets inlined to 0.
}

View File

@ -41,7 +41,7 @@ var e: number = <foo.E1>0;
><foo.E1>0 : foo.E1
>foo : any
>E1 : foo.E1
>0 : number
>0 : 0
=== tests/cases/conformance/externalModules/foo_0.ts ===
export class C1 {

View File

@ -6,5 +6,5 @@ function f() {
>typeof class {} === "function" : boolean
>typeof class {} : string
>class {} : typeof (Anonymous class)
>"function" : string
>"function" : "function"
}

View File

@ -366,22 +366,22 @@ module EmptyTypes {
>base2 : typeof base2
var b1 = [baseObj, base2Obj, ifaceObj];
>b1 : base[]
>[baseObj, base2Obj, ifaceObj] : base[]
>b1 : iface[]
>[baseObj, base2Obj, ifaceObj] : iface[]
>baseObj : base
>base2Obj : base2
>ifaceObj : iface
var b2 = [base2Obj, baseObj, ifaceObj];
>b2 : base2[]
>[base2Obj, baseObj, ifaceObj] : base2[]
>b2 : iface[]
>[base2Obj, baseObj, ifaceObj] : iface[]
>base2Obj : base2
>baseObj : base
>ifaceObj : iface
var b3 = [baseObj, ifaceObj, base2Obj];
>b3 : base[]
>[baseObj, ifaceObj, base2Obj] : base[]
>b3 : iface[]
>[baseObj, ifaceObj, base2Obj] : iface[]
>baseObj : base
>ifaceObj : iface
>base2Obj : base2

View File

@ -3,21 +3,21 @@ var a: string[] = [];
>a : Symbol(a, Decl(arrayConcat2.ts, 0, 3))
a.concat("hello", 'world');
>a.concat : Symbol(Array.concat, Decl(lib.d.ts, --, --))
>a.concat : Symbol(Array.concat, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>a : Symbol(a, Decl(arrayConcat2.ts, 0, 3))
>concat : Symbol(Array.concat, Decl(lib.d.ts, --, --))
>concat : Symbol(Array.concat, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
a.concat('Hello');
>a.concat : Symbol(Array.concat, Decl(lib.d.ts, --, --))
>a.concat : Symbol(Array.concat, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>a : Symbol(a, Decl(arrayConcat2.ts, 0, 3))
>concat : Symbol(Array.concat, Decl(lib.d.ts, --, --))
>concat : Symbol(Array.concat, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
var b = new Array<string>();
>b : Symbol(b, Decl(arrayConcat2.ts, 5, 3))
>Array : Symbol(Array, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
b.concat('hello');
>b.concat : Symbol(Array.concat, Decl(lib.d.ts, --, --))
>b.concat : Symbol(Array.concat, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>b : Symbol(b, Decl(arrayConcat2.ts, 5, 3))
>concat : Symbol(Array.concat, Decl(lib.d.ts, --, --))
>concat : Symbol(Array.concat, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))

View File

@ -5,17 +5,17 @@ var a: string[] = [];
a.concat("hello", 'world');
>a.concat("hello", 'world') : string[]
>a.concat : (...items: (string | string[])[]) => string[]
>a.concat : { (...items: string[][]): string[]; (...items: (string | string[])[]): string[]; }
>a : string[]
>concat : (...items: (string | string[])[]) => string[]
>concat : { (...items: string[][]): string[]; (...items: (string | string[])[]): string[]; }
>"hello" : string
>'world' : string
a.concat('Hello');
>a.concat('Hello') : string[]
>a.concat : (...items: (string | string[])[]) => string[]
>a.concat : { (...items: string[][]): string[]; (...items: (string | string[])[]): string[]; }
>a : string[]
>concat : (...items: (string | string[])[]) => string[]
>concat : { (...items: string[][]): string[]; (...items: (string | string[])[]): string[]; }
>'Hello' : string
var b = new Array<string>();
@ -25,8 +25,8 @@ var b = new Array<string>();
b.concat('hello');
>b.concat('hello') : string[]
>b.concat : (...items: (string | string[])[]) => string[]
>b.concat : { (...items: string[][]): string[]; (...items: (string | string[])[]): string[]; }
>b : string[]
>concat : (...items: (string | string[])[]) => string[]
>concat : { (...items: string[][]): string[]; (...items: (string | string[])[]): string[]; }
>'hello' : string

View File

@ -2,8 +2,8 @@
var x = [].concat([{ a: 1 }], [{ a: 2 }])
>x : Symbol(x, Decl(arrayConcatMap.ts, 0, 3))
>[].concat([{ a: 1 }], [{ a: 2 }]) .map : Symbol(Array.map, Decl(lib.d.ts, --, --))
>[].concat : Symbol(Array.concat, Decl(lib.d.ts, --, --))
>concat : Symbol(Array.concat, Decl(lib.d.ts, --, --))
>[].concat : Symbol(Array.concat, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>concat : Symbol(Array.concat, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>a : Symbol(a, Decl(arrayConcatMap.ts, 0, 20))
>a : Symbol(a, Decl(arrayConcatMap.ts, 0, 32))

View File

@ -4,9 +4,9 @@ var x = [].concat([{ a: 1 }], [{ a: 2 }])
>[].concat([{ a: 1 }], [{ a: 2 }]) .map(b => b.a) : any[]
>[].concat([{ a: 1 }], [{ a: 2 }]) .map : <U>(callbackfn: (value: any, index: number, array: any[]) => U, thisArg?: any) => U[]
>[].concat([{ a: 1 }], [{ a: 2 }]) : any[]
>[].concat : (...items: any[]) => any[]
>[].concat : { (...items: any[][]): any[]; (...items: any[]): any[]; }
>[] : undefined[]
>concat : (...items: any[]) => any[]
>concat : { (...items: any[][]): any[]; (...items: any[]): any[]; }
>[{ a: 1 }] : { a: number; }[]
>{ a: 1 } : { a: number; }
>a : number

View File

@ -1,7 +1,7 @@
=== tests/cases/compiler/arrayLiteralComments.ts ===
var testArrayWithFunc = [
>testArrayWithFunc : ((() => void) | string | number | { a: number; } | number[])[]
>[ // Function comment function() { let x = 1; }, // String comment '1', // Numeric comment 2, // Object comment { a: 1 }, // Array comment [1, 2, 3]] : ((() => void) | string | number | { a: number; } | number[])[]
>testArrayWithFunc : (string | number | (() => void) | number[] | { a: number; })[]
>[ // Function comment function() { let x = 1; }, // String comment '1', // Numeric comment 2, // Object comment { a: 1 }, // Array comment [1, 2, 3]] : (string | number | (() => void) | number[] | { a: number; })[]
// Function comment
function() {

View File

@ -1,7 +1,7 @@
tests/cases/conformance/expressions/contextualTyping/arrayLiteralExpressionContextualTyping.ts(8,5): error TS2322: Type '[number, number, number, string]' is not assignable to type '[number, number, number]'.
Types of property 'pop' are incompatible.
Type '() => number | string' is not assignable to type '() => number'.
Type 'number | string' is not assignable to type 'number'.
Type '() => string | number' is not assignable to type '() => number'.
Type 'string | number' is not assignable to type 'number'.
Type 'string' is not assignable to type 'number'.
tests/cases/conformance/expressions/contextualTyping/arrayLiteralExpressionContextualTyping.ts(14,5): error TS2322: Type 'number[]' is not assignable to type '[number, number, number]'.
Property '0' is missing in type 'number[]'.
@ -19,8 +19,8 @@ tests/cases/conformance/expressions/contextualTyping/arrayLiteralExpressionConte
~~~~
!!! error TS2322: Type '[number, number, number, string]' is not assignable to type '[number, number, number]'.
!!! error TS2322: Types of property 'pop' are incompatible.
!!! error TS2322: Type '() => number | string' is not assignable to type '() => number'.
!!! error TS2322: Type 'number | string' is not assignable to type 'number'.
!!! error TS2322: Type '() => string | number' is not assignable to type '() => number'.
!!! error TS2322: Type 'string | number' is not assignable to type 'number'.
!!! error TS2322: Type 'string' is not assignable to type 'number'.
// In a contextually typed array literal expression containing one or more spread elements,

View File

@ -23,8 +23,8 @@ var as = [a, b]; // { x: number; y?: number };[]
>b : { x: number; z?: number; }
var bs = [b, a]; // { x: number; z?: number };[]
>bs : ({ x: number; z?: number; } | { x: number; y?: number; })[]
>[b, a] : ({ x: number; z?: number; } | { x: number; y?: number; })[]
>bs : ({ x: number; y?: number; } | { x: number; z?: number; })[]
>[b, a] : ({ x: number; y?: number; } | { x: number; z?: number; })[]
>b : { x: number; z?: number; }
>a : { x: number; y?: number; }

View File

@ -24,8 +24,8 @@ var a1 = ["hello", "world"]
>"world" : string
var a2 = [, , , ...a0, "hello"];
>a2 : (number | string)[]
>[, , , ...a0, "hello"] : (number | string)[]
>a2 : (string | number)[]
>[, , , ...a0, "hello"] : (string | number)[]
> : undefined
> : undefined
> : undefined
@ -151,8 +151,8 @@ interface myArray2 extends Array<Number|String> { }
>String : String
var d0 = [1, true, ...temp,]; // has type (string|number|boolean)[]
>d0 : (number | boolean | string)[]
>[1, true, ...temp,] : (number | boolean | string)[]
>d0 : (string | number | boolean)[]
>[1, true, ...temp,] : (string | number | boolean)[]
>1 : number
>true : boolean
>...temp : string
@ -214,8 +214,8 @@ var d8: number[][] = [[...temp1]]
>temp1 : number[]
var d9 = [[...temp1], ...["hello"]];
>d9 : (number[] | string)[]
>[[...temp1], ...["hello"]] : (number[] | string)[]
>d9 : (string | number[])[]
>[[...temp1], ...["hello"]] : (string | number[])[]
>[...temp1] : number[]
>...temp1 : number
>temp1 : number[]

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