Merge branch 'master' into dynamicNames

This commit is contained in:
Ron Buckton
2017-09-21 12:48:51 -07:00
5815 changed files with 341076 additions and 236283 deletions
+3 -1
View File
@@ -57,4 +57,6 @@ internal/
!tests/cases/projects/NodeModulesSearch/**/*
!tests/baselines/reference/project/nodeModules*/**/*
.idea
yarn.lock
yarn.lock
package-lock.json
.parallelperf.json
+11 -2
View File
@@ -17,6 +17,8 @@ Andy Hanson <anhans@microsoft.com> Andy <anhans@microsoft.com>
Anil Anar <anilanar@hotmail.com>
Anton Tolmachev <myste@mail.ru>
Anubha Mathur <anubmat@microsoft.com> anubmat <anubmat@microsoft.com>
Armando Aguirre <armando.aguirre@microsoft.com>
Arnaud Tournier <ltearno@gmail.com>
Arnavion <arnavion@gmail.com> # Arnav Singh
Arthur Ozga <aozgaa@umich.edu> Arthur Ozga <t-arthoz@microsoft.com> Arthur Ozga <aozgaa-ms@outlook.com> Arthur Ozga <aozgaa@users.noreply.github.com> Arthur Ozga <arozga@microsoft.com>
Asad Saeeduddin <masaeedu@gmail.com>
@@ -26,6 +28,7 @@ Bill Ticehurst <billti@hotmail.com> Bill Ticehurst <billti@microsoft.com>
Ben Duffield <jebavarde@gmail.com>
Ben Mosher <me@benmosher.com>
Benjamin Bock <bb@users.noreply.github.com>
Benjamin Lichtman <uniqueiniquity@users.noreply.github.com> uniqueiniquity <blichtman623@gmail.com>
Blake Embrey <hello@blakeembrey.com>
Bowden Kelly <wilkelly@microsoft.com>
Brett Mayen <bmayen@midnightsnacks.net>
@@ -59,6 +62,7 @@ Evan Sebastian <evanlhoini@gmail.com>
Eyas <eyas.sharaiha@gmail.com> # Eyas Sharaiha
Fabian Cook <faybecook@gmail.com>
falsandtru <falsandtru@users.noreply.github.com> # @falsandtru
Filipe Silva <filipematossilva@gmail.com>
flowmemo <flowmemo@outlook.com> # @flowmemo
Frank Wallis <fwallis@outlook.com>
František Žiacik <fziacik@gratex.com> František Žiacik <ziacik@gmail.com>
@@ -192,7 +196,7 @@ TruongSinh Tran-Nguyen <i@truongsinh.pro>
vilicvane <i@vilic.info> # Vilic Vane
Vladimir Matveev <vladima@microsoft.com> vladima <vladima@microsoft.com> v2m <desco.by@gmail.com>
Vadi Taslim <vadz77@hotmail.com>
Wesley Wigham <t-weswig@microsoft.com> Wesley Wigham <wwigham@gmail.com>
Wesley Wigham <t-weswig@microsoft.com> Wesley Wigham <wwigham@gmail.com> Wesley Wigham <wewigham@microsoft.com>
York Yao <plantain-00@users.noreply.github.com> york yao <yaoao12306@outlook.com> yaoyao <yaoyao12306@163.com>
Yuichi Nukiyama <oscar.wilde84@hotmail.co.jp> YuichiNukiyama <oscar.wilde84@hotmail.co.jp>
Zev Spitz <shivisi@etrog.net.il>
@@ -267,4 +271,9 @@ Reiner Dolp <reiner-dolp@users.noreply.github.com>
t_ <t-mrt@users.noreply.github.com> # @t_
TravCav <xurrux@gmail.com> # @TravCav
Vladimir Kurchatkin <vladimir.kurchatkin@gmail.com>
William Orr <will@worrbase.com>
William Orr <will@worrbase.com>
Francois Wouts <f@codonut.com>
Jan Melcher <jan.melcher@aeb.com> Jan Melcher <mail@jan-melcher.de>
Matt Mitchell <mmitche@microsoft.com>
Maxwell Paul Brickner <mbrickn@users.noreply.github.com>
Tycho Grouwstra <tychogrouwstra@gmail.com>
+2 -1
View File
@@ -16,4 +16,5 @@ Jakefile.js
.gitattributes
.settings/
.travis.yml
.vscode/
.vscode/
test.config
+1 -3
View File
@@ -16,9 +16,7 @@ matrix:
branches:
only:
- master
- release-2.1
- release-2.2
- release-2.3
- release-2.5
install:
- npm uninstall typescript --no-save
+7
View File
@@ -18,6 +18,13 @@
"problemMatcher": [
"$tsc"
]
},
{
"taskName": "tests",
"showOutput": "silent",
"problemMatcher": [
"$tsc"
]
}
]
}
+9
View File
@@ -25,6 +25,8 @@ TypeScript is authored by:
* Anton Khlynovskiy
* Anton Tolmachev
* Anubha Mathur
* Armando Aguirre
* Arnaud Tournier
* Arnav Singh
* Arthur Ozga
* Asad Saeeduddin
@@ -33,6 +35,7 @@ TypeScript is authored by:
* Ben Duffield
* Ben Mosher
* Benjamin Bock
* Benjamin Lichtman
* Benny Neugebauer
* Bill Ticehurst
* Blaine Bublitz
@@ -85,7 +88,9 @@ TypeScript is authored by:
* Eyas Sharaiha
* Fabian Cook
* @falsandtru
* Filipe Silva
* @flowmemo
* Francois Wouts
* Frank Wallis
* Franklin Tse
* František Žiacik
@@ -112,6 +117,7 @@ TypeScript is authored by:
* Jakub Młokosiewicz
* James Henry
* James Whitney
* Jan Melcher
* Jason Freeman
* Jason Jarrett
* Jason Killian
@@ -162,9 +168,11 @@ TypeScript is authored by:
* Masahiro Wakame
* Matt Bierner
* Matt McCutchen
* Matt Mitchell
* Mattias Buelens
* Mattias Buelens
* Max Deepfield
* Maxwell Paul Brickner
* Micah Zoltu
* Michael
* Michael Bromley
@@ -243,6 +251,7 @@ TypeScript is authored by:
* Torben Fitschen
* @TravCav
* TruongSinh Tran-Nguyen
* Tycho Grouwstra
* Vadi Taslim
* Vidar Tonaas Fauske
* Viktor Zozulyak
+89 -76
View File
@@ -28,12 +28,9 @@ import minimist = require("minimist");
import browserify = require("browserify");
import through2 = require("through2");
import merge2 = require("merge2");
import intoStream = require("into-stream");
import * as os from "os";
import fold = require("travis-fold");
const gulp = helpMaker(originalGulp);
const mochaParallel = require("./scripts/mocha-parallel.js");
const {runTestsInParallel} = mochaParallel;
Error.stackTraceLimit = 1000;
@@ -256,14 +253,8 @@ function needsUpdate(source: string | string[], dest: string | string[]): boolea
return true;
}
// Doing tsconfig inheritance manually. https://github.com/ivogabe/gulp-typescript/issues/459
const tsconfigBase = JSON.parse(fs.readFileSync("src/tsconfig-base.json", "utf-8")).compilerOptions;
function getCompilerSettings(base: tsc.Settings, useBuiltCompiler?: boolean): tsc.Settings {
const copy: tsc.Settings = {};
for (const key in tsconfigBase) {
copy[key] = tsconfigBase[key];
}
for (const key in base) {
copy[key] = base[key];
}
@@ -300,7 +291,7 @@ gulp.task("configure-nightly", "Runs scripts/configureNightly.ts to prepare a bu
exec(host, [configureNightlyJs, packageJson, versionFile], done, done);
});
gulp.task("publish-nightly", "Runs `npm publish --tag next` to create a new nightly build on npm", ["LKG"], () => {
return runSequence("clean", "useDebugMode", "runtests", (done) => {
return runSequence("clean", "useDebugMode", "runtests-parallel", (done) => {
exec("npm", ["publish", "--tag", "next"], done, done);
});
});
@@ -470,10 +461,11 @@ gulp.task(serverFile, /*help*/ false, [servicesFile, typingsInstallerJs, cancell
.pipe(gulp.dest("src/server"));
});
const typesMapJson = path.join(builtLocalDirectory, "typesMap.json");
const tsserverLibraryFile = path.join(builtLocalDirectory, "tsserverlibrary.js");
const tsserverLibraryDefinitionFile = path.join(builtLocalDirectory, "tsserverlibrary.d.ts");
gulp.task(tsserverLibraryFile, /*help*/ false, [servicesFile], (done) => {
gulp.task(tsserverLibraryFile, /*help*/ false, [servicesFile, typesMapJson], (done) => {
const serverLibraryProject = tsc.createProject("src/server/tsconfig.library.json", getCompilerSettings({}, /*useBuiltCompiler*/ true));
const {js, dts}: { js: NodeJS.ReadableStream, dts: NodeJS.ReadableStream } = serverLibraryProject.src()
.pipe(sourcemaps.init())
@@ -492,6 +484,15 @@ gulp.task(tsserverLibraryFile, /*help*/ false, [servicesFile], (done) => {
]);
});
gulp.task(typesMapJson, /*help*/ false, [], () => {
return gulp.src("src/server/typesMap.json")
.pipe(insert.transform((contents, file) => {
JSON.parse(contents);
return contents;
}))
.pipe(gulp.dest(builtLocalDirectory));
});
gulp.task("lssl", "Builds language service server library", [tsserverLibraryFile]);
gulp.task("local", "Builds the full compiler and services", [builtLocalCompiler, servicesFile, serverFile, builtGeneratedDiagnosticMessagesJSON, tsserverLibraryFile]);
gulp.task("tsc", "Builds only the compiler", [builtLocalCompiler]);
@@ -561,7 +562,7 @@ gulp.task(run, /*help*/ false, [servicesFile], () => {
.pipe(newer(run))
.pipe(sourcemaps.init())
.pipe(testProject())
.pipe(sourcemaps.write(".", { includeContent: false, sourceRoot: "../../" }))
.pipe(sourcemaps.write(".", { includeContent: false, sourceRoot: "." }))
.pipe(gulp.dest("src/harness"));
});
@@ -665,36 +666,18 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done:
}
else {
// run task to load all tests and partition them between workers
const args = [];
args.push("-R", "min");
if (colors) {
args.push("--colors");
}
else {
args.push("--no-colors");
}
args.push(run);
setNodeEnvToDevelopment();
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) {
lintThenFinish();
}
else {
finish(err);
}
});
exec(host, [run], lintThenFinish, function(e, status) {
finish(e, status);
});
}
});
function failWithStatus(err?: any, status?: number) {
if (err) {
console.log(err);
if (err || status) {
process.exit(typeof status === "number" ? status : 2);
}
done(err || status);
process.exit(status);
done();
}
function lintThenFinish() {
@@ -708,7 +691,7 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done:
function finish(error?: any, errorStatus?: number) {
restoreSavedNodeEnv();
deleteTemporaryProjectOutput().then(() => {
deleteTestConfig().then(deleteTemporaryProjectOutput).then(() => {
if (error !== undefined || errorStatus !== undefined) {
failWithStatus(error, errorStatus);
}
@@ -717,6 +700,10 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done:
}
});
}
function deleteTestConfig() {
return del("test.config");
}
}
gulp.task("runtests-parallel", "Runs all the tests in parallel using the built run.js file. Optional arguments are: --t[ests]=category1|category2|... --d[ebug]=true.", ["build-rules", "tests"], (done) => {
@@ -743,50 +730,75 @@ gulp.task(nodeServerOutFile, /*help*/ false, [servicesFile], () => {
import convertMap = require("convert-source-map");
import sorcery = require("sorcery");
declare module "convert-source-map" {
export function fromSource(source: string, largeSource?: boolean): SourceMapConverter;
}
import Vinyl = require("vinyl");
const bundlePath = path.resolve("built/local/bundle.js");
gulp.task("browserify", "Runs browserify on run.js to produce a file suitable for running tests in the browser", [servicesFile], (done) => {
const testProject = tsc.createProject("src/harness/tsconfig.json", getCompilerSettings({ outFile: "../../built/local/bundle.js" }, /*useBuiltCompiler*/ true));
return testProject.src()
.pipe(newer("built/local/bundle.js"))
const testProject = tsc.createProject("src/harness/tsconfig.json", getCompilerSettings({ outFile: bundlePath, inlineSourceMap: true }, /*useBuiltCompiler*/ true));
let originalMap: any;
let prebundledContent: string;
browserify(testProject.src()
.pipe(newer(bundlePath))
.pipe(sourcemaps.init())
.pipe(testProject())
.pipe(through2.obj((file, enc, next) => {
const originalMap = file.sourceMap;
const prebundledContent = file.contents.toString();
if (originalMap) {
throw new Error("Should only recieve one file!");
}
console.log(`Saving sourcemaps for ${file.path}`);
originalMap = file.sourceMap;
prebundledContent = file.contents.toString();
// Make paths absolute to help sorcery deal with all the terrible paths being thrown around
originalMap.sources = originalMap.sources.map(s => path.resolve(path.join("src/harness", s)));
// intoStream (below) makes browserify think the input file is named this, so this is what it puts in the sourcemap
// browserify names input files this when they are streamed in, so this is what it puts in the sourcemap
originalMap.file = "built/local/_stream_0.js";
browserify(intoStream(file.contents), { debug: true })
.bundle((err, res) => {
// assumes file.contents is a Buffer
const maps = JSON.parse(convertMap.fromSource(res.toString(), /*largeSource*/ true).toJSON());
delete maps.sourceRoot;
maps.sources = maps.sources.map(s => path.resolve(s === "_stream_0.js" ? "built/local/_stream_0.js" : s));
// Strip browserify's inline comments away (could probably just let sorcery do this, but then we couldn't fix the paths)
file.contents = new Buffer(convertMap.removeComments(res.toString()));
const chain = sorcery.loadSync("built/local/bundle.js", {
content: {
"built/local/_stream_0.js": prebundledContent,
"built/local/bundle.js": file.contents.toString()
},
sourcemaps: {
"built/local/_stream_0.js": originalMap,
"built/local/bundle.js": maps,
"node_modules/source-map-support/source-map-support.js": undefined,
}
});
const finalMap = chain.apply();
file.sourceMap = finalMap;
next(/*err*/ undefined, file);
});
next(/*err*/ undefined, file.contents);
}))
.pipe(sourcemaps.write(".", { includeContent: false }))
.pipe(gulp.dest("src/harness"));
.on("error", err => {
return done(err);
}), { debug: true, basedir: __dirname }) // Attach error handler to inner stream
.bundle((err, contents) => {
if (err) {
if (err.message.match(/Cannot find module '.*_stream_0.js'/)) {
return done(); // Browserify errors when we pass in no files when `newer` filters the input, we should count that as a success, though
}
return done(err);
}
const stringContent = contents.toString();
const file = new Vinyl({ contents, path: bundlePath });
console.log(`Fixing sourcemaps for ${file.path}`);
// assumes contents is a Buffer, since that's what browserify yields
const maps = convertMap.fromSource(stringContent).toObject();
delete maps.sourceRoot;
maps.sources = maps.sources.map(s => path.resolve(s === "_stream_0.js" ? "built/local/_stream_0.js" : s));
// Strip browserify's inline comments away (could probably just let sorcery do this, but then we couldn't fix the paths)
file.contents = new Buffer(convertMap.removeComments(stringContent));
const chain = sorcery.loadSync(bundlePath, {
content: {
"built/local/_stream_0.js": prebundledContent,
[bundlePath]: stringContent
},
sourcemaps: {
"built/local/_stream_0.js": originalMap,
[bundlePath]: maps,
"node_modules/source-map-support/source-map-support.js": undefined,
}
});
const finalMap = chain.apply();
file.sourceMap = finalMap;
const stream = through2.obj((file, enc, callback) => {
return callback(/*err*/ undefined, file);
});
stream.pipe(sourcemaps.write(".", { includeContent: false }))
.pipe(gulp.dest("."))
.on("end", done)
.on("error", done);
stream.write(file);
stream.end();
});
});
@@ -808,7 +820,7 @@ function cleanTestDirs(done: (e?: any) => void) {
// used to pass data from jake command line directly to run.js
function writeTestConfigFile(tests: string, light: boolean, taskConfigsFolder?: string, workerCount?: number, stackTraceLimit?: string) {
const testConfigContents = JSON.stringify({ test: tests ? [tests] : undefined, light, workerCount, stackTraceLimit, taskConfigsFolder });
const testConfigContents = JSON.stringify({ test: tests ? [tests] : undefined, light, workerCount, stackTraceLimit, taskConfigsFolder, noColor: !cmdLineOptions["colors"] });
console.log("Running tests with config: " + testConfigContents);
fs.writeFileSync("test.config", testConfigContents);
}
@@ -950,7 +962,7 @@ const instrumenterPath = path.join(harnessDirectory, "instrumenter.ts");
const instrumenterJsPath = path.join(builtLocalDirectory, "instrumenter.js");
gulp.task(instrumenterJsPath, /*help*/ false, [servicesFile], () => {
const settings: tsc.Settings = getCompilerSettings({
outFile: instrumenterJsPath,
module: "commonjs",
target: "es5",
lib: [
"es6",
@@ -962,8 +974,8 @@ gulp.task(instrumenterJsPath, /*help*/ false, [servicesFile], () => {
.pipe(newer(instrumenterJsPath))
.pipe(sourcemaps.init())
.pipe(tsc(settings))
.pipe(sourcemaps.write("."))
.pipe(gulp.dest("."));
.pipe(sourcemaps.write(builtLocalDirectory))
.pipe(gulp.dest(builtLocalDirectory));
});
gulp.task("tsc-instrumented", "Builds an instrumented tsc.js", ["local", loggedIOJsPath, instrumenterJsPath, servicesFile], (done) => {
@@ -1038,10 +1050,11 @@ gulp.task("lint", "Runs tslint on the compiler sources. Optional arguments are:
const fileMatcher = cmdLineOptions["files"];
const files = fileMatcher
? `src/**/${fileMatcher}`
: "Gulpfile.ts 'scripts/tslint/*.ts' 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts'";
const cmd = `node node_modules/tslint/bin/tslint ${files} --format stylish`;
: "Gulpfile.ts 'scripts/tslint/**/*.ts' 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts'";
const cmd = `node node_modules/tslint/bin/tslint ${files} --formatters-dir ./built/local/tslint/formatters --format autolinkableStylish`;
console.log("Linting: " + cmd);
child_process.execSync(cmd, { stdio: [0, 1, 2] });
if (fold.isTravis()) console.log(fold.end("lint"));
});
gulp.task("default", "Runs 'local'", ["local"]);
+77 -59
View File
@@ -1,11 +1,11 @@
// This file contains the build logic for the public repo
// @ts-check
var fs = require("fs");
var os = require("os");
var path = require("path");
var child_process = require("child_process");
var fold = require("travis-fold");
var runTestsInParallel = require("./scripts/mocha-parallel").runTestsInParallel;
var ts = require("./lib/typescript");
@@ -38,7 +38,7 @@ else if (process.env.PATH !== undefined) {
function filesFromConfig(configPath) {
var configText = fs.readFileSync(configPath).toString();
var config = ts.parseConfigFileTextToJson(configPath, configText, /*stripComments*/ true);
var config = ts.parseConfigFileTextToJson(configPath, configText);
if (config.error) {
throw new Error(diagnosticsToString([config.error]));
}
@@ -88,6 +88,8 @@ var watchGuardSources = filesFromConfig(path.join(serverDirectory, "watchGuard/t
var serverSources = filesFromConfig(path.join(serverDirectory, "tsconfig.json"))
var languageServiceLibrarySources = filesFromConfig(path.join(serverDirectory, "tsconfig.library.json"));
var typesMapOutputPath = path.join(builtLocalDirectory, 'typesMap.json');
var harnessCoreSources = [
"harness.ts",
"virtualFileSystem.ts",
@@ -102,6 +104,9 @@ var harnessCoreSources = [
"loggedIO.ts",
"rwcRunner.ts",
"test262Runner.ts",
"./parallel/shared.ts",
"./parallel/host.ts",
"./parallel/worker.ts",
"runner.ts"
].map(function (f) {
return path.join(harnessDirectory, f);
@@ -133,11 +138,15 @@ var harnessSources = harnessCoreSources.concat([
"projectErrors.ts",
"matchFiles.ts",
"initializeTSConfig.ts",
"extractMethods.ts",
"printer.ts",
"textChanges.ts",
"telemetry.ts",
"transform.ts",
"customTransforms.ts",
"programMissingFiles.ts",
"symbolWalker.ts",
"languageService.ts",
].map(function (f) {
return path.join(unittestsDirectory, f);
})).concat([
@@ -286,7 +295,7 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts
var startCompileTime = mark();
opts = opts || {};
var compilerPath = useBuiltCompiler ? builtLocalCompiler : LKGCompiler;
var options = "--noImplicitAny --noImplicitThis --noEmitOnError --types "
var options = "--noImplicitAny --noImplicitThis --alwaysStrict --noEmitOnError --types "
if (opts.types) {
options += opts.types.join(",");
}
@@ -421,6 +430,7 @@ var buildProtocolTs = path.join(scriptsDirectory, "buildProtocol.ts");
var buildProtocolJs = path.join(scriptsDirectory, "buildProtocol.js");
var buildProtocolDts = path.join(builtLocalDirectory, "protocol.d.ts");
var typescriptServicesDts = path.join(builtLocalDirectory, "typescriptServices.d.ts");
var typesMapJson = path.join(builtLocalDirectory, "typesMap.json");
file(buildProtocolTs);
@@ -504,7 +514,7 @@ task("configure-nightly", [configureNightlyJs], function () {
}, { async: true });
desc("Configure, build, test, and publish the nightly release.");
task("publish-nightly", ["configure-nightly", "LKG", "clean", "setDebugMode", "runtests"], function () {
task("publish-nightly", ["configure-nightly", "LKG", "clean", "setDebugMode", "runtests-parallel"], function () {
var cmd = "npm publish --tag next";
console.log(cmd);
exec(cmd);
@@ -532,7 +542,6 @@ var tscFile = path.join(builtLocalDirectory, compilerFilename);
compileFile(tscFile, compilerSources, [builtLocalDirectory, copyright].concat(compilerSources), [copyright], /*useBuiltCompiler:*/ false);
var servicesFile = path.join(builtLocalDirectory, "typescriptServices.js");
var servicesFileInBrowserTest = path.join(builtLocalDirectory, "typescriptServicesInBrowserTest.js");
var standaloneDefinitionsFile = path.join(builtLocalDirectory, "typescriptServices.d.ts");
var nodePackageFile = path.join(builtLocalDirectory, "typescript.js");
var nodeDefinitionsFile = path.join(builtLocalDirectory, "typescript.d.ts");
@@ -571,22 +580,6 @@ compileFile(servicesFile, servicesSources, [builtLocalDirectory, copyright].conc
fs.writeFileSync(nodeStandaloneDefinitionsFile, nodeStandaloneDefinitionsFileContents);
});
compileFile(
servicesFileInBrowserTest,
servicesSources,
[builtLocalDirectory, copyright].concat(servicesSources),
/*prefixes*/[copyright],
/*useBuiltCompiler*/ true,
{
noOutFile: false,
generateDeclarations: true,
preserveConstEnums: true,
keepComments: true,
noResolve: false,
stripInternal: true,
inlineSourceMap: true
});
file(typescriptServicesDts, [servicesFile]);
var cancellationTokenFile = path.join(builtLocalDirectory, "cancellationToken.js");
@@ -602,6 +595,16 @@ var serverFile = path.join(builtLocalDirectory, "tsserver.js");
compileFile(serverFile, serverSources, [builtLocalDirectory, copyright, cancellationTokenFile, typingsInstallerFile, watchGuardFile].concat(serverSources).concat(servicesSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { types: ["node"], preserveConstEnums: true, lib: "es6" });
var tsserverLibraryFile = path.join(builtLocalDirectory, "tsserverlibrary.js");
var tsserverLibraryDefinitionFile = path.join(builtLocalDirectory, "tsserverlibrary.d.ts");
file(typesMapOutputPath, function() {
var content = fs.readFileSync(path.join(serverDirectory, 'typesMap.json'));
// Validate that it's valid JSON
try {
JSON.parse(content.toString());
} catch (e) {
console.log("Parse error in typesMap.json: " + e);
}
fs.writeFileSync(typesMapOutputPath, content);
});
compileFile(
tsserverLibraryFile,
languageServiceLibrarySources,
@@ -624,7 +627,7 @@ compileFile(
// Local target to build the language service server library
desc("Builds language service server library");
task("lssl", [tsserverLibraryFile, tsserverLibraryDefinitionFile]);
task("lssl", [tsserverLibraryFile, tsserverLibraryDefinitionFile, typesMapOutputPath]);
desc("Emit the start of the build fold");
task("build-fold-start", [], function () {
@@ -653,7 +656,6 @@ task("release", function () {
// Set the default task to "local"
task("default", ["local"]);
// Cleans the built directory
desc("Cleans the compiler output, declare files, and tests");
task("clean", function () {
@@ -724,7 +726,7 @@ compileFile(
/*prereqs*/[builtLocalDirectory, tscFile].concat(libraryTargets).concat(servicesSources).concat(harnessSources),
/*prefixes*/[],
/*useBuiltCompiler:*/ true,
/*opts*/ { inlineSourceMap: true, types: ["node", "mocha", "chai"], lib: "es6" });
/*opts*/ { types: ["node", "mocha", "chai"], lib: "es6" });
var internalTests = "internal/";
@@ -741,7 +743,7 @@ desc("Builds the test infrastructure using the built compiler");
task("tests", ["local", run].concat(libraryTargets));
function exec(cmd, completeHandler, errorHandler) {
var ex = jake.createExec([cmd], { windowsVerbatimArguments: true });
var ex = jake.createExec([cmd], { windowsVerbatimArguments: true, interactive: true });
// Add listeners for output and error
ex.addListener("stdout", function (output) {
process.stdout.write(output);
@@ -767,15 +769,16 @@ function exec(cmd, completeHandler, errorHandler) {
ex.run();
}
const del = require("del");
function cleanTestDirs() {
// Clean the local baselines directory
if (fs.existsSync(localBaseline)) {
jake.rmRf(localBaseline);
del.sync(localBaseline);
}
// Clean the local Rwc baselines directory
if (fs.existsSync(localRwcBaseline)) {
jake.rmRf(localRwcBaseline);
del.sync(localRwcBaseline);
}
jake.mkdirP(localRwcBaseline);
@@ -784,13 +787,14 @@ function cleanTestDirs() {
}
// used to pass data from jake command line directly to run.js
function writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, stackTraceLimit) {
function writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, stackTraceLimit, colors) {
var testConfigContents = JSON.stringify({
test: tests ? [tests] : undefined,
light: light,
workerCount: workerCount,
taskConfigsFolder: taskConfigsFolder,
stackTraceLimit: stackTraceLimit
stackTraceLimit: stackTraceLimit,
noColor: !colors
});
fs.writeFileSync('test.config', testConfigContents);
}
@@ -832,14 +836,15 @@ function runConsoleTests(defaultReporter, runInParallel) {
}
if (tests || light || taskConfigsFolder) {
writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, stackTraceLimit);
writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, stackTraceLimit, colors);
}
if (tests && tests.toLocaleLowerCase() === "rwc") {
testTimeout = 800000;
}
var colors = process.env.colors || process.env.color || true;
var colorsFlag = process.env.color || process.env.colors;
var colors = colorsFlag !== "false" && colorsFlag !== "0";
var reporter = process.env.reporter || process.env.r || defaultReporter;
var bail = process.env.bail || process.env.b;
var lintFlag = process.env.lint !== 'false';
@@ -894,19 +899,15 @@ function runConsoleTests(defaultReporter, runInParallel) {
var savedNodeEnv = process.env.NODE_ENV;
process.env.NODE_ENV = "development";
var startTime = mark();
runTestsInParallel(taskConfigsFolder, run, { testTimeout: testTimeout, noColors: !colors }, function (err) {
exec(host + " " + run, function () {
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);
if (err) {
fail(err);
}
else {
runLinter();
complete();
}
runLinter();
finish();
}, function (e, status) {
process.env.NODE_ENV = savedNodeEnv;
measure(startTime);
finish(status);
});
}
@@ -959,17 +960,18 @@ var nodeServerInFile = "tests/webTestServer.ts";
compileFile(nodeServerOutFile, [nodeServerInFile], [builtLocalDirectory, tscFile], [], /*useBuiltCompiler:*/ true, { noOutFile: true, lib: "es6" });
desc("Runs browserify on run.js to produce a file suitable for running tests in the browser");
task("browserify", ["tests", builtLocalDirectory, nodeServerOutFile], function() {
var cmd = 'browserify built/local/run.js -t ./scripts/browserify-optional -d -o built/local/bundle.js';
task("browserify", [], function() {
// Shell out to `gulp`, since we do the work to handle sourcemaps correctly w/o inline maps there
var cmd = 'gulp browserify --silent';
exec(cmd);
}, { async: true });
desc("Runs the tests using the built run.js file like 'jake runtests'. Syntax is jake runtests-browser. Additional optional parameters tests=[regex], browser=[chrome|IE]");
task("runtests-browser", ["tests", "browserify", builtLocalDirectory, servicesFileInBrowserTest], function () {
task("runtests-browser", ["browserify", nodeServerOutFile], function () {
cleanTestDirs();
host = "node";
browser = process.env.browser || process.env.b || (os.platform() === "linux" ? "chrome" : "IE");
tests = process.env.test || process.env.tests || process.env.t;
var browser = process.env.browser || process.env.b || (os.platform() === "linux" ? "chrome" : "IE");
var tests = process.env.test || process.env.tests || process.env.t;
var light = process.env.light || false;
var testConfigFile = 'test.config';
if (fs.existsSync(testConfigFile)) {
@@ -1041,6 +1043,7 @@ function acceptBaseline(sourceFolder, targetFolder) {
if (fs.existsSync(target)) {
fs.unlinkSync(target);
}
jake.mkdirP(path.dirname(target));
fs.renameSync(path.join(sourceFolder, filename), target);
}
}
@@ -1099,7 +1102,7 @@ file(loggedIOJsPath, [builtLocalDirectory, loggedIOpath], function () {
var instrumenterPath = harnessDirectory + 'instrumenter.ts';
var instrumenterJsPath = builtLocalDirectory + 'instrumenter.js';
compileFile(instrumenterJsPath, [instrumenterPath], [tscFile, instrumenterPath].concat(libraryTargets), [], /*useBuiltCompiler*/ true, { lib: "es6", types: ["node"] });
compileFile(instrumenterJsPath, [instrumenterPath], [tscFile, instrumenterPath].concat(libraryTargets), [], /*useBuiltCompiler*/ true, { lib: "es6", types: ["node"], noOutFile: true, outDir: builtLocalDirectory });
desc("Builds an instrumented tsc.js");
task('tsc-instrumented', [loggedIOJsPath, instrumenterJsPath, tscFile], function () {
@@ -1118,28 +1121,43 @@ task("update-sublime", ["local", serverFile], function () {
jake.cpR(serverFile + ".map", "../TypeScript-Sublime-Plugin/tsserver/");
});
var tslintRuleDir = "scripts/tslint";
var tslintRuleDir = "scripts/tslint/rules";
var tslintRules = [
"nextLineRule",
"booleanTriviaRule",
"typeOperatorSpacingRule",
"noInOperatorRule",
"debugAssertRule",
"nextLineRule",
"noBomRule",
"noIncrementDecrementRule",
"objectLiteralSurroundingSpaceRule",
"noInOperatorRule",
"noTypeAssertionWhitespaceRule",
"noBomRule"
"objectLiteralSurroundingSpaceRule",
"typeOperatorSpacingRule",
];
var tslintRulesFiles = tslintRules.map(function (p) {
return path.join(tslintRuleDir, p + ".ts");
});
var tslintRulesOutFiles = tslintRules.map(function (p) {
return path.join(builtLocalDirectory, "tslint", p + ".js");
return path.join(builtLocalDirectory, "tslint/rules", p + ".js");
});
var tslintFormattersDir = "scripts/tslint/formatters";
var tslintFormatters = [
"autolinkableStylishFormatter",
];
var tslintFormatterFiles = tslintFormatters.map(function (p) {
return path.join(tslintFormattersDir, p + ".ts");
});
var tslintFormattersOutFiles = tslintFormatters.map(function (p) {
return path.join(builtLocalDirectory, "tslint/formatters", p + ".js");
});
desc("Compiles tslint rules to js");
task("build-rules", ["build-rules-start"].concat(tslintRulesOutFiles).concat(["build-rules-end"]));
task("build-rules", ["build-rules-start"].concat(tslintRulesOutFiles).concat(tslintFormattersOutFiles).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"), lib: "es6" });
{ noOutFile: true, generateDeclarations: false, outDir: path.join(builtLocalDirectory, "tslint/rules"), lib: "es6" });
});
tslintFormatterFiles.forEach(function (ruleFile, i) {
compileFile(tslintFormattersOutFiles[i], [ruleFile], [ruleFile], [], /*useBuiltCompiler*/ false,
{ noOutFile: true, generateDeclarations: false, outDir: path.join(builtLocalDirectory, "tslint/formatters"), lib: "es6" });
});
desc("Emit the start of the build-rules fold");
@@ -1207,8 +1225,8 @@ task("lint", ["build-rules"], () => {
const fileMatcher = process.env.f || process.env.file || process.env.files;
const files = fileMatcher
? `src/**/${fileMatcher}`
: "Gulpfile.ts 'scripts/tslint/*.ts' 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts'";
const cmd = `node node_modules/tslint/bin/tslint ${files} --format stylish`;
: "Gulpfile.ts 'scripts/tslint/**/*.ts' 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts'";
const cmd = `node node_modules/tslint/bin/tslint ${files} --formatters-dir ./built/local/tslint/formatters --format autolinkableStylish`;
console.log("Linting: " + cmd);
jake.exec([cmd], { interactive: true }, () => {
if (fold.isTravis()) console.log(fold.end("lint"));
+13 -13
View File
@@ -6,19 +6,19 @@
[![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](https://blogs.msdn.microsoft.com/typescript) and [Twitter account](https://twitter.com/typescriptlang).
[TypeScript](https://www.typescriptlang.org/) is a language for application-scale JavaScript. TypeScript adds optional types, classes, and modules to JavaScript. TypeScript supports tools for large-scale JavaScript applications for any browser, for any host, on any OS. TypeScript compiles to readable, standards-based JavaScript. Try it out at the [playground](https://www.typescriptlang.org/play/), and stay up to date via [our blog](https://blogs.msdn.microsoft.com/typescript) and [Twitter account](https://twitter.com/typescriptlang).
## Installing
For the latest stable version:
```
```bash
npm install -g typescript
```
For our nightly builds:
```
```bash
npm install -g typescript@next
```
@@ -27,8 +27,8 @@ npm install -g typescript@next
There are many ways to [contribute](https://github.com/Microsoft/TypeScript/blob/master/CONTRIBUTING.md) to TypeScript.
* [Submit bugs](https://github.com/Microsoft/TypeScript/issues) and help us verify fixes as they are checked in.
* Review the [source code changes](https://github.com/Microsoft/TypeScript/pulls).
* Engage with other TypeScript users and developers on [StackOverflow](http://stackoverflow.com/questions/tagged/typescript).
* Join the [#typescript](http://twitter.com/#!/search/realtime/%23typescript) discussion on Twitter.
* Engage with other TypeScript users and developers on [StackOverflow](https://stackoverflow.com/questions/tagged/typescript).
* Join the [#typescript](https://twitter.com/#!/search/realtime/%23typescript) discussion on Twitter.
* [Contribute bug fixes](https://github.com/Microsoft/TypeScript/blob/master/CONTRIBUTING.md).
* Read the language specification ([docx](https://github.com/Microsoft/TypeScript/blob/master/doc/TypeScript%20Language%20Specification.docx?raw=true),
[pdf](https://github.com/Microsoft/TypeScript/blob/master/doc/TypeScript%20Language%20Specification.pdf?raw=true), [md](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md)).
@@ -39,30 +39,30 @@ with any additional questions or comments.
## Documentation
* [Quick tutorial](http://www.typescriptlang.org/docs/tutorial.html)
* [Programming handbook](http://www.typescriptlang.org/docs/handbook/basic-types.html)
* [Quick tutorial](https://www.typescriptlang.org/docs/tutorial.html)
* [Programming handbook](https://www.typescriptlang.org/docs/handbook/basic-types.html)
* [Language specification](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md)
* [Homepage](http://www.typescriptlang.org/)
* [Homepage](https://www.typescriptlang.org/)
## Building
In order to build the TypeScript compiler, ensure that you have [Git](http://git-scm.com/downloads) and [Node.js](http://nodejs.org/) installed.
In order to build the TypeScript compiler, ensure that you have [Git](https://git-scm.com/downloads) and [Node.js](https://nodejs.org/) installed.
Clone a copy of the repo:
```
```bash
git clone https://github.com/Microsoft/TypeScript.git
```
Change to the TypeScript directory:
```
```bash
cd TypeScript
```
Install Gulp tools and dev dependencies:
```
```bash
npm install -g gulp
npm install
```
@@ -88,7 +88,7 @@ gulp help # List the above commands.
## Usage
```shell
```bash
node built/local/tsc.js hello.ts
```
+2 -2
View File
@@ -2,13 +2,13 @@
<!-- QUESTIONS: This is not a general support forum! Ask Qs at http://stackoverflow.com/questions/tagged/typescript -->
<!-- SUGGESTIONS: See https://github.com/Microsoft/TypeScript-wiki/blob/master/Writing-Good-Design-Proposals.md -->
**TypeScript Version:** 2.2.1 / nightly (2.2.0-dev.201xxxxx)
**TypeScript Version:** 2.4.0 / nightly (2.5.0-dev.201xxxxx)
**Code**
```ts
// A *self-contained* demonstration of the problem follows...
// Test this by running `tsc` on the command-line, rather than through another build tool such as Gulp, Webpack, etc.
```
**Expected behavior:**
+4352 -4809
View File
File diff suppressed because it is too large Load Diff
+4200 -4452
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -21,8 +21,8 @@ and limitations under the License.
/// <reference path="lib.es2015.core.d.ts" />
/// <reference path="lib.es2015.collection.d.ts" />
/// <reference path="lib.es2015.generator.d.ts" />
/// <reference path="lib.es2015.iterable.d.ts" />
/// <reference path="lib.es2015.promise.d.ts" />
/// <reference path="lib.es2015.iterable.d.ts" />
/// <reference path="lib.es2015.proxy.d.ts" />
/// <reference path="lib.es2015.reflect.d.ts" />
/// <reference path="lib.es2015.symbol.d.ts" />
+1 -1
View File
@@ -130,7 +130,7 @@ interface Map<K, V> {
readonly [Symbol.toStringTag]: "Map";
}
interface WeakMap<K extends object, V>{
interface WeakMap<K extends object, V> {
readonly [Symbol.toStringTag]: "WeakMap";
}
+4201 -4453
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -22,4 +22,4 @@ and limitations under the License.
/// <reference path="lib.es2017.object.d.ts" />
/// <reference path="lib.es2017.sharedmemory.d.ts" />
/// <reference path="lib.es2017.string.d.ts" />
/// <reference path="lib.es2017.intl.d.ts" />
/// <reference path="lib.es2017.intl.d.ts" />
+4202 -4453
View File
File diff suppressed because it is too large Load Diff
+30
View File
@@ -0,0 +1,30 @@
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/// <reference no-default-lib="true"/>
type DateTimeFormatPartTypes = "day" | "dayPeriod" | "era" | "hour" | "literal" | "minute" | "month" | "second" | "timeZoneName" | "weekday" | "year";
interface DateTimeFormatPart {
type: DateTimeFormatPartTypes;
value: string;
}
interface DateTimeFormat {
formatToParts(date?: Date | number): DateTimeFormatPart[];
}
+152 -357
View File
File diff suppressed because it is too large Load Diff
+4353 -4810
View File
File diff suppressed because it is too large Load Diff
+4201 -4453
View File
File diff suppressed because it is too large Load Diff
+145 -134
View File
@@ -20,7 +20,7 @@ and limitations under the License.
/////////////////////////////
/// IE Worker APIs
/// Worker APIs
/////////////////////////////
interface Algorithm {
@@ -28,16 +28,16 @@ interface Algorithm {
}
interface CacheQueryOptions {
ignoreSearch?: boolean;
ignoreMethod?: boolean;
ignoreVary?: boolean;
cacheName?: string;
ignoreMethod?: boolean;
ignoreSearch?: boolean;
ignoreVary?: boolean;
}
interface CloseEventInit extends EventInit {
wasClean?: boolean;
code?: number;
reason?: string;
wasClean?: boolean;
}
interface EventInit {
@@ -69,16 +69,16 @@ interface MessageEventInit extends EventInit {
channel?: string;
data?: any;
origin?: string;
source?: any;
ports?: MessagePort[];
source?: any;
}
interface NotificationOptions {
dir?: NotificationDirection;
lang?: string;
body?: string;
tag?: string;
dir?: NotificationDirection;
icon?: string;
lang?: string;
tag?: string;
}
interface ObjectURLOptions {
@@ -86,29 +86,29 @@ interface ObjectURLOptions {
}
interface PushSubscriptionOptionsInit {
userVisibleOnly?: boolean;
applicationServerKey?: any;
userVisibleOnly?: boolean;
}
interface RequestInit {
method?: string;
headers?: any;
body?: any;
referrer?: string;
referrerPolicy?: ReferrerPolicy;
mode?: RequestMode;
credentials?: RequestCredentials;
cache?: RequestCache;
redirect?: RequestRedirect;
credentials?: RequestCredentials;
headers?: any;
integrity?: string;
keepalive?: boolean;
method?: string;
mode?: RequestMode;
redirect?: RequestRedirect;
referrer?: string;
referrerPolicy?: ReferrerPolicy;
window?: any;
}
interface ResponseInit {
headers?: any;
status?: number;
statusText?: string;
headers?: any;
}
interface ClientQueryOptions {
@@ -176,7 +176,7 @@ interface AudioBuffer {
declare var AudioBuffer: {
prototype: AudioBuffer;
new(): AudioBuffer;
}
};
interface Blob {
readonly size: number;
@@ -189,7 +189,7 @@ interface Blob {
declare var Blob: {
prototype: Blob;
new (blobParts?: any[], options?: BlobPropertyBag): Blob;
}
};
interface Cache {
add(request: RequestInfo): Promise<void>;
@@ -204,7 +204,7 @@ interface Cache {
declare var Cache: {
prototype: Cache;
new(): Cache;
}
};
interface CacheStorage {
delete(cacheName: string): Promise<boolean>;
@@ -217,7 +217,7 @@ interface CacheStorage {
declare var CacheStorage: {
prototype: CacheStorage;
new(): CacheStorage;
}
};
interface CloseEvent extends Event {
readonly code: number;
@@ -229,7 +229,7 @@ interface CloseEvent extends Event {
declare var CloseEvent: {
prototype: CloseEvent;
new(typeArg: string, eventInitDict?: CloseEventInit): CloseEvent;
}
};
interface Console {
assert(test?: boolean, message?: string, ...optionalParams: any[]): void;
@@ -240,8 +240,8 @@ interface Console {
dirxml(value: any): void;
error(message?: any, ...optionalParams: any[]): void;
exception(message?: string, ...optionalParams: any[]): void;
group(groupTitle?: string): void;
groupCollapsed(groupTitle?: string): void;
group(groupTitle?: string, ...optionalParams: any[]): void;
groupCollapsed(groupTitle?: string, ...optionalParams: any[]): void;
groupEnd(): void;
info(message?: any, ...optionalParams: any[]): void;
log(message?: any, ...optionalParams: any[]): void;
@@ -259,7 +259,7 @@ interface Console {
declare var Console: {
prototype: Console;
new(): Console;
}
};
interface Coordinates {
readonly accuracy: number;
@@ -274,7 +274,7 @@ interface Coordinates {
declare var Coordinates: {
prototype: Coordinates;
new(): Coordinates;
}
};
interface CryptoKey {
readonly algorithm: KeyAlgorithm;
@@ -286,7 +286,7 @@ interface CryptoKey {
declare var CryptoKey: {
prototype: CryptoKey;
new(): CryptoKey;
}
};
interface DOMError {
readonly name: string;
@@ -296,7 +296,7 @@ interface DOMError {
declare var DOMError: {
prototype: DOMError;
new(): DOMError;
}
};
interface DOMException {
readonly code: number;
@@ -316,10 +316,10 @@ interface DOMException {
readonly INVALID_STATE_ERR: number;
readonly NAMESPACE_ERR: number;
readonly NETWORK_ERR: number;
readonly NOT_FOUND_ERR: number;
readonly NOT_SUPPORTED_ERR: number;
readonly NO_DATA_ALLOWED_ERR: number;
readonly NO_MODIFICATION_ALLOWED_ERR: number;
readonly NOT_FOUND_ERR: number;
readonly NOT_SUPPORTED_ERR: number;
readonly PARSE_ERR: number;
readonly QUOTA_EXCEEDED_ERR: number;
readonly SECURITY_ERR: number;
@@ -348,10 +348,10 @@ declare var DOMException: {
readonly INVALID_STATE_ERR: number;
readonly NAMESPACE_ERR: number;
readonly NETWORK_ERR: number;
readonly NOT_FOUND_ERR: number;
readonly NOT_SUPPORTED_ERR: number;
readonly NO_DATA_ALLOWED_ERR: number;
readonly NO_MODIFICATION_ALLOWED_ERR: number;
readonly NOT_FOUND_ERR: number;
readonly NOT_SUPPORTED_ERR: number;
readonly PARSE_ERR: number;
readonly QUOTA_EXCEEDED_ERR: number;
readonly SECURITY_ERR: number;
@@ -362,7 +362,7 @@ declare var DOMException: {
readonly URL_MISMATCH_ERR: number;
readonly VALIDATION_ERR: number;
readonly WRONG_DOCUMENT_ERR: number;
}
};
interface DOMStringList {
readonly length: number;
@@ -374,7 +374,7 @@ interface DOMStringList {
declare var DOMStringList: {
prototype: DOMStringList;
new(): DOMStringList;
}
};
interface ErrorEvent extends Event {
readonly colno: number;
@@ -388,12 +388,12 @@ interface ErrorEvent extends Event {
declare var ErrorEvent: {
prototype: ErrorEvent;
new(type: string, errorEventInitDict?: ErrorEventInit): ErrorEvent;
}
};
interface Event {
readonly bubbles: boolean;
cancelBubble: boolean;
readonly cancelable: boolean;
cancelBubble: boolean;
readonly currentTarget: EventTarget;
readonly defaultPrevented: boolean;
readonly eventPhase: number;
@@ -420,7 +420,7 @@ declare var Event: {
readonly AT_TARGET: number;
readonly BUBBLING_PHASE: number;
readonly CAPTURING_PHASE: number;
}
};
interface EventTarget {
addEventListener(type: string, listener?: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
@@ -431,7 +431,7 @@ interface EventTarget {
declare var EventTarget: {
prototype: EventTarget;
new(): EventTarget;
}
};
interface File extends Blob {
readonly lastModifiedDate: any;
@@ -442,7 +442,7 @@ interface File extends Blob {
declare var File: {
prototype: File;
new (parts: (ArrayBuffer | ArrayBufferView | Blob | string)[], filename: string, properties?: FilePropertyBag): File;
}
};
interface FileList {
readonly length: number;
@@ -453,7 +453,7 @@ interface FileList {
declare var FileList: {
prototype: FileList;
new(): FileList;
}
};
interface FileReader extends EventTarget, MSBaseReader {
readonly error: DOMError;
@@ -468,8 +468,17 @@ interface FileReader extends EventTarget, MSBaseReader {
declare var FileReader: {
prototype: FileReader;
new(): FileReader;
};
interface FormData {
append(name: string, value: string | Blob, fileName?: string): void;
}
declare var FormData: {
prototype: FormData;
new(): FormData;
};
interface Headers {
append(name: string, value: string): void;
delete(name: string): void;
@@ -482,7 +491,7 @@ interface Headers {
declare var Headers: {
prototype: Headers;
new(init?: any): Headers;
}
};
interface IDBCursor {
readonly direction: IDBCursorDirection;
@@ -506,7 +515,7 @@ declare var IDBCursor: {
readonly NEXT_NO_DUPLICATE: string;
readonly PREV: string;
readonly PREV_NO_DUPLICATE: string;
}
};
interface IDBCursorWithValue extends IDBCursor {
readonly value: any;
@@ -515,7 +524,7 @@ interface IDBCursorWithValue extends IDBCursor {
declare var IDBCursorWithValue: {
prototype: IDBCursorWithValue;
new(): IDBCursorWithValue;
}
};
interface IDBDatabaseEventMap {
"abort": Event;
@@ -532,7 +541,7 @@ interface IDBDatabase extends EventTarget {
close(): void;
createObjectStore(name: string, optionalParameters?: IDBObjectStoreParameters): IDBObjectStore;
deleteObjectStore(name: string): void;
transaction(storeNames: string | string[], mode?: string): IDBTransaction;
transaction(storeNames: string | string[], mode?: IDBTransactionMode): IDBTransaction;
addEventListener(type: "versionchange", listener: (ev: IDBVersionChangeEvent) => any, useCapture?: boolean): void;
addEventListener<K extends keyof IDBDatabaseEventMap>(type: K, listener: (this: IDBDatabase, ev: IDBDatabaseEventMap[K]) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
@@ -541,7 +550,7 @@ interface IDBDatabase extends EventTarget {
declare var IDBDatabase: {
prototype: IDBDatabase;
new(): IDBDatabase;
}
};
interface IDBFactory {
cmp(first: any, second: any): number;
@@ -552,7 +561,7 @@ interface IDBFactory {
declare var IDBFactory: {
prototype: IDBFactory;
new(): IDBFactory;
}
};
interface IDBIndex {
keyPath: string | string[];
@@ -563,14 +572,14 @@ interface IDBIndex {
count(key?: IDBKeyRange | IDBValidKey): IDBRequest;
get(key: IDBKeyRange | IDBValidKey): IDBRequest;
getKey(key: IDBKeyRange | IDBValidKey): IDBRequest;
openCursor(range?: IDBKeyRange | IDBValidKey, direction?: string): IDBRequest;
openKeyCursor(range?: IDBKeyRange | IDBValidKey, direction?: string): IDBRequest;
openCursor(range?: IDBKeyRange | IDBValidKey, direction?: IDBCursorDirection): IDBRequest;
openKeyCursor(range?: IDBKeyRange | IDBValidKey, direction?: IDBCursorDirection): IDBRequest;
}
declare var IDBIndex: {
prototype: IDBIndex;
new(): IDBIndex;
}
};
interface IDBKeyRange {
readonly lower: any;
@@ -586,7 +595,7 @@ declare var IDBKeyRange: {
lowerBound(lower: any, open?: boolean): IDBKeyRange;
only(value: any): IDBKeyRange;
upperBound(upper: any, open?: boolean): IDBKeyRange;
}
};
interface IDBObjectStore {
readonly indexNames: DOMStringList;
@@ -602,14 +611,14 @@ interface IDBObjectStore {
deleteIndex(indexName: string): void;
get(key: any): IDBRequest;
index(name: string): IDBIndex;
openCursor(range?: IDBKeyRange | IDBValidKey, direction?: string): IDBRequest;
openCursor(range?: IDBKeyRange | IDBValidKey, direction?: IDBCursorDirection): IDBRequest;
put(value: any, key?: IDBKeyRange | IDBValidKey): IDBRequest;
}
declare var IDBObjectStore: {
prototype: IDBObjectStore;
new(): IDBObjectStore;
}
};
interface IDBOpenDBRequestEventMap extends IDBRequestEventMap {
"blocked": Event;
@@ -626,7 +635,7 @@ interface IDBOpenDBRequest extends IDBRequest {
declare var IDBOpenDBRequest: {
prototype: IDBOpenDBRequest;
new(): IDBOpenDBRequest;
}
};
interface IDBRequestEventMap {
"error": Event;
@@ -634,7 +643,7 @@ interface IDBRequestEventMap {
}
interface IDBRequest extends EventTarget {
readonly error: DOMError;
readonly error: DOMException;
onerror: (this: IDBRequest, ev: Event) => any;
onsuccess: (this: IDBRequest, ev: Event) => any;
readonly readyState: IDBRequestReadyState;
@@ -648,7 +657,7 @@ interface IDBRequest extends EventTarget {
declare var IDBRequest: {
prototype: IDBRequest;
new(): IDBRequest;
}
};
interface IDBTransactionEventMap {
"abort": Event;
@@ -658,7 +667,7 @@ interface IDBTransactionEventMap {
interface IDBTransaction extends EventTarget {
readonly db: IDBDatabase;
readonly error: DOMError;
readonly error: DOMException;
readonly mode: IDBTransactionMode;
onabort: (this: IDBTransaction, ev: Event) => any;
oncomplete: (this: IDBTransaction, ev: Event) => any;
@@ -678,7 +687,7 @@ declare var IDBTransaction: {
readonly READ_ONLY: string;
readonly READ_WRITE: string;
readonly VERSION_CHANGE: string;
}
};
interface IDBVersionChangeEvent extends Event {
readonly newVersion: number | null;
@@ -688,7 +697,7 @@ interface IDBVersionChangeEvent extends Event {
declare var IDBVersionChangeEvent: {
prototype: IDBVersionChangeEvent;
new(): IDBVersionChangeEvent;
}
};
interface ImageData {
data: Uint8ClampedArray;
@@ -700,7 +709,7 @@ declare var ImageData: {
prototype: ImageData;
new(width: number, height: number): ImageData;
new(array: Uint8ClampedArray, width: number, height: number): ImageData;
}
};
interface MessageChannel {
readonly port1: MessagePort;
@@ -710,7 +719,7 @@ interface MessageChannel {
declare var MessageChannel: {
prototype: MessageChannel;
new(): MessageChannel;
}
};
interface MessageEvent extends Event {
readonly data: any;
@@ -723,7 +732,7 @@ interface MessageEvent extends Event {
declare var MessageEvent: {
prototype: MessageEvent;
new(type: string, eventInitDict?: MessageEventInit): MessageEvent;
}
};
interface MessagePortEventMap {
"message": MessageEvent;
@@ -741,7 +750,7 @@ interface MessagePort extends EventTarget {
declare var MessagePort: {
prototype: MessagePort;
new(): MessagePort;
}
};
interface NotificationEventMap {
"click": Event;
@@ -771,7 +780,7 @@ declare var Notification: {
prototype: Notification;
new(title: string, options?: NotificationOptions): Notification;
requestPermission(callback?: NotificationPermissionCallback): Promise<NotificationPermission>;
}
};
interface Performance {
readonly navigation: PerformanceNavigation;
@@ -794,7 +803,7 @@ interface Performance {
declare var Performance: {
prototype: Performance;
new(): Performance;
}
};
interface PerformanceNavigation {
readonly redirectCount: number;
@@ -813,18 +822,18 @@ declare var PerformanceNavigation: {
readonly TYPE_NAVIGATE: number;
readonly TYPE_RELOAD: number;
readonly TYPE_RESERVED: number;
}
};
interface PerformanceTiming {
readonly connectEnd: number;
readonly connectStart: number;
readonly domainLookupEnd: number;
readonly domainLookupStart: number;
readonly domComplete: number;
readonly domContentLoadedEventEnd: number;
readonly domContentLoadedEventStart: number;
readonly domInteractive: number;
readonly domLoading: number;
readonly domainLookupEnd: number;
readonly domainLookupStart: number;
readonly fetchStart: number;
readonly loadEventEnd: number;
readonly loadEventStart: number;
@@ -844,7 +853,7 @@ interface PerformanceTiming {
declare var PerformanceTiming: {
prototype: PerformanceTiming;
new(): PerformanceTiming;
}
};
interface Position {
readonly coords: Coordinates;
@@ -854,7 +863,7 @@ interface Position {
declare var Position: {
prototype: Position;
new(): Position;
}
};
interface PositionError {
readonly code: number;
@@ -871,7 +880,7 @@ declare var PositionError: {
readonly PERMISSION_DENIED: number;
readonly POSITION_UNAVAILABLE: number;
readonly TIMEOUT: number;
}
};
interface ProgressEvent extends Event {
readonly lengthComputable: boolean;
@@ -883,7 +892,7 @@ interface ProgressEvent extends Event {
declare var ProgressEvent: {
prototype: ProgressEvent;
new(type: string, eventInitDict?: ProgressEventInit): ProgressEvent;
}
};
interface PushManager {
getSubscription(): Promise<PushSubscription>;
@@ -894,7 +903,7 @@ interface PushManager {
declare var PushManager: {
prototype: PushManager;
new(): PushManager;
}
};
interface PushSubscription {
readonly endpoint: USVString;
@@ -907,7 +916,7 @@ interface PushSubscription {
declare var PushSubscription: {
prototype: PushSubscription;
new(): PushSubscription;
}
};
interface PushSubscriptionOptions {
readonly applicationServerKey: ArrayBuffer | null;
@@ -917,7 +926,7 @@ interface PushSubscriptionOptions {
declare var PushSubscriptionOptions: {
prototype: PushSubscriptionOptions;
new(): PushSubscriptionOptions;
}
};
interface ReadableStream {
readonly locked: boolean;
@@ -928,7 +937,7 @@ interface ReadableStream {
declare var ReadableStream: {
prototype: ReadableStream;
new(): ReadableStream;
}
};
interface ReadableStreamReader {
cancel(): Promise<void>;
@@ -939,7 +948,7 @@ interface ReadableStreamReader {
declare var ReadableStreamReader: {
prototype: ReadableStreamReader;
new(): ReadableStreamReader;
}
};
interface Request extends Object, Body {
readonly cache: RequestCache;
@@ -961,7 +970,7 @@ interface Request extends Object, Body {
declare var Request: {
prototype: Request;
new(input: Request | string, init?: RequestInit): Request;
}
};
interface Response extends Object, Body {
readonly body: ReadableStream | null;
@@ -977,7 +986,9 @@ interface Response extends Object, Body {
declare var Response: {
prototype: Response;
new(body?: any, init?: ResponseInit): Response;
}
error: () => Response;
redirect: (url: string, status?: number) => Response;
};
interface ServiceWorkerEventMap extends AbstractWorkerEventMap {
"statechange": Event;
@@ -995,7 +1006,7 @@ interface ServiceWorker extends EventTarget, AbstractWorker {
declare var ServiceWorker: {
prototype: ServiceWorker;
new(): ServiceWorker;
}
};
interface ServiceWorkerRegistrationEventMap {
"updatefound": Event;
@@ -1020,7 +1031,7 @@ interface ServiceWorkerRegistration extends EventTarget {
declare var ServiceWorkerRegistration: {
prototype: ServiceWorkerRegistration;
new(): ServiceWorkerRegistration;
}
};
interface SyncManager {
getTags(): any;
@@ -1030,7 +1041,7 @@ interface SyncManager {
declare var SyncManager: {
prototype: SyncManager;
new(): SyncManager;
}
};
interface URL {
hash: string;
@@ -1053,7 +1064,7 @@ declare var URL: {
new(url: string, base?: string): URL;
createObjectURL(object: any, options?: ObjectURLOptions): string;
revokeObjectURL(url: string): void;
}
};
interface WebSocketEventMap {
"close": CloseEvent;
@@ -1090,7 +1101,7 @@ declare var WebSocket: {
readonly CLOSING: number;
readonly CONNECTING: number;
readonly OPEN: number;
}
};
interface WorkerEventMap extends AbstractWorkerEventMap {
"message": MessageEvent;
@@ -1107,7 +1118,7 @@ interface Worker extends EventTarget, AbstractWorker {
declare var Worker: {
prototype: Worker;
new(stringUrl: string): Worker;
}
};
interface XMLHttpRequestEventMap extends XMLHttpRequestEventTargetEventMap {
"readystatechange": Event;
@@ -1153,7 +1164,7 @@ declare var XMLHttpRequest: {
readonly LOADING: number;
readonly OPENED: number;
readonly UNSENT: number;
}
};
interface XMLHttpRequestUpload extends EventTarget, XMLHttpRequestEventTarget {
addEventListener<K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, useCapture?: boolean): void;
@@ -1163,7 +1174,7 @@ interface XMLHttpRequestUpload extends EventTarget, XMLHttpRequestEventTarget {
declare var XMLHttpRequestUpload: {
prototype: XMLHttpRequestUpload;
new(): XMLHttpRequestUpload;
}
};
interface AbstractWorkerEventMap {
"error": ErrorEvent;
@@ -1278,7 +1289,7 @@ interface Client {
declare var Client: {
prototype: Client;
new(): Client;
}
};
interface Clients {
claim(): Promise<void>;
@@ -1290,7 +1301,7 @@ interface Clients {
declare var Clients: {
prototype: Clients;
new(): Clients;
}
};
interface DedicatedWorkerGlobalScopeEventMap extends WorkerGlobalScopeEventMap {
"message": MessageEvent;
@@ -1307,7 +1318,7 @@ interface DedicatedWorkerGlobalScope extends WorkerGlobalScope {
declare var DedicatedWorkerGlobalScope: {
prototype: DedicatedWorkerGlobalScope;
new(): DedicatedWorkerGlobalScope;
}
};
interface ExtendableEvent extends Event {
waitUntil(f: Promise<any>): void;
@@ -1316,7 +1327,7 @@ interface ExtendableEvent extends Event {
declare var ExtendableEvent: {
prototype: ExtendableEvent;
new(type: string, eventInitDict?: ExtendableEventInit): ExtendableEvent;
}
};
interface ExtendableMessageEvent extends ExtendableEvent {
readonly data: any;
@@ -1329,7 +1340,7 @@ interface ExtendableMessageEvent extends ExtendableEvent {
declare var ExtendableMessageEvent: {
prototype: ExtendableMessageEvent;
new(type: string, eventInitDict?: ExtendableMessageEventInit): ExtendableMessageEvent;
}
};
interface FetchEvent extends ExtendableEvent {
readonly clientId: string | null;
@@ -1341,7 +1352,7 @@ interface FetchEvent extends ExtendableEvent {
declare var FetchEvent: {
prototype: FetchEvent;
new(type: string, eventInitDict: FetchEventInit): FetchEvent;
}
};
interface FileReaderSync {
readAsArrayBuffer(blob: Blob): any;
@@ -1353,7 +1364,7 @@ interface FileReaderSync {
declare var FileReaderSync: {
prototype: FileReaderSync;
new(): FileReaderSync;
}
};
interface NotificationEvent extends ExtendableEvent {
readonly action: string;
@@ -1363,7 +1374,7 @@ interface NotificationEvent extends ExtendableEvent {
declare var NotificationEvent: {
prototype: NotificationEvent;
new(type: string, eventInitDict: NotificationEventInit): NotificationEvent;
}
};
interface PushEvent extends ExtendableEvent {
readonly data: PushMessageData | null;
@@ -1372,7 +1383,7 @@ interface PushEvent extends ExtendableEvent {
declare var PushEvent: {
prototype: PushEvent;
new(type: string, eventInitDict?: PushEventInit): PushEvent;
}
};
interface PushMessageData {
arrayBuffer(): ArrayBuffer;
@@ -1384,7 +1395,7 @@ interface PushMessageData {
declare var PushMessageData: {
prototype: PushMessageData;
new(): PushMessageData;
}
};
interface ServiceWorkerGlobalScopeEventMap extends WorkerGlobalScopeEventMap {
"activate": ExtendableEvent;
@@ -1418,7 +1429,7 @@ interface ServiceWorkerGlobalScope extends WorkerGlobalScope {
declare var ServiceWorkerGlobalScope: {
prototype: ServiceWorkerGlobalScope;
new(): ServiceWorkerGlobalScope;
}
};
interface SyncEvent extends ExtendableEvent {
readonly lastChance: boolean;
@@ -1428,7 +1439,7 @@ interface SyncEvent extends ExtendableEvent {
declare var SyncEvent: {
prototype: SyncEvent;
new(type: string, init: SyncEventInit): SyncEvent;
}
};
interface WindowClient extends Client {
readonly focused: boolean;
@@ -1440,7 +1451,7 @@ interface WindowClient extends Client {
declare var WindowClient: {
prototype: WindowClient;
new(): WindowClient;
}
};
interface WorkerGlobalScopeEventMap {
"error": ErrorEvent;
@@ -1463,7 +1474,7 @@ interface WorkerGlobalScope extends EventTarget, WorkerUtils, WindowConsole, Glo
declare var WorkerGlobalScope: {
prototype: WorkerGlobalScope;
new(): WorkerGlobalScope;
}
};
interface WorkerLocation {
readonly hash: string;
@@ -1481,7 +1492,7 @@ interface WorkerLocation {
declare var WorkerLocation: {
prototype: WorkerLocation;
new(): WorkerLocation;
}
};
interface WorkerNavigator extends Object, NavigatorID, NavigatorOnLine, NavigatorBeacon, NavigatorConcurrentHardware {
readonly hardwareConcurrency: number;
@@ -1490,7 +1501,7 @@ interface WorkerNavigator extends Object, NavigatorID, NavigatorOnLine, Navigato
declare var WorkerNavigator: {
prototype: WorkerNavigator;
new(): WorkerNavigator;
}
};
interface WorkerUtils extends Object, WindowBase64 {
readonly indexedDB: IDBFactory;
@@ -1533,38 +1544,38 @@ interface ImageBitmap {
interface URLSearchParams {
/**
* Appends a specified key/value pair as a new search parameter.
*/
* Appends a specified key/value pair as a new search parameter.
*/
append(name: string, value: string): void;
/**
* Deletes the given search parameter, and its associated value, from the list of all search parameters.
*/
* Deletes the given search parameter, and its associated value, from the list of all search parameters.
*/
delete(name: string): void;
/**
* Returns the first value associated to the given search parameter.
*/
* Returns the first value associated to the given search parameter.
*/
get(name: string): string | null;
/**
* Returns all the values association with a given search parameter.
*/
* Returns all the values association with a given search parameter.
*/
getAll(name: string): string[];
/**
* Returns a Boolean indicating if such a search parameter exists.
*/
* Returns a Boolean indicating if such a search parameter exists.
*/
has(name: string): boolean;
/**
* Sets the value associated to a given search parameter to the given value. If there were several values, delete the others.
*/
* Sets the value associated to a given search parameter to the given value. If there were several values, delete the others.
*/
set(name: string, value: string): void;
}
declare var URLSearchParams: {
prototype: URLSearchParams;
/**
* Constructor returning a URLSearchParams object.
*/
* Constructor returning a URLSearchParams object.
*/
new (init?: string | URLSearchParams): URLSearchParams;
}
};
interface BlobPropertyBag {
type?: string;
@@ -1771,8 +1782,23 @@ interface AddEventListenerOptions extends EventListenerOptions {
declare type EventListenerOrEventListenerObject = EventListener | EventListenerObject;
interface DecodeErrorCallback {
(error: DOMException): void;
}
interface DecodeSuccessCallback {
(decodedData: AudioBuffer): void;
}
interface ErrorEventHandler {
(message: string, filename?: string, lineno?: number, colno?: number, error?:Error): void;
(message: string, filename?: string, lineno?: number, colno?: number, error?: Error): void;
}
interface ForEachCallback {
(keyId: any, status: MediaKeyStatus): void;
}
interface FunctionStringCallback {
(data: string): void;
}
interface NotificationPermissionCallback {
(permission: NotificationPermission): void;
}
interface PositionCallback {
(position: Position): void;
@@ -1780,21 +1806,6 @@ interface PositionCallback {
interface PositionErrorCallback {
(error: PositionError): void;
}
interface DecodeSuccessCallback {
(decodedData: AudioBuffer): void;
}
interface DecodeErrorCallback {
(error: DOMException): void;
}
interface FunctionStringCallback {
(data: string): void;
}
interface ForEachCallback {
(keyId: any, status: MediaKeyStatus): void;
}
interface NotificationPermissionCallback {
(permission: NotificationPermission): void;
}
declare var onmessage: (this: DedicatedWorkerGlobalScope, ev: MessageEvent) => any;
declare function close(): void;
declare function postMessage(message: any, transfer?: any[]): void;
+180 -95
View File
@@ -2,51 +2,53 @@
* Declaration module describing the TypeScript Server protocol
*/
declare namespace ts.server.protocol {
namespace CommandTypes {
type Brace = "brace";
type BraceCompletion = "braceCompletion";
type Change = "change";
type Close = "close";
type Completions = "completions";
type CompletionDetails = "completionEntryDetails";
type CompileOnSaveAffectedFileList = "compileOnSaveAffectedFileList";
type CompileOnSaveEmitFile = "compileOnSaveEmitFile";
type Configure = "configure";
type Definition = "definition";
type Implementation = "implementation";
type Exit = "exit";
type Format = "format";
type Formatonkey = "formatonkey";
type Geterr = "geterr";
type GeterrForProject = "geterrForProject";
type SemanticDiagnosticsSync = "semanticDiagnosticsSync";
type SyntacticDiagnosticsSync = "syntacticDiagnosticsSync";
type NavBar = "navbar";
type Navto = "navto";
type NavTree = "navtree";
type NavTreeFull = "navtree-full";
type Occurrences = "occurrences";
type DocumentHighlights = "documentHighlights";
type Open = "open";
type Quickinfo = "quickinfo";
type References = "references";
type Reload = "reload";
type Rename = "rename";
type Saveto = "saveto";
type SignatureHelp = "signatureHelp";
type TypeDefinition = "typeDefinition";
type ProjectInfo = "projectInfo";
type ReloadProjects = "reloadProjects";
type Unknown = "unknown";
type OpenExternalProject = "openExternalProject";
type OpenExternalProjects = "openExternalProjects";
type CloseExternalProject = "closeExternalProject";
type TodoComments = "todoComments";
type Indentation = "indentation";
type DocCommentTemplate = "docCommentTemplate";
type CompilerOptionsForInferredProjects = "compilerOptionsForInferredProjects";
type GetCodeFixes = "getCodeFixes";
type GetSupportedCodeFixes = "getSupportedCodeFixes";
const enum CommandTypes {
Brace = "brace",
BraceCompletion = "braceCompletion",
Change = "change",
Close = "close",
Completions = "completions",
CompletionDetails = "completionEntryDetails",
CompileOnSaveAffectedFileList = "compileOnSaveAffectedFileList",
CompileOnSaveEmitFile = "compileOnSaveEmitFile",
Configure = "configure",
Definition = "definition",
Implementation = "implementation",
Exit = "exit",
Format = "format",
Formatonkey = "formatonkey",
Geterr = "geterr",
GeterrForProject = "geterrForProject",
SemanticDiagnosticsSync = "semanticDiagnosticsSync",
SyntacticDiagnosticsSync = "syntacticDiagnosticsSync",
NavBar = "navbar",
Navto = "navto",
NavTree = "navtree",
NavTreeFull = "navtree-full",
Occurrences = "occurrences",
DocumentHighlights = "documentHighlights",
Open = "open",
Quickinfo = "quickinfo",
References = "references",
Reload = "reload",
Rename = "rename",
Saveto = "saveto",
SignatureHelp = "signatureHelp",
TypeDefinition = "typeDefinition",
ProjectInfo = "projectInfo",
ReloadProjects = "reloadProjects",
Unknown = "unknown",
OpenExternalProject = "openExternalProject",
OpenExternalProjects = "openExternalProjects",
CloseExternalProject = "closeExternalProject",
TodoComments = "todoComments",
Indentation = "indentation",
DocCommentTemplate = "docCommentTemplate",
CompilerOptionsForInferredProjects = "compilerOptionsForInferredProjects",
GetCodeFixes = "getCodeFixes",
GetSupportedCodeFixes = "getSupportedCodeFixes",
GetApplicableRefactors = "getApplicableRefactors",
GetEditsForRefactor = "getEditsForRefactor",
}
/**
* A TypeScript Server message
@@ -287,6 +289,85 @@ declare namespace ts.server.protocol {
*/
offset: number;
}
type FileLocationOrRangeRequestArgs = FileLocationRequestArgs | FileRangeRequestArgs;
/**
* Request refactorings at a given position or selection area.
*/
interface GetApplicableRefactorsRequest extends Request {
command: CommandTypes.GetApplicableRefactors;
arguments: GetApplicableRefactorsRequestArgs;
}
type GetApplicableRefactorsRequestArgs = FileLocationOrRangeRequestArgs;
/**
* Response is a list of available refactorings.
* Each refactoring exposes one or more "Actions"; a user selects one action to invoke a refactoring
*/
interface GetApplicableRefactorsResponse extends Response {
body?: ApplicableRefactorInfo[];
}
/**
* A set of one or more available refactoring actions, grouped under a parent refactoring.
*/
interface ApplicableRefactorInfo {
/**
* The programmatic name of the refactoring
*/
name: string;
/**
* A description of this refactoring category to show to the user.
* If the refactoring gets inlined (see below), this text will not be visible.
*/
description: string;
/**
* Inlineable refactorings can have their actions hoisted out to the top level
* of a context menu. Non-inlineanable refactorings should always be shown inside
* their parent grouping.
*
* If not specified, this value is assumed to be 'true'
*/
inlineable?: boolean;
actions: RefactorActionInfo[];
}
/**
* Represents a single refactoring action - for example, the "Extract Method..." refactor might
* offer several actions, each corresponding to a surround class or closure to extract into.
*/
type RefactorActionInfo = {
/**
* The programmatic name of the refactoring action
*/
name: string;
/**
* A description of this refactoring action to show to the user.
* If the parent refactoring is inlined away, this will be the only text shown,
* so this description should make sense by itself if the parent is inlineable=true
*/
description: string;
};
interface GetEditsForRefactorRequest extends Request {
command: CommandTypes.GetEditsForRefactor;
arguments: GetEditsForRefactorRequestArgs;
}
/**
* Request the edits that a particular refactoring action produces.
* Callers must specify the name of the refactor and the name of the action.
*/
type GetEditsForRefactorRequestArgs = FileLocationOrRangeRequestArgs & {
refactor: string;
action: string;
};
interface GetEditsForRefactorResponse extends Response {
body?: RefactorEditInfo;
}
type RefactorEditInfo = {
edits: FileCodeEdits[];
/**
* An optional location where the editor should start a rename operation once
* the refactoring edits have been applied
*/
renameLocation?: Location;
renameFilename?: string;
};
/**
* Request for the available codefixes at a specific position.
*/
@@ -294,10 +375,7 @@ declare namespace ts.server.protocol {
command: CommandTypes.GetCodeFixes;
arguments: CodeFixRequestArgs;
}
/**
* Instances of this interface specify errorcodes on a specific location in a sourcefile.
*/
interface CodeFixRequestArgs extends FileRequestArgs {
interface FileRangeRequestArgs extends FileRequestArgs {
/**
* The line number for the request (1-based).
*/
@@ -314,6 +392,11 @@ declare namespace ts.server.protocol {
* The character offset (on the line) for the request (1-based).
*/
endOffset: number;
}
/**
* Instances of this interface specify errorcodes on a specific location in a sourcefile.
*/
interface CodeFixRequestArgs extends FileRangeRequestArgs {
/**
* Errorcodes we want to get the fixes for.
*/
@@ -394,7 +477,7 @@ declare namespace ts.server.protocol {
command: CommandTypes.Implementation;
}
/**
* Location in source code expressed as (one-based) line and character offset.
* Location in source code expressed as (one-based) line and (one-based) column offset.
*/
interface Location {
line: number;
@@ -488,10 +571,9 @@ declare namespace ts.server.protocol {
}
/**
* Span augmented with extra information that denotes the kind of the highlighting to be used for span.
* Kind is taken from HighlightSpanKind type.
*/
interface HighlightSpan extends TextSpan {
kind: string;
kind: HighlightSpanKind;
}
/**
* Represents a set of highligh spans for a give name
@@ -609,7 +691,7 @@ declare namespace ts.server.protocol {
/**
* The items's kind (such as 'className' or 'parameterName' or plain 'text').
*/
kind: string;
kind: ScriptElementKind;
/**
* Optional modifiers for the kind (such as 'public').
*/
@@ -957,7 +1039,7 @@ declare namespace ts.server.protocol {
/**
* The symbol's kind (such as 'className' or 'parameterName' or plain 'text').
*/
kind: string;
kind: ScriptElementKind;
/**
* Optional modifiers for the kind (such as 'public').
*/
@@ -1143,7 +1225,7 @@ declare namespace ts.server.protocol {
/**
* The symbol's kind (such as 'className' or 'parameterName').
*/
kind: string;
kind: ScriptElementKind;
/**
* Optional modifiers for the kind (such as 'public').
*/
@@ -1170,7 +1252,7 @@ declare namespace ts.server.protocol {
/**
* The symbol's kind (such as 'className' or 'parameterName').
*/
kind: string;
kind: ScriptElementKind;
/**
* Optional modifiers for the kind (such as 'public').
*/
@@ -1417,6 +1499,12 @@ declare namespace ts.server.protocol {
*/
source?: string;
}
interface DiagnosticWithFileName extends Diagnostic {
/**
* Name of the file the diagnostic is in
*/
fileName: string;
}
interface DiagnosticEventBody {
/**
* The file for which diagnostic information is reported.
@@ -1446,7 +1534,7 @@ declare namespace ts.server.protocol {
/**
* An arry of diagnostic information items for the found config file.
*/
diagnostics: Diagnostic[];
diagnostics: DiagnosticWithFileName[];
}
/**
* Event message for "configFileDiag" event type.
@@ -1563,7 +1651,7 @@ declare namespace ts.server.protocol {
/**
* The symbol's kind (such as 'className' or 'parameterName').
*/
kind: string;
kind: ScriptElementKind;
/**
* exact, substring, or prefix.
*/
@@ -1596,7 +1684,7 @@ declare namespace ts.server.protocol {
/**
* Kind of symbol's container symbol (if any).
*/
containerKind?: string;
containerKind?: ScriptElementKind;
}
/**
* Navto response message. Body is an array of navto items. Each
@@ -1660,7 +1748,7 @@ declare namespace ts.server.protocol {
/**
* The symbol's kind (such as 'className' or 'parameterName').
*/
kind: string;
kind: ScriptElementKind;
/**
* Optional modifiers for the kind (such as 'public').
*/
@@ -1681,7 +1769,7 @@ declare namespace ts.server.protocol {
/** protocol.NavigationTree is identical to ts.NavigationTree, except using protocol.TextSpan instead of ts.TextSpan */
interface NavigationTree {
text: string;
kind: string;
kind: ScriptElementKind;
kindModifiers: string;
spans: TextSpan[];
childItems?: NavigationTree[];
@@ -1756,12 +1844,11 @@ declare namespace ts.server.protocol {
interface NavTreeResponse extends Response {
body?: NavigationTree;
}
namespace IndentStyle {
type None = "None";
type Block = "Block";
type Smart = "Smart";
const enum IndentStyle {
None = "None",
Block = "Block",
Smart = "Smart",
}
type IndentStyle = IndentStyle.None | IndentStyle.Block | IndentStyle.Smart;
interface EditorSettings {
baseIndentSize?: number;
indentSize?: number;
@@ -1782,6 +1869,7 @@ declare namespace ts.server.protocol {
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces?: boolean;
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces?: boolean;
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean;
insertSpaceAfterTypeAssertion?: boolean;
insertSpaceBeforeFunctionParenthesis?: boolean;
placeOpenBraceOnNewLineForFunctions?: boolean;
placeOpenBraceOnNewLineForControlBlocks?: boolean;
@@ -1854,40 +1942,35 @@ declare namespace ts.server.protocol {
typeRoots?: string[];
[option: string]: CompilerOptionsValue | undefined;
}
namespace JsxEmit {
type None = "None";
type Preserve = "Preserve";
type ReactNative = "ReactNative";
type React = "React";
const enum JsxEmit {
None = "None",
Preserve = "Preserve",
ReactNative = "ReactNative",
React = "React",
}
type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React | JsxEmit.ReactNative;
namespace ModuleKind {
type None = "None";
type CommonJS = "CommonJS";
type AMD = "AMD";
type UMD = "UMD";
type System = "System";
type ES6 = "ES6";
type ES2015 = "ES2015";
const enum ModuleKind {
None = "None",
CommonJS = "CommonJS",
AMD = "AMD",
UMD = "UMD",
System = "System",
ES6 = "ES6",
ES2015 = "ES2015",
}
type ModuleKind = ModuleKind.None | ModuleKind.CommonJS | ModuleKind.AMD | ModuleKind.UMD | ModuleKind.System | ModuleKind.ES6 | ModuleKind.ES2015;
namespace ModuleResolutionKind {
type Classic = "Classic";
type Node = "Node";
const enum ModuleResolutionKind {
Classic = "Classic",
Node = "Node",
}
type ModuleResolutionKind = ModuleResolutionKind.Classic | ModuleResolutionKind.Node;
namespace NewLineKind {
type Crlf = "Crlf";
type Lf = "Lf";
const enum NewLineKind {
Crlf = "Crlf",
Lf = "Lf",
}
type NewLineKind = NewLineKind.Crlf | NewLineKind.Lf;
namespace ScriptTarget {
type ES3 = "ES3";
type ES5 = "ES5";
type ES6 = "ES6";
type ES2015 = "ES2015";
const enum ScriptTarget {
ES3 = "ES3",
ES5 = "ES5",
ES6 = "ES6",
ES2015 = "ES2015",
}
type ScriptTarget = ScriptTarget.ES3 | ScriptTarget.ES5 | ScriptTarget.ES6 | ScriptTarget.ES2015;
}
declare namespace ts.server.protocol {
@@ -1943,6 +2026,8 @@ declare namespace ts.server.protocol {
}
declare namespace ts {
// these types are empty stubs for types from services and should not be used directly
export type HighlightSpanKind = never;
export type ScriptElementKind = never;
export type ScriptKind = never;
export type IndentStyle = never;
export type JsxEmit = never;
+33323 -31037
View File
File diff suppressed because it is too large Load Diff
+36816 -32905
View File
File diff suppressed because it is too large Load Diff
+973 -762
View File
File diff suppressed because it is too large Load Diff
+39450 -35580
View File
File diff suppressed because it is too large Load Diff
+866 -464
View File
File diff suppressed because it is too large Load Diff
+42750 -38443
View File
File diff suppressed because it is too large Load Diff
+866 -464
View File
File diff suppressed because it is too large Load Diff
+42750 -38443
View File
File diff suppressed because it is too large Load Diff
+11844 -1496
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -13,6 +13,7 @@ See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
"use strict";
if (process.argv.length < 3) {
process.exit(1);
}
+1 -1
View File
@@ -17,6 +17,6 @@ nodeVersions.each { nodeVer ->
}
Utilities.standardJobSetup(newJob, project, true, "*/${branch}")
Utilities.setMachineAffinity(newJob, 'Ubuntu', '20161020')
Utilities.setMachineAffinity(newJob, 'Ubuntu14.04', '20161020')
Utilities.addGithubPRTriggerForBranch(newJob, branch, "TypeScript Test Run ${newJobName}")
}
+6 -5
View File
@@ -2,7 +2,7 @@
"name": "typescript",
"author": "Microsoft Corp.",
"homepage": "http://typescriptlang.org/",
"version": "2.4.0",
"version": "2.6.0",
"license": "Apache-2.0",
"description": "TypeScript is a language for application scale JavaScript development",
"keywords": [
@@ -31,10 +31,11 @@
"devDependencies": {
"@types/browserify": "latest",
"@types/chai": "latest",
"@types/colors": "latest",
"@types/convert-source-map": "latest",
"@types/del": "latest",
"@types/glob": "latest",
"@types/gulp": "latest",
"@types/gulp": "3.X",
"@types/gulp-concat": "latest",
"@types/gulp-help": "latest",
"@types/gulp-newer": "latest",
@@ -48,11 +49,12 @@
"@types/q": "latest",
"@types/run-sequence": "latest",
"@types/through2": "latest",
"browser-resolve": "^1.11.2",
"browserify": "latest",
"chai": "latest",
"convert-source-map": "latest",
"del": "latest",
"gulp": "latest",
"gulp": "3.X",
"gulp-clone": "latest",
"gulp-concat": "latest",
"gulp-help": "latest",
@@ -60,7 +62,6 @@
"gulp-newer": "latest",
"gulp-sourcemaps": "latest",
"gulp-typescript": "latest",
"into-stream": "latest",
"istanbul": "latest",
"jake": "latest",
"merge2": "latest",
@@ -75,6 +76,7 @@
"travis-fold": "latest",
"ts-node": "latest",
"tslint": "latest",
"colors": "latest",
"typescript": "next"
},
"scripts": {
@@ -91,7 +93,6 @@
"setup-hooks": "node scripts/link-hooks.js"
},
"browser": {
"buffer": false,
"fs": false,
"os": false,
"path": false
+6 -4
View File
@@ -1,5 +1,7 @@
/// <reference path="..\src\harness\external\node.d.ts" />
/**
* You should have ts-node installed globally before executing this, probably!
* Otherwise you'll need to compile this script before you start bisecting!
*/
import cp = require('child_process');
import fs = require('fs');
@@ -42,8 +44,8 @@ jake.on('close', jakeExitCode => {
});
} else {
console.log('Unknown command line arguments.');
console.log('Usage (compile errors): git bisect run scripts\bisect.js "foo.ts --module amd" compiles');
console.log('Usage (emit check): git bisect run scripts\bisect.js bar.ts emits bar.js "_this = this"');
console.log('Usage (compile errors): git bisect run ts-node scripts\bisect-test.ts "../failure.ts --module amd" !compiles');
console.log('Usage (emit check): git bisect run ts-node scripts\bisect-test.ts bar.ts emits bar.js "_this = this"');
// Aborts the 'git bisect run' process
process.exit(-1);
}
-30
View File
@@ -1,30 +0,0 @@
echo off
IF NOT EXIST scripts\bisect.cmd GOTO :wrongdir
IF "%1" == "" GOTO :usage
IF "%1" == "GO" GOTO :run
GOTO :copy
:usage
echo Usage: bisect GoodCommit BadCommit test.ts compiles
echo Usage: bisect GoodCommit BadCommit test.ts emits test.js "var x = 3"
GOTO :eof
:copy
copy scripts\bisect.cmd scripts\bisect-fresh.cmd
scripts\bisect-fresh GO %*
GOTO :eof
:run
call jake local
node built/local/tsc.js scripts/bisect-test.ts --module commonjs
git bisect start %2 %3
git bisect run node scripts/bisect-test.js %4 %5 %6 %7
del scripts\bisect-test.js
del scripts\bisect-fresh.cmd
GOTO :eof
:wrongdir
@echo Run this file from the repo folder, not the scripts folder
GOTO :eof
:eof
+9 -5
View File
@@ -7,11 +7,15 @@ function endsWith(s: string, suffix: string) {
return s.lastIndexOf(suffix, s.length - suffix.length) !== -1;
}
function isStringEnum(declaration: ts.EnumDeclaration) {
return declaration.members.length && declaration.members.every(m => m.initializer && m.initializer.kind === ts.SyntaxKind.StringLiteral);
}
class DeclarationsWalker {
private visitedTypes: ts.Type[] = [];
private text = "";
private removedTypes: ts.Type[] = [];
private constructor(private typeChecker: ts.TypeChecker, private protocolFile: ts.SourceFile) {
}
@@ -19,7 +23,7 @@ class DeclarationsWalker {
let text = "declare namespace ts.server.protocol {\n";
var walker = new DeclarationsWalker(typeChecker, protocolFile);
walker.visitTypeNodes(protocolFile);
text = walker.text
text = walker.text
? `declare namespace ts.server.protocol {\n${walker.text}}`
: "";
if (walker.removedTypes) {
@@ -52,7 +56,7 @@ class DeclarationsWalker {
if (sourceFile === this.protocolFile || path.basename(sourceFile.fileName) === "lib.d.ts") {
return;
}
if (decl.kind === ts.SyntaxKind.EnumDeclaration) {
if (decl.kind === ts.SyntaxKind.EnumDeclaration && !isStringEnum(decl as ts.EnumDeclaration)) {
this.removedTypes.push(type);
return;
}
@@ -91,7 +95,7 @@ class DeclarationsWalker {
for (const type of heritageClauses[0].types) {
this.processTypeOfNode(type);
}
}
}
break;
}
}
@@ -110,7 +114,7 @@ class DeclarationsWalker {
this.processType(type);
}
}
}
}
}
function writeProtocolFile(outputFile: string, protocolTs: string, typeScriptServicesDts: string) {
+34 -24
View File
@@ -19,47 +19,57 @@ function main(): void {
// Acquire the version from the package.json file and modify it appropriately.
const packageJsonFilePath = ts.normalizePath(sys.args[0]);
const packageJsonContents = sys.readFile(packageJsonFilePath);
const packageJsonValue: PackageJson = JSON.parse(packageJsonContents);
const packageJsonValue: PackageJson = JSON.parse(sys.readFile(packageJsonFilePath));
const nightlyVersion = getNightlyVersionString(packageJsonValue.version);
// Modify the package.json structure
packageJsonValue.version = nightlyVersion;
const { majorMinor, patch } = parsePackageJsonVersion(packageJsonValue.version);
const nightlyPatch = getNightlyPatch(patch);
// Acquire and modify the source file that exposes the version string.
const tsFilePath = ts.normalizePath(sys.args[1]);
const tsFileContents = sys.readFile(tsFilePath);
const versionAssignmentRegExp = /export\s+const\s+version\s+=\s+".*";/;
const modifiedTsFileContents = tsFileContents.replace(versionAssignmentRegExp, `export const version = "${nightlyVersion}";`);
const tsFileContents = ts.sys.readFile(tsFilePath);
const modifiedTsFileContents = updateTsFile(tsFilePath, tsFileContents, majorMinor, patch, nightlyPatch);
// Ensure we are actually changing something - the user probably wants to know that the update failed.
if (tsFileContents === modifiedTsFileContents) {
let err = `\n '${tsFilePath}' was not updated while configuring for a nightly publish.\n `;
if (tsFileContents.match(versionAssignmentRegExp)) {
err += `Ensure that you have not already run this script; otherwise, erase your changes using 'git checkout -- "${tsFilePath}"'.`;
}
else {
err += `The file seems to no longer have a string matching '${versionAssignmentRegExp}'.`;
}
err += `Ensure that you have not already run this script; otherwise, erase your changes using 'git checkout -- "${tsFilePath}"'.`;
throw err + "\n";
}
// Finally write the changes to disk.
// Modify the package.json structure
packageJsonValue.version = `${majorMinor}.${nightlyPatch}`;
sys.writeFile(packageJsonFilePath, JSON.stringify(packageJsonValue, /*replacer:*/ undefined, /*space:*/ 4))
sys.writeFile(tsFilePath, modifiedTsFileContents);
}
function getNightlyVersionString(versionString: string): string {
// If the version string already contains "-nightly",
// then get the base string and update based on that.
const dashNightlyPos = versionString.indexOf("-dev");
if (dashNightlyPos >= 0) {
versionString = versionString.slice(0, dashNightlyPos);
function updateTsFile(tsFilePath: string, tsFileContents: string, majorMinor: string, patch: string, nightlyPatch: string): string {
const majorMinorRgx = /export const versionMajorMinor = "(\d+\.\d+)"/;
const majorMinorMatch = majorMinorRgx.exec(tsFileContents);
ts.Debug.assert(majorMinorMatch !== null, "", () => `The file seems to no longer have a string matching '${majorMinorRgx}'.`);
const parsedMajorMinor = majorMinorMatch[1];
ts.Debug.assert(parsedMajorMinor === majorMinor, "versionMajorMinor does not match.", () => `${tsFilePath}: '${parsedMajorMinor}'; package.json: '${majorMinor}'`);
const versionRgx = /export const version = `\$\{versionMajorMinor\}\.(\d)`;/;
const patchMatch = versionRgx.exec(tsFileContents);
ts.Debug.assert(patchMatch !== null, "The file seems to no longer have a string matching", () => versionRgx.toString());
const parsedPatch = patchMatch[1];
if (parsedPatch !== patch) {
throw new Error(`patch does not match. ${tsFilePath}: '${parsedPatch}; package.json: '${patch}'`);
}
return tsFileContents.replace(versionRgx, `export const version = \`\${versionMajorMinor}.${nightlyPatch}\`;`);
}
function parsePackageJsonVersion(versionString: string): { majorMinor: string, patch: string } {
const versionRgx = /(\d+\.\d+)\.(\d+)($|\-)/;
const match = versionString.match(versionRgx);
ts.Debug.assert(match !== null, "package.json 'version' should match", () => versionRgx.toString());
return { majorMinor: match[1], patch: match[2] };
}
/** e.g. 0-dev.20170707 */
function getNightlyPatch(plainPatch: string): string {
// We're going to append a representation of the current time at the end of the current version.
// String.prototype.toISOString() returns a 24-character string formatted as 'YYYY-MM-DDTHH:mm:ss.sssZ',
// but we'd prefer to just remove separators and limit ourselves to YYYYMMDD.
@@ -67,7 +77,7 @@ function getNightlyVersionString(versionString: string): string {
const now = new Date();
const timeStr = now.toISOString().replace(/:|T|\.|-/g, "").slice(0, 8);
return `${versionString}-dev.${timeStr}`;
return `${plainPatch}-dev.${timeStr}`;
}
main();
-26
View File
@@ -1,26 +0,0 @@
/**
* Module dependencies.
*/
var Base = require('mocha').reporters.Base;
/**
* Expose `None`.
*/
exports = module.exports = None;
/**
* Initialize a new `None` test reporter.
*
* @api public
* @param {Runner} runner
*/
function None(runner) {
Base.call(this);
}
/**
* Inherit from `Base.prototype`.
*/
None.prototype.__proto__ = Base.prototype;
-366
View File
@@ -1,366 +0,0 @@
var tty = require("tty")
, readline = require("readline")
, fs = require("fs")
, path = require("path")
, child_process = require("child_process")
, os = require("os")
, mocha = require("mocha")
, Base = mocha.reporters.Base
, color = Base.color
, cursor = Base.cursor
, ms = require("mocha/lib/ms");
var isatty = tty.isatty(1) && tty.isatty(2);
var tapRangePattern = /^(\d+)\.\.(\d+)(?:$|\r\n?|\n)/;
var tapTestPattern = /^(not\sok|ok)\s+(\d+)\s+(?:-\s+)?(.*)$/;
var tapCommentPattern = /^#(?: (tests|pass|fail) (\d+)$)?/;
exports.runTestsInParallel = runTestsInParallel;
exports.ProgressBars = ProgressBars;
function runTestsInParallel(taskConfigsFolder, run, options, cb) {
if (options === undefined) options = { };
return discoverTests(run, options, function (error) {
if (error) {
return cb(error);
}
return runTests(taskConfigsFolder, run, options, cb);
});
}
function discoverTests(run, options, cb) {
console.log("Discovering tests...");
var cmd = "mocha -R " + require.resolve("./mocha-none-reporter.js") + " " + run;
var p = spawnProcess(cmd);
p.on("exit", function (status) {
if (status) {
cb(new Error("Process exited with code " + status));
}
else {
cb();
}
});
}
function runTests(taskConfigsFolder, run, options, cb) {
var configFiles = fs.readdirSync(taskConfigsFolder);
var numPartitions = configFiles.length;
if (numPartitions <= 0) {
cb();
return;
}
console.log("Running tests on " + numPartitions + " threads...");
var partitions = Array(numPartitions);
var progressBars = new ProgressBars();
progressBars.enable();
var counter = numPartitions;
configFiles.forEach(runTestsInPartition);
function runTestsInPartition(file, index) {
var partition = {
file: path.join(taskConfigsFolder, file),
tests: 0,
passed: 0,
failed: 0,
completed: 0,
current: undefined,
start: undefined,
end: undefined,
failures: []
};
partitions[index] = partition;
// Set up the progress bar.
updateProgress(0);
// Start the background process.
var cmd = "mocha -t " + (options.testTimeout || 20000) + " -R tap --no-colors " + run + " --config='" + partition.file + "'";
var p = spawnProcess(cmd);
var rl = readline.createInterface({
input: p.stdout,
terminal: false
});
rl.on("line", onmessage);
p.on("exit", onexit)
function onmessage(line) {
if (partition.start === undefined) {
partition.start = Date.now();
}
var rangeMatch = tapRangePattern.exec(line);
if (rangeMatch) {
partition.tests = parseInt(rangeMatch[2]);
return;
}
var testMatch = tapTestPattern.exec(line);
if (testMatch) {
var test = {
result: testMatch[1],
id: parseInt(testMatch[2]),
name: testMatch[3],
output: []
};
partition.current = test;
partition.completed++;
if (test.result === "ok") {
partition.passed++;
}
else {
partition.failed++;
partition.failures.push(test);
}
var progress = partition.completed / partition.tests;
if (progress < 1) {
updateProgress(progress);
}
return;
}
var commentMatch = tapCommentPattern.exec(line);
if (commentMatch) {
switch (commentMatch[1]) {
case "tests":
partition.current = undefined;
partition.tests = parseInt(commentMatch[2]);
break;
case "pass":
partition.passed = parseInt(commentMatch[2]);
break;
case "fail":
partition.failed = parseInt(commentMatch[2]);
break;
}
return;
}
if (partition.current) {
partition.current.output.push(line);
}
}
function onexit() {
if (partition.end === undefined) {
partition.end = Date.now();
}
partition.duration = partition.end - partition.start;
var summaryColor = partition.failed ? "fail" : "green";
var summarySymbol = partition.failed ? Base.symbols.err : Base.symbols.ok;
var summaryTests = (partition.passed === partition.tests ? partition.passed : partition.passed + "/" + partition.tests) + " passing";
var summaryDuration = "(" + ms(partition.duration) + ")";
var savedUseColors = Base.useColors;
Base.useColors = !options.noColors;
var summary = color(summaryColor, summarySymbol + " " + summaryTests) + " " + color("light", summaryDuration);
Base.useColors = savedUseColors;
updateProgress(1, summary);
signal();
}
function updateProgress(percentComplete, title) {
var progressColor = "pending";
if (partition.failed) {
progressColor = "fail";
}
progressBars.update(
index,
percentComplete,
progressColor,
title
);
}
}
function signal() {
counter--;
if (counter <= 0) {
var reporter = new Base(),
stats = reporter.stats,
failures = reporter.failures;
var duration = 0;
for (var i = 0; i < numPartitions; i++) {
var partition = partitions[i];
stats.passes += partition.passed;
stats.failures += partition.failed;
stats.tests += partition.tests;
duration += partition.duration;
for (var j = 0; j < partition.failures.length; j++) {
var failure = partition.failures[j];
failures.push(makeMochaTest(failure));
}
}
stats.duration = duration;
progressBars.disable();
if (options.noColors) {
var savedUseColors = Base.useColors;
Base.useColors = false;
reporter.epilogue();
Base.useColors = savedUseColors;
}
else {
reporter.epilogue();
}
if (stats.failures) {
return cb(new Error("Test failures reported: " + stats.failures));
}
else {
return cb();
}
}
}
function makeMochaTest(test) {
return {
fullTitle: function() {
return test.name;
},
err: {
message: test.output[0],
stack: test.output.join(os.EOL)
}
};
}
}
var nodeModulesPathPrefix = path.resolve("./node_modules/.bin/") + path.delimiter;
if (process.env.path !== undefined) {
process.env.path = nodeModulesPathPrefix + process.env.path;
} else if (process.env.PATH !== undefined) {
process.env.PATH = nodeModulesPathPrefix + process.env.PATH;
}
function spawnProcess(cmd, options) {
var shell = process.platform === "win32" ? "cmd" : "/bin/sh";
var prefix = process.platform === "win32" ? "/c" : "-c";
return child_process.spawn(shell, [prefix, cmd], { windowsVerbatimArguments: true });
}
function ProgressBars(options) {
if (!options) options = {};
var open = options.open || '[';
var close = options.close || ']';
var complete = options.complete || '▬';
var incomplete = options.incomplete || Base.symbols.dot;
var maxWidth = Math.floor(Base.window.width * .30) - open.length - close.length - 2;
var width = minMax(options.width || maxWidth, 10, maxWidth);
this._options = {
open: open,
complete: complete,
incomplete: incomplete,
close: close,
width: width
};
this._progressBars = [];
this._lineCount = 0;
this._enabled = false;
}
ProgressBars.prototype = {
enable: function () {
if (!this._enabled) {
process.stdout.write(os.EOL);
this._enabled = true;
}
},
disable: function () {
if (this._enabled) {
process.stdout.write(os.EOL);
this._enabled = false;
}
},
update: function (index, percentComplete, color, title) {
percentComplete = minMax(percentComplete, 0, 1);
var progressBar = this._progressBars[index] || (this._progressBars[index] = { });
var width = this._options.width;
var n = Math.floor(width * percentComplete);
var i = width - n;
if (n === progressBar.lastN && title === progressBar.title && color === progressBar.progressColor) {
return;
}
progressBar.lastN = n;
progressBar.title = title;
progressBar.progressColor = color;
var progress = " ";
progress += this._color('progress', this._options.open);
progress += this._color(color, fill(this._options.complete, n));
progress += this._color('progress', fill(this._options.incomplete, i));
progress += this._color('progress', this._options.close);
if (title) {
progress += this._color('progress', ' ' + title);
}
if (progressBar.text !== progress) {
progressBar.text = progress;
this._render(index);
}
},
_render: function (index) {
if (!this._enabled || !isatty) {
return;
}
cursor.hide();
readline.moveCursor(process.stdout, -process.stdout.columns, -this._lineCount);
var lineCount = 0;
var numProgressBars = this._progressBars.length;
for (var i = 0; i < numProgressBars; i++) {
if (i === index) {
readline.clearLine(process.stdout, 1);
process.stdout.write(this._progressBars[i].text + os.EOL);
}
else {
readline.moveCursor(process.stdout, -process.stdout.columns, +1);
}
lineCount++;
}
this._lineCount = lineCount;
cursor.show();
},
_color: function (type, text) {
return type && !this._options.noColors ? color(type, text) : text;
}
};
function fill(ch, size) {
var s = "";
while (s.length < size) {
s += ch;
}
return s.length > size ? s.substr(0, size) : s;
}
function minMax(value, min, max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
+38 -165
View File
@@ -6,9 +6,7 @@ interface DiagnosticDetails {
isEarly?: boolean;
}
interface InputDiagnosticMessageTable {
[msg: string]: DiagnosticDetails;
}
type InputDiagnosticMessageTable = ts.Map<DiagnosticDetails>;
function main(): void {
var sys = ts.sys;
@@ -28,101 +26,66 @@ function main(): void {
var inputFilePath = sys.args[0].replace(/\\/g, "/");
var inputStr = sys.readFile(inputFilePath);
var diagnosticMessages: InputDiagnosticMessageTable = JSON.parse(inputStr);
var diagnosticMessagesJson: { [key: string]: DiagnosticDetails } = JSON.parse(inputStr);
// Check that there are no duplicates.
const seenNames = ts.createMap<true>();
for (const name of Object.keys(diagnosticMessagesJson)) {
if (seenNames.has(name))
throw new Error(`Name ${name} appears twice`);
seenNames.set(name, true);
}
var names = Utilities.getObjectKeys(diagnosticMessages);
var nameMap = buildUniqueNameMap(names);
const diagnosticMessages: InputDiagnosticMessageTable = ts.createMapFromTemplate(diagnosticMessagesJson);
var infoFileOutput = buildInfoFileOutput(diagnosticMessages, nameMap);
checkForUniqueCodes(names, diagnosticMessages);
var infoFileOutput = buildInfoFileOutput(diagnosticMessages);
checkForUniqueCodes(diagnosticMessages);
writeFile("diagnosticInformationMap.generated.ts", infoFileOutput);
var messageOutput = buildDiagnosticMessageOutput(diagnosticMessages, nameMap);
var messageOutput = buildDiagnosticMessageOutput(diagnosticMessages);
writeFile("diagnosticMessages.generated.json", messageOutput);
}
function checkForUniqueCodes(messages: string[], diagnosticTable: InputDiagnosticMessageTable) {
const originalMessageForCode: string[] = [];
let numConflicts = 0;
for (const currentMessage of messages) {
const code = diagnosticTable[currentMessage].code;
if (code in originalMessageForCode) {
const originalMessage = originalMessageForCode[code];
ts.sys.write("\x1b[91m"); // High intensity red.
ts.sys.write("Error");
ts.sys.write("\x1b[0m"); // Reset formatting.
ts.sys.write(`: Diagnostic code '${code}' conflicts between "${originalMessage}" and "${currentMessage}".`);
ts.sys.write(ts.sys.newLine + ts.sys.newLine);
numConflicts++;
}
else {
originalMessageForCode[code] = currentMessage;
}
}
if (numConflicts > 0) {
throw new Error(`Found ${numConflicts} conflict(s) in diagnostic codes.`);
}
function checkForUniqueCodes(diagnosticTable: InputDiagnosticMessageTable) {
const allCodes: { [key: number]: true | undefined } = [];
diagnosticTable.forEach(({ code }) => {
if (allCodes[code])
throw new Error(`Diagnostic code ${code} appears more than once.`);
allCodes[code] = true;
});
}
function buildUniqueNameMap(names: string[]): ts.Map<string> {
var nameMap = ts.createMap<string>();
var uniqueNames = NameGenerator.ensureUniqueness(names, /* isCaseSensitive */ false, /* isFixed */ undefined);
for (var i = 0; i < names.length; i++) {
nameMap.set(names[i], uniqueNames[i]);
}
return nameMap;
}
function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable, nameMap: ts.Map<string>): string {
function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable): string {
var result =
'// <auto-generated />\r\n' +
'/// <reference path="types.ts" />\r\n' +
'/* @internal */\r\n' +
'namespace ts {\r\n' +
" function diag(code: number, category: DiagnosticCategory, key: string, message: string): DiagnosticMessage {\r\n" +
" return { code, category, key, message };\r\n" +
" }\r\n" +
' export const Diagnostics = {\r\n';
var names = Utilities.getObjectKeys(messageTable);
for (var i = 0; i < names.length; i++) {
var name = names[i];
var diagnosticDetails = messageTable[name];
var propName = convertPropertyName(nameMap.get(name));
result +=
' ' + propName +
': { code: ' + diagnosticDetails.code +
', category: DiagnosticCategory.' + diagnosticDetails.category +
', key: "' + createKey(propName, diagnosticDetails.code) + '"' +
', message: "' + name.replace(/[\"]/g, '\\"') + '"' +
' },\r\n';
}
messageTable.forEach(({ code, category }, name) => {
const propName = convertPropertyName(name);
result += ` ${propName}: diag(${code}, DiagnosticCategory.${category}, "${createKey(propName, code)}", ${JSON.stringify(name)}),\r\n`;
});
result += ' };\r\n}';
return result;
}
function buildDiagnosticMessageOutput(messageTable: InputDiagnosticMessageTable, nameMap: ts.Map<string>): string {
var result =
'{';
var names = Utilities.getObjectKeys(messageTable);
for (var i = 0; i < names.length; i++) {
var name = names[i];
var diagnosticDetails = messageTable[name];
var propName = convertPropertyName(nameMap.get(name));
function buildDiagnosticMessageOutput(messageTable: InputDiagnosticMessageTable): string {
let result = '{';
messageTable.forEach(({ code }, name) => {
const propName = convertPropertyName(name);
result += `\r\n "${createKey(propName, code)}" : "${name.replace(/[\"]/g, '\\"')}",`;
});
result += '\r\n "' + createKey(propName, diagnosticDetails.code) + '"' + ' : "' + name.replace(/[\"]/g, '\\"') + '"';
if (i !== names.length - 1) {
result += ',';
}
}
// Shave trailing comma, then add newline and ending brace
result = result.slice(0, result.length - 1) + '\r\n}';
result += '\r\n}';
// Assert that we generated valid JSON
JSON.parse(result);
return result;
}
@@ -139,7 +102,6 @@ function convertPropertyName(origName: string): string {
return /\w/.test(char) ? char : "_";
}).join("");
// get rid of all multi-underscores
result = result.replace(/_+/g, "_");
@@ -152,93 +114,4 @@ function convertPropertyName(origName: string): string {
return result;
}
module NameGenerator {
export function ensureUniqueness(names: string[], isCaseSensitive: boolean, isFixed?: boolean[]): string[]{
if (!isFixed) {
isFixed = names.map(() => false)
}
var names = names.slice();
ensureUniquenessInPlace(names, isCaseSensitive, isFixed);
return names;
}
function ensureUniquenessInPlace(names: string[], isCaseSensitive: boolean, isFixed: boolean[]): void {
for (var i = 0; i < names.length; i++) {
var name = names[i];
var collisionIndices = Utilities.collectMatchingIndices(name, names, isCaseSensitive);
// We will always have one "collision" because getCollisionIndices returns the index of name itself as well;
// so if we only have one collision, then there are no issues.
if (collisionIndices.length < 2) {
continue;
}
handleCollisions(name, names, isFixed, collisionIndices, isCaseSensitive);
}
}
function handleCollisions(name: string, proposedNames: string[], isFixed: boolean[], collisionIndices: number[], isCaseSensitive: boolean): void {
var suffix = 1;
for (var i = 0; i < collisionIndices.length; i++) {
var collisionIndex = collisionIndices[i];
if (isFixed[collisionIndex]) {
// can't do anything about this name.
continue;
}
while (true) {
var newName = name + suffix;
suffix++;
// Check if we've synthesized a unique name, and if so
// replace the conflicting name with the new one.
if (!proposedNames.some(name => Utilities.stringEquals(name, newName, isCaseSensitive))) {
proposedNames[collisionIndex] = newName;
break;
}
}
}
}
}
module Utilities {
/// Return a list of all indices where a string occurs.
export function collectMatchingIndices(name: string, proposedNames: string[], isCaseSensitive: boolean): number[] {
var matchingIndices: number[] = [];
for (var i = 0; i < proposedNames.length; i++) {
if (stringEquals(name, proposedNames[i], isCaseSensitive)) {
matchingIndices.push(i);
}
}
return matchingIndices;
}
export function stringEquals(s1: string, s2: string, caseSensitive: boolean): boolean {
if (caseSensitive) {
s1 = s1.toLowerCase();
s2 = s2.toLowerCase();
}
return s1 == s2;
}
// Like Object.keys
export function getObjectKeys(obj: any): string[] {
var result: string[] = [];
for (var name in obj) {
if (obj.hasOwnProperty(name)) {
result.push(name);
}
}
return result;
}
}
main();
@@ -0,0 +1,97 @@
import * as Lint from "tslint";
import * as colors from "colors";
import { sep } from "path";
function groupBy<T>(array: ReadonlyArray<T> | undefined, getGroupId: (elem: T, index: number) => number | string): T[][] {
if (!array) {
return [];
}
const groupIdToGroup: { [index: string]: T[] } = {};
let result: T[][] | undefined; // Compacted array for return value
for (let index = 0; index < array.length; index++) {
const value = array[index];
const key = getGroupId(value, index);
if (groupIdToGroup[key]) {
groupIdToGroup[key].push(value);
}
else {
const newGroup = [value];
groupIdToGroup[key] = newGroup;
if (!result) {
result = [newGroup];
}
else {
result.push(newGroup);
}
}
}
return result || [];
}
function max<T>(array: ReadonlyArray<T> | undefined, selector: (elem: T) => number): number {
if (!array) {
return 0;
}
let max = 0;
for (const item of array) {
const scalar = selector(item);
if (scalar > max) {
max = scalar;
}
}
return max;
}
function getLink(failure: Lint.RuleFailure, color: boolean): string {
const lineAndCharacter = failure.getStartPosition().getLineAndCharacter();
const sev = failure.getRuleSeverity().toUpperCase();
let path = failure.getFileName();
// Most autolinks only become clickable if they contain a slash in some way; so we make a top level file into a relative path here
if (path.indexOf("/") === -1 && path.indexOf("\\") === -1) {
path = `.${sep}${path}`;
}
return `${color ? (sev === "WARNING" ? colors.blue(sev) : colors.red(sev)) : sev}: ${path}:${lineAndCharacter.line + 1}:${lineAndCharacter.character + 1}`;
}
function getLinkMaxSize(failures: Lint.RuleFailure[]): number {
return max(failures, f => getLink(f, /*color*/ false).length);
}
function getNameMaxSize(failures: Lint.RuleFailure[]): number {
return max(failures, f => f.getRuleName().length);
}
function pad(str: string, visiblelen: number, len: number) {
if (visiblelen >= len) return str;
const count = len - visiblelen;
for (let i = 0; i < count; i++) {
str += " ";
}
return str;
}
export class Formatter extends Lint.Formatters.AbstractFormatter {
public static metadata: Lint.IFormatterMetadata = {
formatterName: "autolinkableStylish",
description: "Human-readable formatter which creates stylish messages with autolinkable filepaths.",
descriptionDetails: Lint.Utils.dedent`
Colorized output grouped by file, with autolinkable filepaths containing line and column information
`,
sample: Lint.Utils.dedent`
src/myFile.ts
ERROR: src/myFile.ts:1:14 semicolon Missing semicolon`,
consumer: "human"
};
public format(failures: Lint.RuleFailure[]): string {
return groupBy(failures, f => f.getFileName()).map(group => {
const currentFile = group[0].getFileName();
const linkMaxSize = getLinkMaxSize(group);
const nameMaxSize = getNameMaxSize(group);
return `
${currentFile}
${group.map(f => `${pad(getLink(f, /*color*/ true), getLink(f, /*color*/ false).length, linkMaxSize)} ${colors.grey(pad(f.getRuleName(), f.getRuleName().length, nameMaxSize))} ${colors.yellow(f.getFailure())}`).join("\n")}`;
}).join("\n");
}
}
@@ -27,13 +27,14 @@ function walk(ctx: Lint.WalkContext<void>): void {
/** Skip certain function/method names whose parameter names are not informative. */
function shouldIgnoreCalledExpression(expression: ts.Expression): boolean {
if (expression.kind === ts.SyntaxKind.PropertyAccessExpression) {
const methodName = (expression as ts.PropertyAccessExpression).name.text;
const methodName = (expression as ts.PropertyAccessExpression).name.text as string;
if (methodName.indexOf("set") === 0) {
return true;
}
switch (methodName) {
case "apply":
case "assert":
case "assertEqual":
case "call":
case "equal":
case "fail":
@@ -44,7 +45,7 @@ function walk(ctx: Lint.WalkContext<void>): void {
}
}
else if (expression.kind === ts.SyntaxKind.Identifier) {
const functionName = (expression as ts.Identifier).text;
const functionName = (expression as ts.Identifier).text as string;
if (functionName.indexOf("set") === 0) {
return true;
}
@@ -69,7 +70,7 @@ function walk(ctx: Lint.WalkContext<void>): void {
const ranges = ts.getTrailingCommentRanges(sourceFile.text, arg.pos) || ts.getLeadingCommentRanges(sourceFile.text, arg.pos);
if (ranges === undefined || ranges.length !== 1 || ranges[0].kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
ctx.addFailureAtNode(arg, "Tag boolean argument with parameter name");
ctx.addFailureAtNode(arg, "Tag argument with parameter name");
return;
}
+45
View File
@@ -0,0 +1,45 @@
import * as Lint from "tslint/lib";
import * as ts from "typescript";
export class Rule extends Lint.Rules.AbstractRule {
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, ctx => walk(ctx));
}
}
function walk(ctx: Lint.WalkContext<void>): void {
ts.forEachChild(ctx.sourceFile, function recur(node) {
if (ts.isCallExpression(node)) {
checkCall(node);
}
ts.forEachChild(node, recur);
});
function checkCall(node: ts.CallExpression) {
if (!isDebugAssert(node.expression) || node.arguments.length < 2) {
return;
}
const message = node.arguments[1];
if (!ts.isStringLiteral(message)) {
ctx.addFailureAtNode(message, "Second argument to 'Debug.assert' should be a string literal.");
}
if (node.arguments.length < 3) {
return;
}
const message2 = node.arguments[2];
if (!ts.isStringLiteral(message2) && !ts.isArrowFunction(message2)) {
ctx.addFailureAtNode(message, "Third argument to 'Debug.assert' should be a string literal or arrow function.");
}
}
function isDebugAssert(expr: ts.Node): boolean {
return ts.isPropertyAccessExpression(expr) && isName(expr.expression, "Debug") && isName(expr.name, "assert");
}
function isName(expr: ts.Node, text: string): boolean {
return ts.isIdentifier(expr) && expr.text === text;
}
}
@@ -19,7 +19,7 @@ function walk(ctx: Lint.WalkContext<void>): void {
ts.forEachChild(node, recur);
}
function check(types: ts.TypeNode[]): void {
function check(types: ReadonlyArray<ts.TypeNode>): void {
let expectedStart = types[0].end + 2; // space, | or &
for (let i = 1; i < types.length; i++) {
const currentType = types[i];
-8
View File
@@ -13,13 +13,5 @@ declare module "gulp-insert" {
export function transform(cb: (contents: string, file: {path: string, relative: string}) => string): NodeJS.ReadWriteStream; // file is a vinyl file
}
declare module "into-stream" {
function IntoStream(content: string | Buffer | (string | Buffer)[]): NodeJS.ReadableStream;
namespace IntoStream {
export function obj(content: any): NodeJS.ReadableStream
}
export = IntoStream;
}
declare module "sorcery";
declare module "travis-fold";
+158 -196
View File
@@ -10,7 +10,7 @@ namespace ts {
}
interface ActiveLabel {
name: string;
name: __String;
breakTarget: FlowLabel;
continueTarget: FlowLabel;
referenced: boolean;
@@ -132,8 +132,9 @@ namespace ts {
let inStrictMode: boolean;
let symbolCount = 0;
let Symbol: { new (flags: SymbolFlags, name: string): Symbol };
let classifiableNames: Map<string>;
let Symbol: { new (flags: SymbolFlags, name: __String): Symbol };
let classifiableNames: UnderscoreEscapedMap<true>;
const unreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
const reportedUnreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
@@ -147,7 +148,7 @@ namespace ts {
options = opts;
languageVersion = getEmitScriptTarget(options);
inStrictMode = bindInStrictMode(file, opts);
classifiableNames = createMap<string>();
classifiableNames = createUnderscoreEscapedMap<true>();
symbolCount = 0;
skipTransformFlagAggregation = file.isDeclarationFile;
@@ -191,7 +192,7 @@ namespace ts {
}
}
function createSymbol(flags: SymbolFlags, name: string): Symbol {
function createSymbol(flags: SymbolFlags, name: __String): Symbol {
symbolCount++;
return new Symbol(flags, name);
}
@@ -202,16 +203,18 @@ namespace ts {
node.symbol = symbol;
if (!symbol.declarations) {
symbol.declarations = [];
symbol.declarations = [node];
}
else {
symbol.declarations.push(node);
}
symbol.declarations.push(node);
if (symbolFlags & SymbolFlags.HasExports && !symbol.exports) {
symbol.exports = createMap<Symbol>();
symbol.exports = createSymbolTable();
}
if (symbolFlags & SymbolFlags.HasMembers && !symbol.members) {
symbol.members = createMap<Symbol>();
symbol.members = createSymbolTable();
}
if (symbolFlags & SymbolFlags.Value) {
@@ -226,76 +229,68 @@ namespace ts {
// Should not be called on a declaration with a computed property name,
// unless it is a well known Symbol.
function getDeclarationName(node: Declaration): string {
function getDeclarationName(node: Declaration): __String {
const name = getNameOfDeclaration(node);
if (name) {
if (isAmbientModule(node)) {
return isGlobalScopeAugmentation(<ModuleDeclaration>node) ? "__global" : `"${(<LiteralExpression>name).text}"`;
const moduleName = getTextOfIdentifierOrLiteral(<Identifier | LiteralExpression>name);
return (isGlobalScopeAugmentation(<ModuleDeclaration>node) ? "__global" : `"${moduleName}"`) as __String;
}
if (name.kind === SyntaxKind.ComputedPropertyName) {
const nameExpression = (<ComputedPropertyName>name).expression;
// treat computed property names where expression is string/numeric literal as just string/numeric literal
if (isStringOrNumericLiteral(nameExpression)) {
return nameExpression.text;
return escapeLeadingUnderscores(nameExpression.text);
}
Debug.assert(isWellKnownSymbolSyntactically(nameExpression));
return getPropertyNameForKnownSymbolName((<PropertyAccessExpression>nameExpression).name.text);
return getPropertyNameForKnownSymbolName(unescapeLeadingUnderscores((<PropertyAccessExpression>nameExpression).name.escapedText));
}
return (<Identifier | LiteralExpression>name).text;
return getEscapedTextOfIdentifierOrLiteral(<Identifier | LiteralExpression>name);
}
switch (node.kind) {
case SyntaxKind.Constructor:
return "__constructor";
return InternalSymbolName.Constructor;
case SyntaxKind.FunctionType:
case SyntaxKind.CallSignature:
return "__call";
return InternalSymbolName.Call;
case SyntaxKind.ConstructorType:
case SyntaxKind.ConstructSignature:
return "__new";
return InternalSymbolName.New;
case SyntaxKind.IndexSignature:
return "__index";
return InternalSymbolName.Index;
case SyntaxKind.ExportDeclaration:
return "__export";
return InternalSymbolName.ExportStar;
case SyntaxKind.ExportAssignment:
return (<ExportAssignment>node).isExportEquals ? "export=" : "default";
return (<ExportAssignment>node).isExportEquals ? InternalSymbolName.ExportEquals : InternalSymbolName.Default;
case SyntaxKind.BinaryExpression:
if (getSpecialPropertyAssignmentKind(node as BinaryExpression) === SpecialPropertyAssignmentKind.ModuleExports) {
// module.exports = ...
return "export=";
return InternalSymbolName.ExportEquals;
}
Debug.fail("Unknown binary declaration kind");
break;
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ClassDeclaration:
return hasModifier(node, ModifierFlags.Default) ? "default" : undefined;
return (hasModifier(node, ModifierFlags.Default) ? InternalSymbolName.Default : undefined);
case SyntaxKind.JSDocFunctionType:
return isJSDocConstructSignature(node) ? "__new" : "__call";
return (isJSDocConstructSignature(node) ? InternalSymbolName.New : InternalSymbolName.Call);
case SyntaxKind.Parameter:
// Parameters with names are handled at the top of this function. Parameters
// without names can only come from JSDocFunctionTypes.
Debug.assert(node.parent.kind === SyntaxKind.JSDocFunctionType);
const functionType = <JSDocFunctionType>node.parent;
const index = indexOf(functionType.parameters, node);
return "arg" + index;
return "arg" + index as __String;
case SyntaxKind.JSDocTypedefTag:
const parentNode = node.parent && node.parent.parent;
let nameFromParentNode: string;
if (parentNode && parentNode.kind === SyntaxKind.VariableStatement) {
if ((<VariableStatement>parentNode).declarationList.declarations.length > 0) {
const nameIdentifier = (<VariableStatement>parentNode).declarationList.declarations[0].name;
if (nameIdentifier.kind === SyntaxKind.Identifier) {
nameFromParentNode = (<Identifier>nameIdentifier).text;
}
}
}
return nameFromParentNode;
const name = getNameOfJSDocTypedef(node as JSDocTypedefTag);
return typeof name !== "undefined" ? name.escapedText : undefined;
}
}
function getDisplayName(node: Declaration): string {
return (node as NamedDeclaration).name ? declarationNameToString((node as NamedDeclaration).name) : getDeclarationName(node);
return (node as NamedDeclaration).name ? declarationNameToString((node as NamedDeclaration).name) : unescapeLeadingUnderscores(getDeclarationName(node));
}
/**
@@ -306,17 +301,17 @@ namespace ts {
* @param includes - The SymbolFlags that node has in addition to its declaration type (eg: export, ambient, etc.)
* @param excludes - The flags which node cannot be declared alongside in a symbol table. Used to report forbidden declarations.
*/
function declareSymbol(symbolTable: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol {
function declareSymbol(symbolTable: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags, isReplaceableByMethod?: boolean): Symbol {
Debug.assert(!hasDynamicName(node));
const isDefaultExport = hasModifier(node, ModifierFlags.Default);
// The exported symbol for an export default function/class node is always named "default"
const name = isDefaultExport && parent ? "default" : getDeclarationName(node);
const name = isDefaultExport && parent ? InternalSymbolName.Default : getDeclarationName(node);
let symbol: Symbol;
if (name === undefined) {
symbol = createSymbol(SymbolFlags.None, "__missing");
symbol = createSymbol(SymbolFlags.None, InternalSymbolName.Missing);
}
else {
// Check and see if the symbol table already has a symbol with this name. If not,
@@ -343,15 +338,20 @@ namespace ts {
// you have multiple 'vars' with the same name in the same container). In this case
// just add this node into the declarations list of the symbol.
symbol = symbolTable.get(name);
if (includes & SymbolFlags.Classifiable) {
classifiableNames.set(name, true);
}
if (!symbol) {
symbolTable.set(name, symbol = createSymbol(SymbolFlags.None, name));
if (isReplaceableByMethod) symbol.isReplaceableByMethod = true;
}
if (name && (includes & SymbolFlags.Classifiable)) {
classifiableNames.set(name, name);
else if (isReplaceableByMethod && !symbol.isReplaceableByMethod) {
// A symbol already exists, so don't add this as a declaration.
return symbol;
}
if (symbol.flags & excludes) {
else if (symbol.flags & excludes) {
if (symbol.isReplaceableByMethod) {
// Javascript constructor-declared symbols can be discarded in favor of
// prototype symbols like methods.
@@ -414,9 +414,8 @@ namespace ts {
}
}
else {
// Exported module members are given 2 symbols: A local symbol that is classified with an ExportValue,
// ExportType, or ExportContainer flag, and an associated export symbol with all the correct flags set
// on it. There are 2 main reasons:
// Exported module members are given 2 symbols: A local symbol that is classified with an ExportValue flag,
// and an associated export symbol with all the correct flags set on it. There are 2 main reasons:
//
// 1. We treat locals and exports of the same name as mutually exclusive within a container.
// That means the binder will issue a Duplicate Identifier error if you mix locals and exports
@@ -436,10 +435,7 @@ namespace ts {
(node as JSDocTypedefTag).name.kind === SyntaxKind.Identifier &&
((node as JSDocTypedefTag).name as Identifier).isInJSDocNamespace;
if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || isJSDocTypedefInJSDocNamespace) {
const exportKind =
(symbolFlags & SymbolFlags.Value ? SymbolFlags.ExportValue : 0) |
(symbolFlags & SymbolFlags.Type ? SymbolFlags.ExportType : 0) |
(symbolFlags & SymbolFlags.Namespace ? SymbolFlags.ExportNamespace : 0);
const exportKind = symbolFlags & SymbolFlags.Value ? SymbolFlags.ExportValue : 0;
const local = declareSymbol(container.locals, /*parent*/ undefined, node, exportKind, symbolExcludes);
local.exportSymbol = declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes);
node.localSymbol = local;
@@ -481,7 +477,7 @@ namespace ts {
if (containerFlags & ContainerFlags.IsContainer) {
container = blockScopeContainer = node;
if (containerFlags & ContainerFlags.HasLocals) {
container.locals = createMap<Symbol>();
container.locals = createSymbolTable();
}
addToContainerChain(container);
}
@@ -595,7 +591,19 @@ namespace ts {
// Binding of JsDocComment should be done before the current block scope container changes.
// because the scope of JsDocComment should not be affected by whether the current node is a
// container or not.
forEach(node.jsDoc, bind);
if (hasJSDocNodes(node)) {
if (isInJavaScriptFile(node)) {
for (const j of node.jsDoc) {
bind(j);
}
}
else {
for (const j of node.jsDoc) {
setParentPointers(node, j);
}
}
}
if (checkUnreachable(node)) {
bindEachChild(node);
return;
@@ -612,7 +620,7 @@ namespace ts {
break;
case SyntaxKind.ForInStatement:
case SyntaxKind.ForOfStatement:
bindForInOrForOfStatement(<ForInStatement | ForOfStatement>node);
bindForInOrForOfStatement(<ForInOrOfStatement>node);
break;
case SyntaxKind.IfStatement:
bindIfStatement(<IfStatement>node);
@@ -791,11 +799,7 @@ namespace ts {
return antecedent;
}
setFlowNodeReferenced(antecedent);
return <FlowCondition>{
flags,
expression,
antecedent
};
return { flags, expression, antecedent };
}
function createFlowSwitchClause(antecedent: FlowNode, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): FlowNode {
@@ -803,31 +807,18 @@ namespace ts {
return antecedent;
}
setFlowNodeReferenced(antecedent);
return <FlowSwitchClause>{
flags: FlowFlags.SwitchClause,
switchStatement,
clauseStart,
clauseEnd,
antecedent
};
return { flags: FlowFlags.SwitchClause, switchStatement, clauseStart, clauseEnd, antecedent };
}
function createFlowAssignment(antecedent: FlowNode, node: Expression | VariableDeclaration | BindingElement): FlowNode {
setFlowNodeReferenced(antecedent);
return <FlowAssignment>{
flags: FlowFlags.Assignment,
antecedent,
node
};
return { flags: FlowFlags.Assignment, antecedent, node };
}
function createFlowArrayMutation(antecedent: FlowNode, node: CallExpression | BinaryExpression): FlowNode {
setFlowNodeReferenced(antecedent);
return <FlowArrayMutation>{
flags: FlowFlags.ArrayMutation,
antecedent,
node
};
const res: FlowArrayMutation = { flags: FlowFlags.ArrayMutation, antecedent, node };
return res;
}
function finishFlowLabel(flow: FlowLabel): FlowNode {
@@ -950,7 +941,7 @@ namespace ts {
currentFlow = finishFlowLabel(postLoopLabel);
}
function bindForInOrForOfStatement(node: ForInStatement | ForOfStatement): void {
function bindForInOrForOfStatement(node: ForInOrOfStatement): void {
const preLoopLabel = createLoopLabel();
const postLoopLabel = createBranchLabel();
addAntecedent(preLoopLabel, currentFlow);
@@ -994,7 +985,7 @@ namespace ts {
currentFlow = unreachableFlow;
}
function findActiveLabel(name: string) {
function findActiveLabel(name: __String) {
if (activeLabels) {
for (const label of activeLabels) {
if (label.name === name) {
@@ -1016,7 +1007,7 @@ namespace ts {
function bindBreakOrContinueStatement(node: BreakOrContinueStatement): void {
bind(node.label);
if (node.label) {
const activeLabel = findActiveLabel(node.label.text);
const activeLabel = findActiveLabel(node.label.escapedText);
if (activeLabel) {
activeLabel.referenced = true;
bindBreakOrContinueFlow(node, activeLabel.breakTarget, activeLabel.continueTarget);
@@ -1157,8 +1148,8 @@ namespace ts {
bindEach(node.statements);
}
function pushActiveLabel(name: string, breakTarget: FlowLabel, continueTarget: FlowLabel): ActiveLabel {
const activeLabel = {
function pushActiveLabel(name: __String, breakTarget: FlowLabel, continueTarget: FlowLabel): ActiveLabel {
const activeLabel: ActiveLabel = {
name,
breakTarget,
continueTarget,
@@ -1177,7 +1168,7 @@ namespace ts {
const postStatementLabel = createBranchLabel();
bind(node.label);
addAntecedent(preStatementLabel, currentFlow);
const activeLabel = pushActiveLabel(node.label.text, postStatementLabel, preStatementLabel);
const activeLabel = pushActiveLabel(node.label.escapedText, postStatementLabel, preStatementLabel);
bind(node.statement);
popActiveLabel();
if (!activeLabel.referenced && !options.allowUnusedLabels) {
@@ -1317,7 +1308,7 @@ namespace ts {
function bindInitializedVariableFlow(node: VariableDeclaration | ArrayBindingElement) {
const name = !isOmittedExpression(node) ? node.name : undefined;
if (isBindingPattern(name)) {
for (const child of <ArrayBindingElement[]>name.elements) {
for (const child of name.elements) {
bindInitializedVariableFlow(child);
}
}
@@ -1328,7 +1319,7 @@ namespace ts {
function bindVariableDeclarationFlow(node: VariableDeclaration) {
bindEachChild(node);
if (node.initializer || node.parent.parent.kind === SyntaxKind.ForInStatement || node.parent.parent.kind === SyntaxKind.ForOfStatement) {
if (node.initializer || isForInOrOfStatement(node.parent.parent)) {
bindInitializedVariableFlow(node);
}
}
@@ -1385,14 +1376,12 @@ namespace ts {
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.TypeLiteral:
case SyntaxKind.JSDocTypeLiteral:
case SyntaxKind.JSDocRecordType:
case SyntaxKind.JsxAttributes:
return ContainerFlags.IsContainer;
case SyntaxKind.InterfaceDeclaration:
return ContainerFlags.IsContainer | ContainerFlags.IsInterface;
case SyntaxKind.JSDocFunctionType:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.TypeAliasDeclaration:
case SyntaxKind.MappedType:
@@ -1412,9 +1401,10 @@ namespace ts {
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.CallSignature:
case SyntaxKind.JSDocFunctionType:
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructSignature:
case SyntaxKind.IndexSignature:
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructorType:
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike;
@@ -1490,10 +1480,9 @@ namespace ts {
return declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes);
case SyntaxKind.TypeLiteral:
case SyntaxKind.JSDocTypeLiteral:
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.JSDocRecordType:
case SyntaxKind.JSDocTypeLiteral:
case SyntaxKind.JsxAttributes:
// Interface/Object-types always have their children added to the 'members' of
// their container. They are only accessible through an instance of their
@@ -1633,10 +1622,10 @@ namespace ts {
const symbol = createSymbol(SymbolFlags.Signature, getDeclarationName(node));
addDeclarationToSymbol(symbol, node, SymbolFlags.Signature);
const typeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, "__type");
const typeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, InternalSymbolName.Type);
addDeclarationToSymbol(typeLiteralSymbol, node, SymbolFlags.TypeLiteral);
typeLiteralSymbol.members = createMap<Symbol>();
typeLiteralSymbol.members.set(symbol.name, symbol);
typeLiteralSymbol.members = createSymbolTable();
typeLiteralSymbol.members.set(symbol.escapedName, symbol);
}
function bindObjectLiteralExpression(node: ObjectLiteralExpression) {
@@ -1646,14 +1635,14 @@ namespace ts {
}
if (inStrictMode) {
const seen = createMap<ElementKind>();
const seen = createUnderscoreEscapedMap<ElementKind>();
for (const prop of node.properties) {
if (prop.kind === SyntaxKind.SpreadAssignment || prop.name.kind !== SyntaxKind.Identifier) {
continue;
}
const identifier = <Identifier>prop.name;
const identifier = prop.name;
// ECMA-262 11.1.5 Object Initializer
// If previous is not undefined then throw a SyntaxError exception if any of the following conditions are true
@@ -1667,9 +1656,9 @@ namespace ts {
? ElementKind.Property
: ElementKind.Accessor;
const existingKind = seen.get(identifier.text);
const existingKind = seen.get(identifier.escapedText);
if (!existingKind) {
seen.set(identifier.text, currentKind);
seen.set(identifier.escapedText, currentKind);
continue;
}
@@ -1681,18 +1670,18 @@ namespace ts {
}
}
return bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, "__object");
return bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, InternalSymbolName.Object);
}
function bindJsxAttributes(node: JsxAttributes) {
return bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, "__jsxAttributes");
return bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, InternalSymbolName.JSXAttributes);
}
function bindJsxAttribute(node: JsxAttribute, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
return declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes);
}
function bindAnonymousDeclaration(node: Declaration, symbolFlags: SymbolFlags, name: string) {
function bindAnonymousDeclaration(node: Declaration, symbolFlags: SymbolFlags, name: __String) {
const symbol = createSymbol(symbolFlags, name);
addDeclarationToSymbol(symbol, node, symbolFlags);
}
@@ -1710,7 +1699,7 @@ namespace ts {
// falls through
default:
if (!blockScopeContainer.locals) {
blockScopeContainer.locals = createMap<Symbol>();
blockScopeContainer.locals = createSymbolTable();
addToContainerChain(blockScopeContainer);
}
declareSymbol(blockScopeContainer.locals, /*parent*/ undefined, node, symbolFlags, symbolExcludes);
@@ -1779,8 +1768,7 @@ namespace ts {
}
function isEvalOrArgumentsIdentifier(node: Node): boolean {
return node.kind === SyntaxKind.Identifier &&
((<Identifier>node).text === "eval" || (<Identifier>node).text === "arguments");
return isIdentifier(node) && (node.escapedText === "eval" || node.escapedText === "arguments");
}
function checkStrictModeEvalOrArguments(contextNode: Node, name: Node) {
@@ -1791,7 +1779,7 @@ namespace ts {
// otherwise report generic error message.
const span = getErrorSpanForNode(file, name);
file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length,
getStrictModeEvalOrArgumentsMessage(contextNode), identifier.text));
getStrictModeEvalOrArgumentsMessage(contextNode), unescapeLeadingUnderscores(identifier.escapedText)));
}
}
}
@@ -1883,10 +1871,6 @@ namespace ts {
file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, message, arg0, arg1, arg2));
}
function getDestructuringParameterName(node: Declaration) {
return "__" + indexOf((<SignatureDeclaration>node.parent).parameters, node);
}
function bind(node: Node): void {
if (!node) {
return;
@@ -1903,7 +1887,7 @@ namespace ts {
// Here the current node is "foo", which is a container, but the scope of "MyType" should
// not be inside "foo". Therefore we always bind @typedef before bind the parent node,
// and skip binding this tag later when binding all the other jsdoc tags.
bindJSDocTypedefTagIfAny(node);
if (isInJavaScriptFile(node)) bindJSDocTypedefTagIfAny(node);
// First we bind declaration nodes to a symbol if possible. We'll both create a symbol
// and then potentially add the symbol to an appropriate symbol table. Possible
@@ -1940,7 +1924,7 @@ namespace ts {
}
function bindJSDocTypedefTagIfAny(node: Node) {
if (!node.jsDoc) {
if (!hasJSDocNodes(node)) {
return;
}
@@ -1991,7 +1975,7 @@ namespace ts {
// for typedef type names with namespaces, bind the new jsdoc type symbol here
// because it requires all containing namespaces to be in effect, namely the
// current "blockScopeContainer" needs to be set to its immediate namespace parent.
if (isInJavaScriptFile(node) && (<Identifier>node).isInJSDocNamespace) {
if ((<Identifier>node).isInJSDocNamespace) {
let parentNode = node.parent;
while (parentNode && parentNode.kind !== SyntaxKind.JSDocTypedefTag) {
parentNode = parentNode.parent;
@@ -2053,15 +2037,14 @@ namespace ts {
case SyntaxKind.TypePredicate:
return checkTypePredicate(node as TypePredicateNode);
case SyntaxKind.TypeParameter:
if (node.parent.kind !== ts.SyntaxKind.JSDocTemplateTag || isInJavaScriptFile(node)) {
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
}
return;
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
case SyntaxKind.Parameter:
return bindParameter(<ParameterDeclaration>node);
case SyntaxKind.VariableDeclaration:
return bindVariableDeclarationOrBindingElement(<VariableDeclaration>node);
case SyntaxKind.BindingElement:
return bindVariableDeclarationOrBindingElement(<VariableDeclaration | BindingElement>node);
node.flowNode = currentFlow;
return bindVariableDeclarationOrBindingElement(<BindingElement>node);
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
return bindPropertyWorker(node as PropertyDeclaration | PropertySignature);
@@ -2071,22 +2054,6 @@ namespace ts {
case SyntaxKind.EnumMember:
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes);
case SyntaxKind.SpreadAssignment:
case SyntaxKind.JsxSpreadAttribute:
let root = container;
let hasRest = false;
while (root.parent) {
if (root.kind === SyntaxKind.ObjectLiteralExpression &&
root.parent.kind === SyntaxKind.BinaryExpression &&
(root.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken &&
(root.parent as BinaryExpression).left === root) {
hasRest = true;
break;
}
root = root.parent;
}
return;
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.IndexSignature:
@@ -2108,11 +2075,13 @@ namespace ts {
case SyntaxKind.SetAccessor:
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes);
case SyntaxKind.FunctionType:
case SyntaxKind.JSDocFunctionType:
case SyntaxKind.ConstructorType:
return bindFunctionOrConstructorType(<SignatureDeclaration>node);
case SyntaxKind.TypeLiteral:
case SyntaxKind.JSDocTypeLiteral:
case SyntaxKind.MappedType:
return bindAnonymousTypeWorker(node as TypeLiteralNode | MappedTypeNode);
return bindAnonymousTypeWorker(node as TypeLiteralNode | MappedTypeNode | JSDocTypeLiteral);
case SyntaxKind.ObjectLiteralExpression:
return bindObjectLiteralExpression(<ObjectLiteralExpression>node);
case SyntaxKind.FunctionExpression:
@@ -2139,7 +2108,6 @@ namespace ts {
return bindEnumDeclaration(<EnumDeclaration>node);
case SyntaxKind.ModuleDeclaration:
return bindModuleDeclaration(<ModuleDeclaration>node);
// Jsx-attributes
case SyntaxKind.JsxAttributes:
return bindJsxAttributes(<JsxAttributes>node);
@@ -2171,25 +2139,17 @@ namespace ts {
case SyntaxKind.ModuleBlock:
return updateStrictModeStatementList((<Block | ModuleBlock>node).statements);
default:
if (isInJavaScriptFile(node)) return bindJSDocWorker(node);
}
}
function bindJSDocWorker(node: Node) {
switch (node.kind) {
case SyntaxKind.JSDocRecordMember:
return bindPropertyWorker(node as JSDocRecordMember);
case SyntaxKind.JSDocParameterTag:
if (node.parent.kind !== SyntaxKind.JSDocTypeLiteral) {
break;
}
// falls through
case SyntaxKind.JSDocPropertyTag:
return declareSymbolAndAddToSymbolTable(node as JSDocPropertyTag,
(node as JSDocPropertyTag).isBracketed || ((node as JSDocPropertyTag).typeExpression && (node as JSDocPropertyTag).typeExpression.type.kind === SyntaxKind.JSDocOptionalType) ?
SymbolFlags.Property | SymbolFlags.Optional : SymbolFlags.Property,
SymbolFlags.PropertyExcludes);
case SyntaxKind.JSDocFunctionType:
return bindFunctionOrConstructorType(<SignatureDeclaration>node);
case SyntaxKind.JSDocTypeLiteral:
case SyntaxKind.JSDocRecordType:
return bindAnonymousTypeWorker(node as JSDocTypeLiteral | JSDocRecordType);
const propTag = node as JSDocPropertyLikeTag;
const flags = propTag.isBracketed || propTag.typeExpression.type.kind === SyntaxKind.JSDocOptionalType ?
SymbolFlags.Property | SymbolFlags.Optional :
SymbolFlags.Property;
return declareSymbolAndAddToSymbolTable(propTag, flags, SymbolFlags.PropertyExcludes);
case SyntaxKind.JSDocTypedefTag: {
const { fullName } = node as JSDocTypedefTag;
if (!fullName || fullName.kind === SyntaxKind.Identifier) {
@@ -2204,8 +2164,8 @@ namespace ts {
return bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property | (node.questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes);
}
function bindAnonymousTypeWorker(node: TypeLiteralNode | MappedTypeNode | JSDocTypeLiteral | JSDocRecordType) {
return bindAnonymousDeclaration(<Declaration>node, SymbolFlags.TypeLiteral, "__type");
function bindAnonymousTypeWorker(node: TypeLiteralNode | MappedTypeNode | JSDocTypeLiteral) {
return bindAnonymousDeclaration(<Declaration>node, SymbolFlags.TypeLiteral, InternalSymbolName.Type);
}
function checkTypePredicate(node: TypePredicateNode) {
@@ -2227,7 +2187,7 @@ namespace ts {
}
function bindSourceFileAsExternalModule() {
bindAnonymousDeclaration(file, SymbolFlags.ValueModule, `"${removeFileExtension(file.fileName)}"`);
bindAnonymousDeclaration(file, SymbolFlags.ValueModule, `"${removeFileExtension(file.fileName)}"` as __String);
}
function bindExportAssignment(node: ExportAssignment | BinaryExpression) {
@@ -2271,7 +2231,7 @@ namespace ts {
}
}
file.symbol.globalExports = file.symbol.globalExports || createMap<Symbol>();
file.symbol.globalExports = file.symbol.globalExports || createSymbolTable();
declareSymbol(file.symbol.globalExports, file.symbol, node, SymbolFlags.Alias, SymbolFlags.AliasExcludes);
}
@@ -2305,7 +2265,7 @@ namespace ts {
// When we create a property via 'exports.foo = bar', the 'exports.foo' property access
// expression is the declaration
setCommonJsModuleIndicator(node);
declareSymbol(file.symbol.exports, file.symbol, <PropertyAccessExpression>node.left, SymbolFlags.Property | SymbolFlags.Export, SymbolFlags.None);
declareSymbol(file.symbol.exports, file.symbol, <PropertyAccessExpression>node.left, SymbolFlags.Property | SymbolFlags.ExportValue, SymbolFlags.None);
}
function isExportsOrModuleExportsOrAlias(node: Node): boolean {
@@ -2315,21 +2275,17 @@ namespace ts {
}
function isNameOfExportsOrModuleExportsAliasDeclaration(node: Node) {
if (node.kind === SyntaxKind.Identifier) {
const symbol = lookupSymbolForName((<Identifier>node).text);
if (symbol && symbol.valueDeclaration && symbol.valueDeclaration.kind === SyntaxKind.VariableDeclaration) {
const declaration = symbol.valueDeclaration as VariableDeclaration;
if (declaration.initializer) {
return isExportsOrModuleExportsOrAliasOrAssignemnt(declaration.initializer);
}
}
if (isIdentifier(node)) {
const symbol = lookupSymbolForName(node.escapedText);
return symbol && symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) &&
symbol.valueDeclaration.initializer && isExportsOrModuleExportsOrAliasOrAssignment(symbol.valueDeclaration.initializer);
}
return false;
}
function isExportsOrModuleExportsOrAliasOrAssignemnt(node: Node): boolean {
function isExportsOrModuleExportsOrAliasOrAssignment(node: Node): boolean {
return isExportsOrModuleExportsOrAlias(node) ||
(isAssignmentExpression(node, /*excludeCompoundAssignements*/ true) && (isExportsOrModuleExportsOrAliasOrAssignemnt(node.left) || isExportsOrModuleExportsOrAliasOrAssignemnt(node.right)));
(isAssignmentExpression(node, /*excludeCompoundAssignements*/ true) && (isExportsOrModuleExportsOrAliasOrAssignment(node.left) || isExportsOrModuleExportsOrAliasOrAssignment(node.right)));
}
function bindModuleExportsAssignment(node: BinaryExpression) {
@@ -2346,7 +2302,7 @@ namespace ts {
// 'module.exports = expr' assignment
setCommonJsModuleIndicator(node);
declareSymbol(file.symbol.exports, file.symbol, node, SymbolFlags.Property | SymbolFlags.Export | SymbolFlags.ValueModule, SymbolFlags.None);
declareSymbol(file.symbol.exports, file.symbol, node, SymbolFlags.Property | SymbolFlags.ExportValue | SymbolFlags.ValueModule, SymbolFlags.None);
}
function bindThisPropertyAssignment(node: BinaryExpression) {
@@ -2356,7 +2312,7 @@ namespace ts {
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
// Declare a 'member' if the container is an ES5 class or ES6 constructor
container.symbol.members = container.symbol.members || createMap<Symbol>();
container.symbol.members = container.symbol.members || createSymbolTable();
// It's acceptable for multiple 'this' assignments of the same identifier to occur
declareSymbol(container.symbol.members, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property);
break;
@@ -2369,11 +2325,8 @@ namespace ts {
// this.foo assignment in a JavaScript class
// Bind this property to the containing class
const containingClass = container.parent;
const symbol = declareSymbol(hasModifier(container, ModifierFlags.Static) ? containingClass.symbol.exports : containingClass.symbol.members, containingClass.symbol, node, SymbolFlags.Property, SymbolFlags.None);
if (symbol) {
// symbols declared through 'this' property assignements can be overwritten by subsequent method declarations
(symbol as Symbol).isReplaceableByMethod = true;
}
const symbolTable = hasModifier(container, ModifierFlags.Static) ? containingClass.symbol.exports : containingClass.symbol.members;
declareSymbol(symbolTable, containingClass.symbol, node, SymbolFlags.Property, SymbolFlags.None, /*isReplaceableByMethod*/ true);
break;
}
}
@@ -2392,7 +2345,7 @@ namespace ts {
constructorFunction.parent = classPrototype;
classPrototype.parent = leftSideOfAssignment;
bindPropertyAssignment(constructorFunction.text, leftSideOfAssignment, /*isPrototypeProperty*/ true);
bindPropertyAssignment(constructorFunction.escapedText, leftSideOfAssignment, /*isPrototypeProperty*/ true);
}
function bindStaticPropertyAssignment(node: BinaryExpression) {
@@ -2414,15 +2367,15 @@ namespace ts {
bindExportsPropertyAssignment(node);
}
else {
bindPropertyAssignment(target.text, leftSideOfAssignment, /*isPrototypeProperty*/ false);
bindPropertyAssignment(target.escapedText, leftSideOfAssignment, /*isPrototypeProperty*/ false);
}
}
function lookupSymbolForName(name: string) {
function lookupSymbolForName(name: __String) {
return (container.symbol && container.symbol.exports && container.symbol.exports.get(name)) || (container.locals && container.locals.get(name));
}
function bindPropertyAssignment(functionName: string, propertyAccessExpression: PropertyAccessExpression, isPrototypeProperty: boolean) {
function bindPropertyAssignment(functionName: __String, propertyAccessExpression: PropertyAccessExpression, isPrototypeProperty: boolean) {
let targetSymbol = lookupSymbolForName(functionName);
if (targetSymbol && isDeclarationOfFunctionOrClassExpression(targetSymbol)) {
@@ -2435,8 +2388,8 @@ namespace ts {
// Set up the members collection if it doesn't exist already
const symbolTable = isPrototypeProperty ?
(targetSymbol.members || (targetSymbol.members = createMap<Symbol>())) :
(targetSymbol.exports || (targetSymbol.exports = createMap<Symbol>()));
(targetSymbol.members || (targetSymbol.members = createSymbolTable())) :
(targetSymbol.exports || (targetSymbol.exports = createSymbolTable()));
// Declare the method/property
declareSymbol(symbolTable, targetSymbol, propertyAccessExpression, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
@@ -2455,11 +2408,11 @@ namespace ts {
bindBlockScopedDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes);
}
else {
const bindingName = node.name ? node.name.text : "__class";
const bindingName = node.name ? node.name.escapedText : InternalSymbolName.Class;
bindAnonymousDeclaration(node, SymbolFlags.Class, bindingName);
// Add name of class expression into the map for semantic classifier
if (node.name) {
classifiableNames.set(node.name.text, node.name.text);
classifiableNames.set(node.name.escapedText, true);
}
}
@@ -2474,15 +2427,15 @@ namespace ts {
// Note: we check for this here because this class may be merging into a module. The
// module might have an exported variable called 'prototype'. We can't allow that as
// that would clash with the built-in 'prototype' for the class.
const prototypeSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Prototype, "prototype");
const symbolExport = symbol.exports.get(prototypeSymbol.name);
const prototypeSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Prototype, "prototype" as __String);
const symbolExport = symbol.exports.get(prototypeSymbol.escapedName);
if (symbolExport) {
if (node.name) {
node.name.parent = node;
}
file.bindDiagnostics.push(createDiagnosticForNode(symbolExport.declarations[0], Diagnostics.Duplicate_identifier_0, prototypeSymbol.name));
file.bindDiagnostics.push(createDiagnosticForNode(symbolExport.declarations[0], Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(prototypeSymbol.escapedName)));
}
symbol.exports.set(prototypeSymbol.name, prototypeSymbol);
symbol.exports.set(prototypeSymbol.escapedName, prototypeSymbol);
prototypeSymbol.parent = symbol;
}
@@ -2527,7 +2480,7 @@ namespace ts {
}
if (isBindingPattern(node.name)) {
bindAnonymousDeclaration(node, SymbolFlags.FunctionScopedVariable, getDestructuringParameterName(node));
bindAnonymousDeclaration(node, SymbolFlags.FunctionScopedVariable, "__" + indexOf(node.parent.parameters, node) as __String);
}
else {
declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes);
@@ -2568,7 +2521,7 @@ namespace ts {
node.flowNode = currentFlow;
}
checkStrictModeFunctionName(node);
const bindingName = node.name ? node.name.text : "__function";
const bindingName = node.name ? node.name.escapedText : InternalSymbolName.Function;
return bindAnonymousDeclaration(node, SymbolFlags.Function, bindingName);
}
@@ -2582,7 +2535,7 @@ namespace ts {
}
return hasDynamicName(node)
? bindAnonymousDeclaration(node, symbolFlags, "__computed")
? bindAnonymousDeclaration(node, symbolFlags, InternalSymbolName.Computed)
: declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes);
}
@@ -2807,7 +2760,6 @@ namespace ts {
function computeParameter(node: ParameterDeclaration, subtreeFlags: TransformFlags) {
let transformFlags = subtreeFlags;
const modifierFlags = getModifierFlags(node);
const name = node.name;
const initializer = node.initializer;
const dotDotDotToken = node.dotDotDotToken;
@@ -2822,7 +2774,7 @@ namespace ts {
}
// If a parameter has an accessibility modifier, then it is TypeScript syntax.
if (modifierFlags & ModifierFlags.ParameterPropertyModifier) {
if (hasModifier(node, ModifierFlags.ParameterPropertyModifier)) {
transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsParameterPropertyAssignments;
}
@@ -2867,9 +2819,8 @@ namespace ts {
function computeClassDeclaration(node: ClassDeclaration, subtreeFlags: TransformFlags) {
let transformFlags: TransformFlags;
const modifierFlags = getModifierFlags(node);
if (modifierFlags & ModifierFlags.Ambient) {
if (hasModifier(node, ModifierFlags.Ambient)) {
// An ambient declaration is TypeScript syntax.
transformFlags = TransformFlags.AssertTypeScript;
}
@@ -2944,7 +2895,10 @@ namespace ts {
function computeCatchClause(node: CatchClause, subtreeFlags: TransformFlags) {
let transformFlags = subtreeFlags;
if (node.variableDeclaration && isBindingPattern(node.variableDeclaration.name)) {
if (!node.variableDeclaration) {
transformFlags |= TransformFlags.AssertESNext;
}
else if (isBindingPattern(node.variableDeclaration.name)) {
transformFlags |= TransformFlags.AssertES2015;
}
@@ -3210,11 +3164,10 @@ namespace ts {
function computeVariableStatement(node: VariableStatement, subtreeFlags: TransformFlags) {
let transformFlags: TransformFlags;
const modifierFlags = getModifierFlags(node);
const declarationListTransformFlags = node.declarationList.transformFlags;
// An ambient declaration is TypeScript syntax.
if (modifierFlags & ModifierFlags.Ambient) {
if (hasModifier(node, ModifierFlags.Ambient)) {
transformFlags = TransformFlags.AssertTypeScript;
}
else {
@@ -3603,4 +3556,13 @@ namespace ts {
return TransformFlags.NodeExcludes;
}
}
}
/**
* "Binds" JSDoc nodes in TypeScript code.
* Since we will never create symbols for JSDoc, we just set parent pointers instead.
*/
function setParentPointers(parent: Node, child: Node): void {
child.parent = parent;
forEachChild(child, (childsChild) => setParentPointers(child, childsChild));
}
}
+2343 -1875
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+5 -15
View File
@@ -8,7 +8,7 @@ namespace ts {
setWriter(writer: EmitTextWriter): void;
emitNodeWithComments(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
emitBodyWithDetachedComments(node: Node, detachedRange: TextRange, emitCallback: (node: Node) => void): void;
emitTrailingCommentsOfPosition(pos: number): void;
emitTrailingCommentsOfPosition(pos: number, prefixSpace?: boolean): void;
emitLeadingCommentsOfPosition(pos: number): void;
}
@@ -21,7 +21,7 @@ namespace ts {
let declarationListContainerEnd = -1;
let currentSourceFile: SourceFile;
let currentText: string;
let currentLineMap: number[];
let currentLineMap: ReadonlyArray<number>;
let detachedCommentsInfo: { nodePos: number, detachedCommentEndPos: number}[];
let hasWrittenComment = false;
let disabled: boolean = printerOptions.removeComments;
@@ -306,7 +306,7 @@ namespace ts {
}
}
function emitTrailingCommentsOfPosition(pos: number) {
function emitTrailingCommentsOfPosition(pos: number, prefixSpace?: boolean) {
if (disabled) {
return;
}
@@ -315,7 +315,7 @@ namespace ts {
performance.mark("beforeEmitTrailingCommentsOfPosition");
}
forEachTrailingCommentToEmit(pos, emitTrailingCommentOfPosition);
forEachTrailingCommentToEmit(pos, prefixSpace ? emitTrailingComment : emitTrailingCommentOfPosition);
if (extendedDiagnostics) {
performance.measure("commentTime", "beforeEmitTrailingCommentsOfPosition");
@@ -415,17 +415,7 @@ namespace ts {
* @return true if the comment is a triple-slash comment else false
*/
function isTripleSlashComment(commentPos: number, commentEnd: number) {
// Verify this is /// comment, but do the regexp match only when we first can find /// in the comment text
// so that we don't end up computing comment string and doing match for all // comments
if (currentText.charCodeAt(commentPos + 1) === CharacterCodes.slash &&
commentPos + 2 < commentEnd &&
currentText.charCodeAt(commentPos + 2) === CharacterCodes.slash) {
const textSubStr = currentText.substring(commentPos, commentEnd);
return textSubStr.match(fullTripleSlashReferencePathRegEx) ||
textSubStr.match(fullTripleSlashAMDReferencePathRegEx) ?
true : false;
}
return false;
return isRecognizedTripleSlashComment(currentText, commentPos, commentEnd);
}
}
}
+359 -259
View File
File diff suppressed because it is too large Load Diff
+19 -13
View File
@@ -60,7 +60,7 @@ namespace ts {
let enclosingDeclaration: Node;
let resultHasExternalModuleIndicator: boolean;
let currentText: string;
let currentLineMap: number[];
let currentLineMap: ReadonlyArray<number>;
let currentIdentifiers: Map<string>;
let isCurrentFileExternalModule: boolean;
let reportedDeclarationError = false;
@@ -211,7 +211,7 @@ namespace ts {
decreaseIndent = newWriter.decreaseIndent;
}
function writeAsynchronousModuleElements(nodes: Node[]) {
function writeAsynchronousModuleElements(nodes: ReadonlyArray<Node>) {
const oldWriter = writer;
forEach(nodes, declaration => {
let nodeToCheck: Node;
@@ -335,9 +335,12 @@ namespace ts {
write(": ");
// use the checker's type, not the declared type,
// for non-optional initialized parameters that aren't a parameter property
// for optional parameter properties
// and also for non-optional initialized parameters that aren't a parameter property
// these types may need to add `undefined`.
const shouldUseResolverType = declaration.kind === SyntaxKind.Parameter &&
resolver.isRequiredInitializedParameter(declaration as ParameterDeclaration);
(resolver.isRequiredInitializedParameter(declaration as ParameterDeclaration) ||
resolver.isOptionalUninitializedParameterProperty(declaration as ParameterDeclaration));
if (type && !shouldUseResolverType) {
// Write the type
emitType(type);
@@ -346,7 +349,6 @@ namespace ts {
errorNameNode = declaration.name;
const format = TypeFormatFlags.UseTypeOfFunction |
TypeFormatFlags.WriteClassExpressionAsTypeLiteral |
TypeFormatFlags.UseTypeAliasValue |
(shouldUseResolverType ? TypeFormatFlags.AddUndefined : 0);
resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, format, writer);
errorNameNode = undefined;
@@ -365,19 +367,19 @@ namespace ts {
resolver.writeReturnTypeOfSignatureDeclaration(
signature,
enclosingDeclaration,
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
writer);
errorNameNode = undefined;
}
}
function emitLines(nodes: Node[]) {
function emitLines(nodes: ReadonlyArray<Node>) {
for (const node of nodes) {
emit(node);
}
}
function emitSeparatedList(nodes: Node[], separator: string, eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) {
function emitSeparatedList(nodes: ReadonlyArray<Node>, separator: string, eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) {
let currentWriterPos = writer.getTextPos();
for (const node of nodes) {
if (!canEmitFn || canEmitFn(node)) {
@@ -390,7 +392,7 @@ namespace ts {
}
}
function emitCommaList(nodes: Node[], eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) {
function emitCommaList(nodes: ReadonlyArray<Node>, eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) {
emitSeparatedList(nodes, ", ", eachNodeEmitFn, canEmitFn);
}
@@ -632,7 +634,7 @@ namespace ts {
resolver.writeTypeOfExpression(
expr,
enclosingDeclaration,
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
writer);
write(";");
writeLine();
@@ -1006,7 +1008,7 @@ namespace ts {
return node.parent.kind === SyntaxKind.MethodDeclaration && hasModifier(node.parent, ModifierFlags.Private);
}
function emitTypeParameters(typeParameters: TypeParameterDeclaration[]) {
function emitTypeParameters(typeParameters: ReadonlyArray<TypeParameterDeclaration>) {
function emitTypeParameter(node: TypeParameterDeclaration) {
increaseIndent();
emitJsDocComments(node);
@@ -1108,7 +1110,7 @@ namespace ts {
}
}
function emitHeritageClause(typeReferences: ExpressionWithTypeArguments[], isImplementsList: boolean) {
function emitHeritageClause(typeReferences: ReadonlyArray<ExpressionWithTypeArguments>, isImplementsList: boolean) {
if (typeReferences) {
write(isImplementsList ? " implements " : " extends ");
emitCommaList(typeReferences, emitTypeOfTypeReference);
@@ -1163,7 +1165,7 @@ namespace ts {
if (baseTypeNode && !isEntityNameExpression(baseTypeNode.expression)) {
tempVarName = baseTypeNode.expression.kind === SyntaxKind.NullKeyword ?
"null" :
emitTempVariableDeclaration(baseTypeNode.expression, `${node.name.text}_base`, {
emitTempVariableDeclaration(baseTypeNode.expression, `${node.name.escapedText}_base`, {
diagnosticMessage: Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1,
errorNode: baseTypeNode,
typeName: node.name
@@ -1381,6 +1383,10 @@ namespace ts {
}
function writeVariableStatement(node: VariableStatement) {
// If binding pattern doesn't have name, then there is nothing to be emitted for declaration file i.e. const [,] = [1,2].
if (every(node.declarationList && node.declarationList.declarations, decl => decl.name && isEmptyBindingPattern(decl.name))) {
return;
}
emitJsDocComments(node);
emitModuleElementDeclarationFlags(node);
if (isLet(node.declarationList)) {
+88 -27
View File
@@ -1,4 +1,4 @@
{
{
"Unterminated string literal.": {
"category": "Error",
"code": 1002
@@ -627,11 +627,11 @@
"category": "Error",
"code": 1200
},
"Import assignment cannot be used when targeting ECMAScript 2015 modules. Consider using 'import * as ns from \"mod\"', 'import {a} from \"mod\"', 'import d from \"mod\"', or another module format instead.": {
"Import assignment cannot be used when targeting ECMAScript modules. Consider using 'import * as ns from \"mod\"', 'import {a} from \"mod\"', 'import d from \"mod\"', or another module format instead.": {
"category": "Error",
"code": 1202
},
"Export assignment cannot be used when targeting ECMAScript 2015 modules. Consider using 'export default' or another module format instead.": {
"Export assignment cannot be used when targeting ECMAScript modules. Consider using 'export default' or another module format instead.": {
"category": "Error",
"code": 1203
},
@@ -707,7 +707,7 @@
"category": "Error",
"code": 1223
},
"Signature '{0}' must have a type predicate.": {
"Signature '{0}' must be a type predicate.": {
"category": "Error",
"code": 1224
},
@@ -899,14 +899,22 @@
"category": "Error",
"code": 1326
},
"Unique 'symbol()' types are only allowed on variables and properties.": {
"String literal with double quotes expected.": {
"category": "Error",
"code": 1327
},
"Unique 'symbol()' types may not be used on a variable declaration with a binding name.": {
"Property value can only be string literal, numeric literal, 'true', 'false', 'null', object literal or array literal.": {
"category": "Error",
"code": 1328
},
"Unique 'symbol()' types are only allowed on variables and properties.": {
"category": "Error",
"code": 1329
},
"Unique 'symbol()' types may not be used on a variable declaration with a binding name.": {
"category": "Error",
"code": 1330
},
"Duplicate identifier '{0}'.": {
"category": "Error",
@@ -1908,6 +1916,22 @@
"category": "Error",
"code": 2559
},
"Value of type '{0}' has no properties in common with type '{1}'. Did you mean to call it?": {
"category": "Error",
"code": 2560
},
"Object literal may only specify known properties, but '{0}' does not exist in type '{1}'. Did you mean to write '{2}'?": {
"category": "Error",
"code": 2561
},
"Base class expressions cannot reference class type parameters.": {
"category": "Error",
"code": 2562
},
"The containing function or module body is too large for control flow analysis.": {
"category": "Error",
"code": 2563
},
"JSX element attributes type '{0}' may not be a union type.": {
"category": "Error",
"code": 2600
@@ -2064,7 +2088,7 @@
"category": "Error",
"code": 2679
},
"A 'this' parameter must be the first parameter.": {
"A '{0}' parameter must be the first parameter.": {
"category": "Error",
"code": 2680
},
@@ -2192,14 +2216,22 @@
"category": "Error",
"code": 2712
},
"Subsequent property declarations must have the same type. Property '{0}' must be of type '{1}', but here has type '{2}'.": {
"Cannot access '{0}.{1}' because '{0}' is a type, but not a namespace. Did you mean to retrieve the type of the property '{1}' in '{0}' with '{0}[\"{1}\"]'?": {
"category": "Error",
"code": 2713
},
"Duplicate declaration '{0}'.": {
"The expression of an export assignment must be an identifier or qualified name in an ambient context.": {
"category": "Error",
"code": 2714
},
"Subsequent property declarations must have the same type. Property '{0}' must be of type '{1}', but here has type '{2}'.": {
"category": "Error",
"code": 2715
},
"Duplicate declaration '{0}'.": {
"category": "Error",
"code": 2716
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
@@ -2662,11 +2694,15 @@
"category": "Message",
"code": 6012
},
"Do not resolve the real path of symlinks.": {
"category": "Message",
"code": 6013
},
"Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'.": {
"category": "Message",
"code": 6015
},
"Specify module code generation: 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.": {
"Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.": {
"category": "Message",
"code": 6016
},
@@ -3086,7 +3122,7 @@
"category": "Message",
"code": 6132
},
"'{0}' is declared but never used.": {
"'{0}' is declared but its value is never read.": {
"category": "Error",
"code": 6133
},
@@ -3106,7 +3142,7 @@
"category": "Error",
"code": 6137
},
"Property '{0}' is declared but never used.": {
"Property '{0}' is declared but its value is never read.": {
"category": "Error",
"code": 6138
},
@@ -3126,10 +3162,6 @@
"category": "Error",
"code": 6142
},
"Module '{0}' was resolved to '{1}', but '--allowJs' is not set.": {
"category": "Error",
"code": 6143
},
"Module '{0}' was resolved as locally declared ambient module in file '{1}'.": {
"category": "Message",
"code": 6144
@@ -3294,6 +3326,10 @@
"category": "Message",
"code": 6184
},
"Disable strict checking of generic signatures in function types.": {
"category": "Message",
"code": 6185
},
"Variable '{0}' implicitly has an '{1}' type.": {
"category": "Error",
"code": 7005
@@ -3459,6 +3495,10 @@
"category": "Error",
"code": 8012
},
"'non-null assertions' can only be used in a .ts file.": {
"category": "Error",
"code": 8013
},
"'enum declarations' can only be used in a .ts file.": {
"category": "Error",
"code": 8015
@@ -3467,6 +3507,22 @@
"category": "Error",
"code": 8016
},
"Octal literal types must use ES2015 syntax. Use the syntax '{0}'.": {
"category": "Error",
"code": 8017
},
"Octal literals are not allowed in enums members initializer. Use the syntax '{0}'.": {
"category": "Error",
"code": 8018
},
"Report errors in .js files.": {
"category": "Message",
"code": 8019
},
"JSDoc types can only be used inside documentation comments.": {
"category": "Error",
"code": 8020
},
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clause.": {
"category": "Error",
"code": 9002
@@ -3637,7 +3693,15 @@
"category": "Message",
"code": 90024
},
"Prefix '{0}' with an underscore.": {
"category": "Message",
"code": 90025
},
"Rewrite as the indexed access type '{0}'.": {
"category": "Message",
"code": 90026
},
"Convert function to an ES2015 class": {
"category": "Message",
"code": 95001
@@ -3647,16 +3711,13 @@
"code": 95002
},
"Octal literal types must use ES2015 syntax. Use the syntax '{0}'.": {
"category": "Error",
"code": 8017
},
"Octal literals are not allowed in enums members initializer. Use the syntax '{0}'.": {
"category": "Error",
"code": 8018
},
"Report errors in .js files.": {
"Extract function": {
"category": "Message",
"code": 8019
"code": 95003
},
"Extract to {0}": {
"category": "Message",
"code": 95004
}
}
+187 -117
View File
@@ -8,6 +8,70 @@ namespace ts {
const delimiters = createDelimiterMap();
const brackets = createBracketsMap();
/*@internal*/
/**
* Iterates over the source files that are expected to have an emit output.
*
* @param host An EmitHost.
* @param action The action to execute.
* @param sourceFilesOrTargetSourceFile
* If an array, the full list of source files to emit.
* Else, calls `getSourceFilesToEmit` with the (optional) target source file to determine the list of source files to emit.
*/
export function forEachEmittedFile(
host: EmitHost, action: (emitFileNames: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle, emitOnlyDtsFiles: boolean) => void,
sourceFilesOrTargetSourceFile?: SourceFile[] | SourceFile,
emitOnlyDtsFiles?: boolean) {
const sourceFiles = isArray(sourceFilesOrTargetSourceFile) ? sourceFilesOrTargetSourceFile : getSourceFilesToEmit(host, sourceFilesOrTargetSourceFile);
const options = host.getCompilerOptions();
if (options.outFile || options.out) {
if (sourceFiles.length) {
const jsFilePath = options.outFile || options.out;
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
const declarationFilePath = options.declaration ? removeFileExtension(jsFilePath) + Extension.Dts : "";
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, createBundle(sourceFiles), emitOnlyDtsFiles);
}
}
else {
for (const sourceFile of sourceFiles) {
const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, getOutputExtension(sourceFile, options));
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (emitOnlyDtsFiles || options.declaration) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, sourceFile, emitOnlyDtsFiles);
}
}
}
function getSourceMapFilePath(jsFilePath: string, options: CompilerOptions) {
return options.sourceMap ? jsFilePath + ".map" : undefined;
}
// JavaScript files are always LanguageVariant.JSX, as JSX syntax is allowed in .js files also.
// So for JavaScript files, '.jsx' is only emitted if the input was '.jsx', and JsxEmit.Preserve.
// For TypeScript, the only time to emit with a '.jsx' extension, is on JSX input, and JsxEmit.Preserve
function getOutputExtension(sourceFile: SourceFile, options: CompilerOptions): Extension {
if (options.jsx === JsxEmit.Preserve) {
if (isSourceFileJavaScript(sourceFile)) {
if (fileExtensionIs(sourceFile.fileName, Extension.Jsx)) {
return Extension.Jsx;
}
}
else if (sourceFile.languageVariant === LanguageVariant.JSX) {
// TypeScript source file preserving JSX syntax
return Extension.Jsx;
}
}
return Extension.Js;
}
function getOriginalSourceFileOrBundle(sourceFileOrBundle: SourceFile | Bundle) {
if (sourceFileOrBundle.kind === SyntaxKind.Bundle) {
return updateBundle(sourceFileOrBundle, sameMap(sourceFileOrBundle.sourceFiles, getOriginalSourceFile));
}
return getOriginalSourceFile(sourceFileOrBundle);
}
/*@internal*/
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile, emitOnlyDtsFiles?: boolean, transformers?: TransformerFactory<SourceFile>[]): EmitResult {
@@ -217,7 +281,7 @@ namespace ts {
let currentSourceFile: SourceFile | undefined;
let nodeIdToGeneratedName: string[]; // Map of generated names for specific nodes.
let autoGeneratedIdToGeneratedName: string[]; // Map of generated names for temp and loop variables.
let generatedNames: Map<string>; // Set of names generated by the NameGenerator.
let generatedNames: Map<true>; // Set of names generated by the NameGenerator.
let tempFlagsStack: TempFlags[]; // Stack of enclosing name generation scopes.
let tempFlags: TempFlags; // TempFlags for the current name generation scope.
let writer: EmitTextWriter;
@@ -335,13 +399,21 @@ namespace ts {
function reset() {
nodeIdToGeneratedName = [];
autoGeneratedIdToGeneratedName = [];
generatedNames = createMap<string>();
generatedNames = createMap<true>();
tempFlagsStack = [];
tempFlags = TempFlags.Auto;
comments.reset();
setWriter(/*output*/ undefined);
}
// TODO: Should this just be `emit`?
// See https://github.com/Microsoft/TypeScript/pull/18284#discussion_r137611034
function emitIfPresent(node: Node | undefined) {
if (node) {
emit(node);
}
}
function emit(node: Node) {
pipelineEmitWithNotification(EmitHint.Unspecified, node);
}
@@ -387,6 +459,7 @@ namespace ts {
case EmitHint.SourceFile: return pipelineEmitSourceFile(node);
case EmitHint.IdentifierName: return pipelineEmitIdentifierName(node);
case EmitHint.Expression: return pipelineEmitExpression(node);
case EmitHint.MappedTypeParameter: return emitMappedTypeParameter(cast(node, isTypeParameterDeclaration));
case EmitHint.Unspecified: return pipelineEmitUnspecified(node);
}
}
@@ -401,6 +474,12 @@ namespace ts {
emitIdentifier(<Identifier>node);
}
function emitMappedTypeParameter(node: TypeParameterDeclaration): void {
emit(node.name);
write(" in ");
emit(node.constraint);
}
function pipelineEmitUnspecified(node: Node): void {
const kind = node.kind;
@@ -836,9 +915,9 @@ namespace ts {
function emitParameter(node: ParameterDeclaration) {
emitDecorators(node, node.decorators);
emitModifiers(node, node.modifiers);
writeIfPresent(node.dotDotDotToken, "...");
emitIfPresent(node.dotDotDotToken);
emit(node.name);
writeIfPresent(node.questionToken, "?");
emitIfPresent(node.questionToken);
emitWithPrefix(": ", node.type);
emitExpressionWithPrefix(" = ", node.initializer);
}
@@ -856,7 +935,7 @@ namespace ts {
emitDecorators(node, node.decorators);
emitModifiers(node, node.modifiers);
emit(node.name);
writeIfPresent(node.questionToken, "?");
emitIfPresent(node.questionToken);
emitWithPrefix(": ", node.type);
write(";");
}
@@ -865,7 +944,7 @@ namespace ts {
emitDecorators(node, node.decorators);
emitModifiers(node, node.modifiers);
emit(node.name);
writeIfPresent(node.questionToken, "?");
emitIfPresent(node.questionToken);
emitWithPrefix(": ", node.type);
emitExpressionWithPrefix(" = ", node.initializer);
write(";");
@@ -875,7 +954,7 @@ namespace ts {
emitDecorators(node, node.decorators);
emitModifiers(node, node.modifiers);
emit(node.name);
writeIfPresent(node.questionToken, "?");
emitIfPresent(node.questionToken);
emitTypeParameters(node, node.typeParameters);
emitParameters(node, node.parameters);
emitWithPrefix(": ", node.type);
@@ -885,9 +964,9 @@ namespace ts {
function emitMethodDeclaration(node: MethodDeclaration) {
emitDecorators(node, node.decorators);
emitModifiers(node, node.modifiers);
writeIfPresent(node.asteriskToken, "*");
emitIfPresent(node.asteriskToken);
emit(node.name);
writeIfPresent(node.questionToken, "?");
emitIfPresent(node.questionToken);
emitSignatureAndBody(node, emitSignatureHead);
}
@@ -973,10 +1052,8 @@ namespace ts {
function emitTypeLiteral(node: TypeLiteralNode) {
write("{");
// If the literal is empty, do not add spaces between braces.
if (node.members.length > 0) {
emitList(node, node.members, getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTypeLiteralMembers : ListFormat.MultiLineTypeLiteralMembers);
}
const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTypeLiteralMembers : ListFormat.MultiLineTypeLiteralMembers;
emitList(node, node.members, flags | ListFormat.NoSpaceIfEmpty);
write("}");
}
@@ -1032,13 +1109,16 @@ namespace ts {
writeLine();
increaseIndent();
}
writeIfPresent(node.readonlyToken, "readonly ");
if (node.readonlyToken) {
emit(node.readonlyToken);
write(" ");
}
write("[");
emit(node.typeParameter.name);
write(" in ");
emit(node.typeParameter.constraint);
pipelineEmitWithNotification(EmitHint.MappedTypeParameter, node.typeParameter);
write("]");
writeIfPresent(node.questionToken, "?");
emitIfPresent(node.questionToken);
write(": ");
emit(node.type);
write(";");
@@ -1086,7 +1166,7 @@ namespace ts {
function emitBindingElement(node: BindingElement) {
emitWithSuffix(node.propertyName, ": ");
writeIfPresent(node.dotDotDotToken, "...");
emitIfPresent(node.dotDotDotToken);
emit(node.name);
emitExpressionWithPrefix(" = ", node.initializer);
}
@@ -1097,33 +1177,22 @@ namespace ts {
function emitArrayLiteralExpression(node: ArrayLiteralExpression) {
const elements = node.elements;
if (elements.length === 0) {
write("[]");
}
else {
const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None;
emitExpressionList(node, elements, ListFormat.ArrayLiteralExpressionElements | preferNewLine);
}
const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None;
emitExpressionList(node, elements, ListFormat.ArrayLiteralExpressionElements | preferNewLine);
}
function emitObjectLiteralExpression(node: ObjectLiteralExpression) {
const properties = node.properties;
if (properties.length === 0) {
write("{}");
const indentedFlag = getEmitFlags(node) & EmitFlags.Indented;
if (indentedFlag) {
increaseIndent();
}
else {
const indentedFlag = getEmitFlags(node) & EmitFlags.Indented;
if (indentedFlag) {
increaseIndent();
}
const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None;
const allowTrailingComma = currentSourceFile.languageVersion >= ScriptTarget.ES5 ? ListFormat.AllowTrailingComma : ListFormat.None;
emitList(node, properties, ListFormat.ObjectLiteralExpressionProperties | allowTrailingComma | preferNewLine);
const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None;
const allowTrailingComma = currentSourceFile.languageVersion >= ScriptTarget.ES5 ? ListFormat.AllowTrailingComma : ListFormat.None;
emitList(node, node.properties, ListFormat.ObjectLiteralExpressionProperties | allowTrailingComma | preferNewLine);
if (indentedFlag) {
decreaseIndent();
}
if (indentedFlag) {
decreaseIndent();
}
}
@@ -1133,7 +1202,9 @@ namespace ts {
if (!(getEmitFlags(node) & EmitFlags.NoIndentation)) {
const dotRangeStart = node.expression.end;
const dotRangeEnd = skipTrivia(currentSourceFile.text, node.expression.end) + 1;
const dotToken = <Node>{ kind: SyntaxKind.DotToken, pos: dotRangeStart, end: dotRangeEnd };
const dotToken = createToken(SyntaxKind.DotToken);
dotToken.pos = dotRangeStart;
dotToken.end = dotRangeEnd;
indentBeforeDot = needsIndentation(node, node.expression, dotToken);
indentAfterDot = needsIndentation(node, dotToken, node.name);
}
@@ -1222,7 +1293,8 @@ namespace ts {
emitTypeParameters(node, node.typeParameters);
emitParametersForArrow(node, node.parameters);
emitWithPrefix(": ", node.type);
write(" =>");
write(" ");
emit(node.equalsGreaterThanToken);
}
function emitDeleteExpression(node: DeleteExpression) {
@@ -1284,7 +1356,9 @@ namespace ts {
emitExpression(node.left);
increaseIndentIf(indentBeforeOperator, isCommaOperator ? " " : undefined);
emitLeadingCommentsOfPosition(node.operatorToken.pos);
writeTokenNode(node.operatorToken);
emitTrailingCommentsOfPosition(node.operatorToken.end, /*prefixSpace*/ true); // Binary operators should have a space before the comment starts
increaseIndentIf(indentAfterOperator, " ");
emitExpression(node.right);
decreaseIndentIf(indentBeforeOperator, indentAfterOperator);
@@ -1298,13 +1372,13 @@ namespace ts {
emitExpression(node.condition);
increaseIndentIf(indentBeforeQuestion, " ");
write("?");
emit(node.questionToken);
increaseIndentIf(indentAfterQuestion, " ");
emitExpression(node.whenTrue);
decreaseIndentIf(indentBeforeQuestion, indentAfterQuestion);
increaseIndentIf(indentBeforeColon, " ");
write(":");
emit(node.colonToken);
increaseIndentIf(indentAfterColon, " ");
emitExpression(node.whenFalse);
decreaseIndentIf(indentBeforeColon, indentAfterColon);
@@ -1316,7 +1390,8 @@ namespace ts {
}
function emitYieldExpression(node: YieldExpression) {
write(node.asteriskToken ? "yield*" : "yield");
write("yield");
emit(node.asteriskToken);
emitExpressionWithPrefix(" ", node.expression);
}
@@ -1367,29 +1442,18 @@ namespace ts {
//
function emitBlock(node: Block) {
if (isSingleLineEmptyBlock(node)) {
writeToken(SyntaxKind.OpenBraceToken, node.pos, /*contextNode*/ node);
write(" ");
writeToken(SyntaxKind.CloseBraceToken, node.statements.end, /*contextNode*/ node);
}
else {
writeToken(SyntaxKind.OpenBraceToken, node.pos, /*contextNode*/ node);
emitBlockStatements(node);
// We have to call emitLeadingComments explicitly here because otherwise leading comments of the close brace token will not be emitted
increaseIndent();
emitLeadingCommentsOfPosition(node.statements.end);
decreaseIndent();
writeToken(SyntaxKind.CloseBraceToken, node.statements.end, /*contextNode*/ node);
}
writeToken(SyntaxKind.OpenBraceToken, node.pos, /*contextNode*/ node);
emitBlockStatements(node, /*forceSingleLine*/ !node.multiLine && isEmptyBlock(node));
// We have to call emitLeadingComments explicitly here because otherwise leading comments of the close brace token will not be emitted
increaseIndent();
emitLeadingCommentsOfPosition(node.statements.end);
decreaseIndent();
writeToken(SyntaxKind.CloseBraceToken, node.statements.end, /*contextNode*/ node);
}
function emitBlockStatements(node: BlockLike) {
if (getEmitFlags(node) & EmitFlags.SingleLine) {
emitList(node, node.statements, ListFormat.SingleLineBlockStatements);
}
else {
emitList(node, node.statements, ListFormat.MultiLineBlockStatements);
}
function emitBlockStatements(node: BlockLike, forceSingleLine: boolean) {
const format = forceSingleLine || getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineBlockStatements : ListFormat.MultiLineBlockStatements;
emitList(node, node.statements, format);
}
function emitVariableStatement(node: VariableStatement) {
@@ -1508,8 +1572,20 @@ namespace ts {
write(";");
}
function emitTokenWithComment(token: SyntaxKind, pos: number, contextNode?: Node) {
const node = contextNode && getParseTreeNode(contextNode);
if (node && node.kind === contextNode.kind) {
pos = skipTrivia(currentSourceFile.text, pos);
}
pos = writeToken(token, pos, /*contextNode*/ contextNode);
if (node && node.kind === contextNode.kind) {
emitTrailingCommentsOfPosition(pos, /*prefixSpace*/ true);
}
return pos;
}
function emitReturnStatement(node: ReturnStatement) {
writeToken(SyntaxKind.ReturnKeyword, node.pos, /*contextNode*/ node);
emitTokenWithComment(SyntaxKind.ReturnKeyword, node.pos, /*contextNode*/ node);
emitExpressionWithPrefix(" ", node.expression);
write(";");
}
@@ -1584,7 +1660,9 @@ namespace ts {
function emitFunctionDeclarationOrExpression(node: FunctionDeclaration | FunctionExpression) {
emitDecorators(node, node.decorators);
emitModifiers(node, node.modifiers);
write(node.asteriskToken ? "function* " : "function ");
write("function");
emitIfPresent(node.asteriskToken);
write(" ");
emitIdentifierName(node.name);
emitSignatureAndBody(node, emitSignatureHead);
}
@@ -1802,16 +1880,11 @@ namespace ts {
}
function emitModuleBlock(node: ModuleBlock) {
if (isEmptyBlock(node)) {
write("{ }");
}
else {
pushNameGenerationScope();
write("{");
emitBlockStatements(node);
write("}");
popNameGenerationScope();
}
pushNameGenerationScope();
write("{");
emitBlockStatements(node, /*forceSingleLine*/ isEmptyBlock(node));
write("}");
popNameGenerationScope();
}
function emitCaseBlock(node: CaseBlock) {
@@ -1990,9 +2063,7 @@ namespace ts {
function emitJsxExpression(node: JsxExpression) {
if (node.expression) {
write("{");
if (node.dotDotDotToken) {
write("...");
}
emitIfPresent(node.dotDotDotToken);
emitExpression(node.expression);
write("}");
}
@@ -2050,13 +2121,12 @@ namespace ts {
emitTrailingCommentsOfPosition(statements.pos);
}
let format = ListFormat.CaseOrDefaultClauseStatements;
if (emitAsSingleStatement) {
write(" ");
emit(statements[0]);
}
else {
emitList(parentNode, statements, ListFormat.CaseOrDefaultClauseStatements);
format &= ~(ListFormat.MultiLine | ListFormat.Indented);
}
emitList(parentNode, statements, format);
}
function emitHeritageClause(node: HeritageClause) {
@@ -2069,10 +2139,12 @@ namespace ts {
function emitCatchClause(node: CatchClause) {
const openParenPos = writeToken(SyntaxKind.CatchKeyword, node.pos);
write(" ");
writeToken(SyntaxKind.OpenParenToken, openParenPos);
emit(node.variableDeclaration);
writeToken(SyntaxKind.CloseParenToken, node.variableDeclaration ? node.variableDeclaration.end : openParenPos);
write(" ");
if (node.variableDeclaration) {
writeToken(SyntaxKind.OpenParenToken, openParenPos);
emit(node.variableDeclaration);
writeToken(SyntaxKind.CloseParenToken, node.variableDeclaration.end);
write(" ");
}
emit(node.block);
}
@@ -2166,7 +2238,7 @@ namespace ts {
* Emits any prologue directives at the start of a Statement list, returning the
* number of prologue directives written to the output.
*/
function emitPrologueDirectives(statements: Node[], startWithNewLine?: boolean, seenPrologueDirectives?: Map<String>): number {
function emitPrologueDirectives(statements: ReadonlyArray<Node>, startWithNewLine?: boolean, seenPrologueDirectives?: Map<true>): number {
for (let i = 0; i < statements.length; i++) {
const statement = statements[i];
if (isPrologueDirective(statement)) {
@@ -2177,7 +2249,7 @@ namespace ts {
}
emit(statement);
if (seenPrologueDirectives) {
seenPrologueDirectives.set(statement.expression.text, statement.expression.text);
seenPrologueDirectives.set(statement.expression.text, true);
}
}
}
@@ -2196,7 +2268,7 @@ namespace ts {
emitPrologueDirectives((sourceFileOrBundle as SourceFile).statements);
}
else {
const seenPrologueDirectives = createMap<String>();
const seenPrologueDirectives = createMap<true>();
for (const sourceFile of (sourceFileOrBundle as Bundle).sourceFiles) {
setSourceFile(sourceFile);
emitPrologueDirectives(sourceFile.statements, /*startWithNewLine*/ true, seenPrologueDirectives);
@@ -2304,7 +2376,7 @@ namespace ts {
function emitParametersForArrow(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray<ParameterDeclaration>) {
if (canEmitSimpleArrowHead(parentNode, parameters)) {
emit(parameters[0]);
emitList(parentNode, parameters, ListFormat.Parameters & ~ListFormat.Parenthesis);
}
else {
emitParameters(parentNode, parameters);
@@ -2329,8 +2401,14 @@ namespace ts {
return;
}
const isEmpty = isUndefined || children.length === 0 || start >= children.length || count === 0;
const isEmpty = isUndefined || start >= children.length || count === 0;
if (isEmpty && format & ListFormat.OptionalIfEmpty) {
if (onBeforeEmitNodeArray) {
onBeforeEmitNodeArray(children);
}
if (onAfterEmitNodeArray) {
onAfterEmitNodeArray(children);
}
return;
}
@@ -2347,7 +2425,7 @@ namespace ts {
if (format & ListFormat.MultiLine) {
writeLine();
}
else if (format & ListFormat.SpaceBetweenBraces) {
else if (format & ListFormat.SpaceBetweenBraces && !(format & ListFormat.NoSpaceIfEmpty)) {
write(" ");
}
}
@@ -2439,7 +2517,7 @@ namespace ts {
// 2
// /* end of element 2 */
// ];
if (previousSibling && delimiter && previousSibling.end !== parentNode.end) {
if (previousSibling && delimiter && previousSibling.end !== parentNode.end && !(getEmitFlags(previousSibling) & EmitFlags.NoTrailingComments)) {
emitLeadingCommentsOfPosition(previousSibling.end);
}
@@ -2488,12 +2566,6 @@ namespace ts {
}
}
function writeIfPresent(node: Node, text: string) {
if (node) {
write(text);
}
}
function writeToken(token: SyntaxKind, pos: number, contextNode?: Node) {
return onEmitSourceMapOfToken
? onEmitSourceMapOfToken(contextNode, token, pos, writeTokenText)
@@ -2504,7 +2576,7 @@ namespace ts {
if (onBeforeEmitToken) {
onBeforeEmitToken(node);
}
writeTokenText(node.kind);
write(tokenToString(node.kind));
if (onAfterEmitToken) {
onAfterEmitToken(node);
}
@@ -2676,11 +2748,6 @@ namespace ts {
&& !rangeEndIsOnSameLineAsRangeStart(node1, node2, currentSourceFile);
}
function isSingleLineEmptyBlock(block: Block) {
return !block.multiLine
&& isEmptyBlock(block);
}
function isEmptyBlock(block: BlockLike) {
return block.statements.length === 0
&& rangeEndIsOnSameLineAsRangeStart(block, block, currentSourceFile);
@@ -2699,7 +2766,7 @@ namespace ts {
return generateName(node);
}
else if (isIdentifier(node) && (nodeIsSynthesized(node) || !node.parent)) {
return unescapeIdentifier(node.text);
return unescapeLeadingUnderscores(node.escapedText);
}
else if (node.kind === SyntaxKind.StringLiteral && (<StringLiteral>node).textSourceNode) {
return getTextOfNode((<StringLiteral>node).textSourceNode, includeTrivia);
@@ -2756,13 +2823,13 @@ namespace ts {
// Auto, Loop, and Unique names are cached based on their unique
// autoGenerateId.
const autoGenerateId = name.autoGenerateId;
return autoGeneratedIdToGeneratedName[autoGenerateId] || (autoGeneratedIdToGeneratedName[autoGenerateId] = unescapeIdentifier(makeName(name)));
return autoGeneratedIdToGeneratedName[autoGenerateId] || (autoGeneratedIdToGeneratedName[autoGenerateId] = makeName(name));
}
}
function generateNameCached(node: Node) {
const nodeId = getNodeId(node);
return nodeIdToGeneratedName[nodeId] || (nodeIdToGeneratedName[nodeId] = unescapeIdentifier(generateNameForNode(node)));
return nodeIdToGeneratedName[nodeId] || (nodeIdToGeneratedName[nodeId] = generateNameForNode(node));
}
/**
@@ -2781,7 +2848,7 @@ namespace ts {
function isUniqueLocalName(name: string, container: Node): boolean {
for (let node = container; isNodeDescendantOf(node, container); node = node.nextContainer) {
if (node.locals) {
const local = node.locals.get(name);
const local = node.locals.get(escapeLeadingUnderscores(name));
// We conservatively include alias symbols to cover cases where they're emitted as locals
if (local && local.flags & (SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias)) {
return false;
@@ -2834,7 +2901,7 @@ namespace ts {
while (true) {
const generatedName = baseName + i;
if (isUniqueName(generatedName)) {
generatedNames.set(generatedName, generatedName);
generatedNames.set(generatedName, true);
return generatedName;
}
i++;
@@ -2855,8 +2922,8 @@ namespace ts {
*/
function generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) {
const expr = getExternalModuleName(node);
const baseName = expr.kind === SyntaxKind.StringLiteral ?
escapeIdentifier(makeIdentifierFromModuleName((<LiteralExpression>expr).text)) : "module";
const baseName = isStringLiteral(expr) ?
makeIdentifierFromModuleName(expr.text) : "module";
return makeUniqueName(baseName);
}
@@ -2919,7 +2986,7 @@ namespace ts {
case GeneratedIdentifierKind.Loop:
return makeTempVariableName(TempFlags._i);
case GeneratedIdentifierKind.Unique:
return makeUniqueName(unescapeIdentifier(name.text));
return makeUniqueName(unescapeLeadingUnderscores(name.escapedText));
}
Debug.fail("Unsupported GeneratedIdentifierKind.");
@@ -3027,6 +3094,9 @@ namespace ts {
NoTrailingNewLine = 1 << 16, // Do not emit a trailing NewLine for a MultiLine list.
NoInterveningComments = 1 << 17, // Do not emit comments between each node
NoSpaceIfEmpty = 1 << 18, // If the literal is empty, do not add spaces between braces.
SingleElement = 1 << 19,
// Precomputed Formats
Modifiers = SingleLine | SpaceBetweenSiblings | NoInterveningComments,
HeritageClauses = SingleLine | SpaceBetweenSiblings,
@@ -3038,7 +3108,7 @@ namespace ts {
IntersectionTypeConstituents = AmpersandDelimited | SpaceBetweenSiblings | SingleLine,
ObjectBindingPatternElements = SingleLine | AllowTrailingComma | SpaceBetweenBraces | CommaDelimited | SpaceBetweenSiblings,
ArrayBindingPatternElements = SingleLine | AllowTrailingComma | CommaDelimited | SpaceBetweenSiblings,
ObjectLiteralExpressionProperties = PreserveLines | CommaDelimited | SpaceBetweenSiblings | SpaceBetweenBraces | Indented | Braces,
ObjectLiteralExpressionProperties = PreserveLines | CommaDelimited | SpaceBetweenSiblings | SpaceBetweenBraces | Indented | Braces | NoSpaceIfEmpty,
ArrayLiteralExpressionElements = PreserveLines | CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | Indented | SquareBrackets,
CommaListElements = CommaDelimited | SpaceBetweenSiblings | SingleLine,
CallExpressionArguments = CommaDelimited | SpaceBetweenSiblings | SingleLine | Parenthesis,
+460 -335
View File
File diff suppressed because it is too large Load Diff
+147 -81
View File
@@ -19,13 +19,26 @@ namespace ts {
push(value: T): void;
}
/**
* Result of trying to resolve a module.
* At least one of `ts` and `js` should be defined, or the whole thing should be `undefined`.
*/
function withPackageId(packageId: PackageId | undefined, r: PathAndExtension | undefined): Resolved {
return r && { path: r.path, extension: r.ext, packageId };
}
function noPackageId(r: PathAndExtension | undefined): Resolved {
return withPackageId(/*packageId*/ undefined, r);
}
/** Result of trying to resolve a module. */
interface Resolved {
path: string;
extension: Extension;
packageId: PackageId | undefined;
}
/** Result of trying to resolve a module at a file. Needs to have 'packageId' added later. */
interface PathAndExtension {
path: string;
// (Use a different name than `extension` to make sure Resolved isn't assignable to PathAndExtension.)
ext: Extension;
}
/**
@@ -38,35 +51,42 @@ namespace ts {
DtsOnly /** Only '.d.ts' */
}
interface PathAndPackageId {
readonly fileName: string;
readonly packageId: PackageId;
}
/** Used with `Extensions.DtsOnly` to extract the path from TypeScript results. */
function resolvedTypeScriptOnly(resolved: Resolved | undefined): string | undefined {
function resolvedTypeScriptOnly(resolved: Resolved | undefined): PathAndPackageId | undefined {
if (!resolved) {
return undefined;
}
Debug.assert(extensionIsTypeScript(resolved.extension));
return resolved.path;
return { fileName: resolved.path, packageId: resolved.packageId };
}
function createResolvedModuleWithFailedLookupLocations(resolved: Resolved | undefined, isExternalLibraryImport: boolean, failedLookupLocations: string[]): ResolvedModuleWithFailedLookupLocations {
return {
resolvedModule: resolved && { resolvedFileName: resolved.path, extension: resolved.extension, isExternalLibraryImport },
resolvedModule: resolved && { resolvedFileName: resolved.path, extension: resolved.extension, isExternalLibraryImport, packageId: resolved.packageId },
failedLookupLocations
};
}
export function moduleHasNonRelativeName(moduleName: string): boolean {
return !(isRootedDiskPath(moduleName) || isExternalModuleNameRelative(moduleName));
}
interface ModuleResolutionState {
host: ModuleResolutionHost;
compilerOptions: CompilerOptions;
traceEnabled: boolean;
}
interface PackageJson {
name?: string;
version?: string;
typings?: string;
types?: string;
main?: string;
}
/** Reads from "main" or "types"/"typings" depending on `extensions`. */
function tryReadPackageJsonFields(readTypes: boolean, packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string | undefined {
const jsonContent = readJson(packageJsonPath, state.host);
function tryReadPackageJsonFields(readTypes: boolean, jsonContent: PackageJson, baseDirectory: string, state: ModuleResolutionState): string | undefined {
return readTypes ? tryReadFromField("typings") || tryReadFromField("types") : tryReadFromField("main");
function tryReadFromField(fieldName: "typings" | "types" | "main"): string | undefined {
@@ -93,7 +113,7 @@ namespace ts {
}
}
function readJson(path: string, host: ModuleResolutionHost): { typings?: string, types?: string, main?: string } {
function readJson(path: string, host: ModuleResolutionHost): PackageJson {
try {
const jsonText = host.readFile(path);
return jsonText ? JSON.parse(jsonText) : {};
@@ -151,11 +171,7 @@ namespace ts {
*/
export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string, containingFile: string | undefined, options: CompilerOptions, host: ModuleResolutionHost): ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
const traceEnabled = isTraceEnabled(options, host);
const moduleResolutionState: ModuleResolutionState = {
compilerOptions: options,
host: host,
traceEnabled
};
const moduleResolutionState: ModuleResolutionState = { compilerOptions: options, host, traceEnabled };
const typeRoots = getEffectiveTypeRoots(options, host);
if (traceEnabled) {
@@ -188,16 +204,19 @@ namespace ts {
let resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined;
if (resolved) {
resolved = realpath(resolved, host, traceEnabled);
if (traceEnabled) {
trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, resolved, primary);
if (!options.preserveSymlinks) {
resolved = { ...resolved, fileName: realPath(resolved.fileName, host, traceEnabled) };
}
resolvedTypeReferenceDirective = { primary, resolvedFileName: resolved };
if (traceEnabled) {
trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, resolved.fileName, primary);
}
resolvedTypeReferenceDirective = { primary, resolvedFileName: resolved.fileName, packageId: resolved.packageId };
}
return { resolvedTypeReferenceDirective, failedLookupLocations };
function primaryLookup(): string | undefined {
function primaryLookup(): PathAndPackageId | undefined {
// Check primary library paths
if (typeRoots && typeRoots.length) {
if (traceEnabled) {
@@ -222,8 +241,8 @@ namespace ts {
}
}
function secondaryLookup(): string | undefined {
let resolvedFile: string;
function secondaryLookup(): PathAndPackageId | undefined {
let resolvedFile: PathAndPackageId;
const initialLocationForSecondaryLookup = containingFile && getDirectoryPath(containingFile);
if (initialLocationForSecondaryLookup !== undefined) {
@@ -270,6 +289,8 @@ namespace ts {
for (const typeDirectivePath of host.getDirectories(root)) {
const normalized = normalizePath(typeDirectivePath);
const packageJsonPath = pathToPackageJson(combinePaths(root, normalized));
// `types-publisher` sometimes creates packages with `"typings": null` for packages that don't provide their own types.
// See `createNotNeededPackageJSON` in the types-publisher` repo.
// tslint:disable-next-line:no-null-keyword
const isNotNeededPackage = host.fileExists(packageJsonPath) && readJson(packageJsonPath, host).typings === null;
if (!isNotNeededPackage) {
@@ -306,7 +327,7 @@ namespace ts {
}
export function createModuleResolutionCache(currentDirectory: string, getCanonicalFileName: (s: string) => string): ModuleResolutionCache {
const directoryToModuleNameMap = createFileMap<Map<ResolvedModuleWithFailedLookupLocations>>();
const directoryToModuleNameMap = createMap<Map<ResolvedModuleWithFailedLookupLocations>>();
const moduleNameToDirectoryMap = createMap<PerModuleNameCache>();
return { getOrCreateCacheForDirectory, getOrCreateCacheForModuleName };
@@ -322,7 +343,7 @@ namespace ts {
}
function getOrCreateCacheForModuleName(nonRelativeModuleName: string) {
if (!moduleHasNonRelativeName(nonRelativeModuleName)) {
if (isExternalModuleNameRelative(nonRelativeModuleName)) {
return undefined;
}
let perModuleNameCache = moduleNameToDirectoryMap.get(nonRelativeModuleName);
@@ -334,7 +355,7 @@ namespace ts {
}
function createPerModuleNameCache(): PerModuleNameCache {
const directoryPathMap = createFileMap<ResolvedModuleWithFailedLookupLocations>();
const directoryPathMap = createMap<ResolvedModuleWithFailedLookupLocations>();
return { get, set };
@@ -356,7 +377,7 @@ namespace ts {
function set(directory: string, result: ResolvedModuleWithFailedLookupLocations): void {
const path = toPath(directory, currentDirectory, getCanonicalFileName);
// if entry is already in cache do nothing
if (directoryPathMap.contains(path)) {
if (directoryPathMap.has(path)) {
return;
}
directoryPathMap.set(path, result);
@@ -370,7 +391,7 @@ namespace ts {
let current = path;
while (true) {
const parent = getDirectoryPath(current);
if (parent === current || directoryPathMap.contains(parent)) {
if (parent === current || directoryPathMap.has(parent)) {
break;
}
directoryPathMap.set(parent, result);
@@ -539,7 +560,7 @@ namespace ts {
function tryLoadModuleUsingOptionalResolutionSettings(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
if (moduleHasNonRelativeName(moduleName)) {
if (!isExternalModuleNameRelative(moduleName)) {
return tryLoadModuleUsingBaseUrl(extensions, moduleName, loader, failedLookupLocations, state);
}
else {
@@ -658,7 +679,7 @@ namespace ts {
if (extension !== undefined) {
const path = tryFile(candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state);
if (path !== undefined) {
return { path, extension };
return noPackageId({ path, ext: extension });
}
}
@@ -690,7 +711,7 @@ namespace ts {
const { resolvedModule, failedLookupLocations } =
nodeModuleNameResolverWorker(moduleName, initialDir, { moduleResolution: ts.ModuleResolutionKind.NodeJs, allowJs: true }, host, /*cache*/ undefined, /*jsOnly*/ true);
if (!resolvedModule) {
throw new Error(`Could not resolve JS module ${moduleName} starting at ${initialDir}. Looked in: ${failedLookupLocations.join(", ")}`);
throw new Error(`Could not resolve JS module '${moduleName}' starting at '${initialDir}'. Looked in: ${failedLookupLocations.join(", ")}`);
}
return resolvedModule.resolvedFileName;
}
@@ -715,23 +736,30 @@ namespace ts {
return toSearchResult({ resolved, isExternalLibraryImport: false });
}
if (moduleHasNonRelativeName(moduleName)) {
if (!isExternalModuleNameRelative(moduleName)) {
if (traceEnabled) {
trace(host, Diagnostics.Loading_module_0_from_node_modules_folder_target_file_type_1, moduleName, Extensions[extensions]);
}
const resolved = loadModuleFromNodeModules(extensions, moduleName, containingDirectory, failedLookupLocations, state, cache);
if (!resolved) return undefined;
let resolvedValue = resolved.value;
if (!compilerOptions.preserveSymlinks) {
resolvedValue = resolvedValue && { ...resolved.value, path: realPath(resolved.value.path, host, traceEnabled), extension: resolved.value.extension };
}
// For node_modules lookups, get the real path so that multiple accesses to an `npm link`-ed module do not create duplicate files.
return resolved && { value: resolved.value && { resolved: { path: realpath(resolved.value.path, host, traceEnabled), extension: resolved.value.extension }, isExternalLibraryImport: true } };
return { value: resolvedValue && { resolved: resolvedValue, isExternalLibraryImport: true } };
}
else {
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
const { path: candidate, parts } = normalizePathAndParts(combinePaths(containingDirectory, moduleName));
const resolved = nodeLoadModuleByRelativeName(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state, /*considerPackageJson*/ true);
return resolved && toSearchResult({ resolved, isExternalLibraryImport: false });
// Treat explicit "node_modules" import as an external library import.
return resolved && toSearchResult({ resolved, isExternalLibraryImport: contains(parts, "node_modules") });
}
}
}
function realpath(path: string, host: ModuleResolutionHost, traceEnabled: boolean): string {
function realPath(path: string, host: ModuleResolutionHost, traceEnabled: boolean): string {
if (!host.realpath) {
return path;
}
@@ -759,7 +787,7 @@ namespace ts {
}
const resolvedFromFile = loadModuleFromFile(extensions, candidate, failedLookupLocations, onlyRecordFailures, state);
if (resolvedFromFile) {
return resolvedFromFile;
return noPackageId(resolvedFromFile);
}
}
if (!onlyRecordFailures) {
@@ -780,11 +808,15 @@ namespace ts {
return !host.directoryExists || host.directoryExists(directoryName);
}
function loadModuleFromFileNoPackageId(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved {
return noPackageId(loadModuleFromFile(extensions, candidate, failedLookupLocations, onlyRecordFailures, state));
}
/**
* @param {boolean} onlyRecordFailures - if true then function won't try to actually load files but instead record all attempts as failures. This flag is necessary
* in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations.
*/
function loadModuleFromFile(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
function loadModuleFromFile(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
// First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts"
const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, failedLookupLocations, onlyRecordFailures, state);
if (resolvedByAddingExtension) {
@@ -804,7 +836,7 @@ namespace ts {
}
/** Try to return an existing file that adds one of the `extensions` to `candidate`. */
function tryAddingExtensions(candidate: string, extensions: Extensions, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
function tryAddingExtensions(candidate: string, extensions: Extensions, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
if (!onlyRecordFailures) {
// check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing
const directory = getDirectoryPath(candidate);
@@ -815,16 +847,16 @@ namespace ts {
switch (extensions) {
case Extensions.DtsOnly:
return tryExtension(".d.ts", Extension.Dts);
return tryExtension(Extension.Dts);
case Extensions.TypeScript:
return tryExtension(".ts", Extension.Ts) || tryExtension(".tsx", Extension.Tsx) || tryExtension(".d.ts", Extension.Dts);
return tryExtension(Extension.Ts) || tryExtension(Extension.Tsx) || tryExtension(Extension.Dts);
case Extensions.JavaScript:
return tryExtension(".js", Extension.Js) || tryExtension(".jsx", Extension.Jsx);
return tryExtension(Extension.Js) || tryExtension(Extension.Jsx);
}
function tryExtension(ext: string, extension: Extension): Resolved | undefined {
function tryExtension(ext: Extension): PathAndExtension | undefined {
const path = tryFile(candidate + ext, failedLookupLocations, onlyRecordFailures, state);
return path && { path, extension };
return path && { path, ext };
}
}
@@ -847,35 +879,53 @@ namespace ts {
return undefined;
}
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true): Resolved | undefined {
const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host);
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true) {
const { packageJsonContent, packageId } = considerPackageJson
? getPackageJsonInfo(candidate, "", failedLookupLocations, onlyRecordFailures, state)
: { packageJsonContent: undefined, packageId: undefined };
return withPackageId(packageId, loadNodeModuleFromDirectoryWorker(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, packageJsonContent));
}
if (considerPackageJson) {
const packageJsonPath = pathToPackageJson(candidate);
if (directoryExists && state.host.fileExists(packageJsonPath)) {
const fromPackageJson = loadModuleFromPackageJson(packageJsonPath, extensions, candidate, failedLookupLocations, state);
if (fromPackageJson) {
return fromPackageJson;
}
}
else {
if (directoryExists && state.traceEnabled) {
trace(state.host, Diagnostics.File_0_does_not_exist, packageJsonPath);
}
// record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
failedLookupLocations.push(packageJsonPath);
}
function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, packageJsonContent: PackageJson | undefined): PathAndExtension | undefined {
const fromPackageJson = packageJsonContent && loadModuleFromPackageJson(packageJsonContent, extensions, candidate, failedLookupLocations, state);
if (fromPackageJson) {
return fromPackageJson;
}
const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host);
return loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state);
}
function loadModuleFromPackageJson(packageJsonPath: string, extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Found_package_json_at_0, packageJsonPath);
function getPackageJsonInfo(
nodeModuleDirectory: string,
subModuleName: string,
failedLookupLocations: Push<string>,
onlyRecordFailures: boolean,
{ host, traceEnabled }: ModuleResolutionState,
): { packageJsonContent: PackageJson | undefined, packageId: PackageId | undefined } {
const directoryExists = !onlyRecordFailures && directoryProbablyExists(nodeModuleDirectory, host);
const packageJsonPath = pathToPackageJson(nodeModuleDirectory);
if (directoryExists && host.fileExists(packageJsonPath)) {
if (traceEnabled) {
trace(host, Diagnostics.Found_package_json_at_0, packageJsonPath);
}
const packageJsonContent = readJson(packageJsonPath, host);
const packageId: PackageId = typeof packageJsonContent.name === "string" && typeof packageJsonContent.version === "string"
? { name: packageJsonContent.name, subModuleName, version: packageJsonContent.version }
: undefined;
return { packageJsonContent, packageId };
}
else {
if (directoryExists && traceEnabled) {
trace(host, Diagnostics.File_0_does_not_exist, packageJsonPath);
}
// record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
failedLookupLocations.push(packageJsonPath);
return { packageJsonContent: undefined, packageId: undefined };
}
}
const file = tryReadPackageJsonFields(extensions !== Extensions.JavaScript, packageJsonPath, candidate, state);
function loadModuleFromPackageJson(jsonContent: PackageJson, extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): PathAndExtension | undefined {
const file = tryReadPackageJsonFields(extensions !== Extensions.JavaScript, jsonContent, candidate, state);
if (!file) {
return undefined;
}
@@ -895,13 +945,18 @@ namespace ts {
// Even if extensions is DtsOnly, we can still look up a .ts file as a result of package.json "types"
const nextExtensions = extensions === Extensions.DtsOnly ? Extensions.TypeScript : extensions;
// Don't do package.json lookup recursively, because Node.js' package lookup doesn't.
return nodeLoadModuleByRelativeName(nextExtensions, file, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/ false);
const result = nodeLoadModuleByRelativeName(nextExtensions, file, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/ false);
if (result) {
// It won't have a `packageId` set, because we disabled `considerPackageJson`.
Debug.assert(result.packageId === undefined);
return { path: result.path, ext: result.extension };
}
}
/** Resolve from an arbitrarily specified file. Return `undefined` if it has an unsupported extension. */
function resolvedIfExtensionMatches(extensions: Extensions, path: string): Resolved | undefined {
const extension = tryGetExtensionFromPath(path);
return extension !== undefined && extensionIsOk(extensions, extension) ? { path, extension } : undefined;
function resolvedIfExtensionMatches(extensions: Extensions, path: string): PathAndExtension | undefined {
const ext = tryGetExtensionFromPath(path);
return ext !== undefined && extensionIsOk(extensions, ext) ? { path, ext } : undefined;
}
/** True if `extension` is one of the supported `extensions`. */
@@ -921,10 +976,21 @@ namespace ts {
}
function loadModuleFromNodeModulesFolder(extensions: Extensions, moduleName: string, nodeModulesFolder: string, nodeModulesFolderExists: boolean, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
const { packageName, rest } = getPackageName(moduleName);
const packageRootPath = combinePaths(nodeModulesFolder, packageName);
const { packageJsonContent, packageId } = getPackageJsonInfo(packageRootPath, rest, failedLookupLocations, !nodeModulesFolderExists, state);
const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
const pathAndExtension = loadModuleFromFile(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) ||
loadNodeModuleFromDirectoryWorker(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state, packageJsonContent);
return withPackageId(packageId, pathAndExtension);
}
return loadModuleFromFile(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) ||
loadNodeModuleFromDirectory(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state);
function getPackageName(moduleName: string): { packageName: string, rest: string } {
let idx = moduleName.indexOf(directorySeparator);
if (moduleName[0] === "@") {
idx = moduleName.indexOf(directorySeparator, idx + 1);
}
return idx === -1 ? { packageName: moduleName, rest: "" } : { packageName: moduleName.slice(0, idx), rest: moduleName.slice(idx + 1) };
}
function loadModuleFromNodeModules(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, cache: NonRelativeModuleNameResolutionCache): SearchResult<Resolved> {
@@ -995,7 +1061,7 @@ namespace ts {
export function getPackageNameFromAtTypesDirectory(mangledName: string): string {
const withoutAtTypePrefix = removePrefix(mangledName, "@types/");
if (withoutAtTypePrefix !== mangledName) {
return withoutAtTypePrefix.indexOf("__") !== -1 ?
return withoutAtTypePrefix.indexOf(mangledScopedPackageSeparator) !== -1 ?
"@" + withoutAtTypePrefix.replace(mangledScopedPackageSeparator, ts.directorySeparator) :
withoutAtTypePrefix;
}
@@ -1008,7 +1074,7 @@ namespace ts {
if (traceEnabled) {
trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache, moduleName);
}
return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, extension: result.resolvedModule.extension } };
return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId } };
}
}
@@ -1022,13 +1088,13 @@ namespace ts {
return createResolvedModuleWithFailedLookupLocations(resolved && resolved.value, /*isExternalLibraryImport*/ false, failedLookupLocations);
function tryResolve(extensions: Extensions): SearchResult<Resolved> {
const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFile, failedLookupLocations, state);
const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, failedLookupLocations, state);
if (resolvedUsingSettings) {
return { value: resolvedUsingSettings };
}
const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName);
if (moduleHasNonRelativeName(moduleName)) {
if (!isExternalModuleNameRelative(moduleName)) {
// Climb up parent directories looking for a module.
const resolved = forEachAncestorDirectory(containingDirectory, directory => {
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, directory, traceEnabled, host);
@@ -1036,7 +1102,7 @@ namespace ts {
return resolutionFromCache;
}
const searchName = normalizePath(combinePaths(directory, moduleName));
return toSearchResult(loadModuleFromFile(extensions, searchName, failedLookupLocations, /*onlyRecordFailures*/ false, state));
return toSearchResult(loadModuleFromFileNoPackageId(extensions, searchName, failedLookupLocations, /*onlyRecordFailures*/ false, state));
});
if (resolved) {
return resolved;
@@ -1048,7 +1114,7 @@ namespace ts {
}
else {
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
return toSearchResult(loadModuleFromFile(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state));
return toSearchResult(loadModuleFromFileNoPackageId(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state));
}
}
}
+674 -780
View File
File diff suppressed because it is too large Load Diff
+386 -136
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+3 -3
View File
@@ -145,7 +145,7 @@ namespace ts {
// Initialize source map data
sourceMapData = {
sourceMapFilePath: sourceMapFilePath,
sourceMapFilePath,
jsSourceMappingURL: !compilerOptions.inlineSourceMap ? getBaseFileName(normalizeSlashes(sourceMapFilePath)) : undefined,
sourceMapFile: getBaseFileName(normalizeSlashes(filePath)),
sourceMapSourceRoot: compilerOptions.sourceRoot || "",
@@ -292,8 +292,8 @@ namespace ts {
// New span
lastRecordedSourceMapSpan = {
emittedLine: emittedLine,
emittedColumn: emittedColumn,
emittedLine,
emittedColumn,
sourceLine: sourceLinePos.line,
sourceColumn: sourceLinePos.character,
sourceIndex: sourceMapSourceIndex
+191
View File
@@ -0,0 +1,191 @@
/** @internal */
namespace ts {
export function createGetSymbolWalker(
getRestTypeOfSignature: (sig: Signature) => Type,
getReturnTypeOfSignature: (sig: Signature) => Type,
getBaseTypes: (type: Type) => Type[],
resolveStructuredTypeMembers: (type: ObjectType) => ResolvedType,
getTypeOfSymbol: (sym: Symbol) => Type,
getResolvedSymbol: (node: Node) => Symbol,
getIndexTypeOfStructuredType: (type: Type, kind: IndexKind) => Type,
getConstraintFromTypeParameter: (typeParameter: TypeParameter) => Type,
getFirstIdentifier: (node: EntityNameOrEntityNameExpression) => Identifier) {
return getSymbolWalker;
function getSymbolWalker(accept: (symbol: Symbol) => boolean = () => true): SymbolWalker {
const visitedTypes = createMap<Type>(); // Key is id as string
const visitedSymbols = createMap<Symbol>(); // Key is id as string
return {
walkType: type => {
visitedTypes.clear();
visitedSymbols.clear();
visitType(type);
return { visitedTypes: arrayFrom(visitedTypes.values()), visitedSymbols: arrayFrom(visitedSymbols.values()) };
},
walkSymbol: symbol => {
visitedTypes.clear();
visitedSymbols.clear();
visitSymbol(symbol);
return { visitedTypes: arrayFrom(visitedTypes.values()), visitedSymbols: arrayFrom(visitedSymbols.values()) };
},
};
function visitType(type: Type): void {
if (!type) {
return;
}
const typeIdString = type.id.toString();
if (visitedTypes.has(typeIdString)) {
return;
}
visitedTypes.set(typeIdString, type);
// Reuse visitSymbol to visit the type's symbol,
// but be sure to bail on recuring into the type if accept declines the symbol.
const shouldBail = visitSymbol(type.symbol);
if (shouldBail) return;
// Visit the type's related types, if any
if (type.flags & TypeFlags.Object) {
const objectType = type as ObjectType;
const objectFlags = objectType.objectFlags;
if (objectFlags & ObjectFlags.Reference) {
visitTypeReference(type as TypeReference);
}
if (objectFlags & ObjectFlags.Mapped) {
visitMappedType(type as MappedType);
}
if (objectFlags & (ObjectFlags.Class | ObjectFlags.Interface)) {
visitInterfaceType(type as InterfaceType);
}
if (objectFlags & (ObjectFlags.Tuple | ObjectFlags.Anonymous)) {
visitObjectType(objectType);
}
}
if (type.flags & TypeFlags.TypeParameter) {
visitTypeParameter(type as TypeParameter);
}
if (type.flags & TypeFlags.UnionOrIntersection) {
visitUnionOrIntersectionType(type as UnionOrIntersectionType);
}
if (type.flags & TypeFlags.Index) {
visitIndexType(type as IndexType);
}
if (type.flags & TypeFlags.IndexedAccess) {
visitIndexedAccessType(type as IndexedAccessType);
}
}
function visitTypeList(types: Type[]): void {
if (!types) {
return;
}
for (let i = 0; i < types.length; i++) {
visitType(types[i]);
}
}
function visitTypeReference(type: TypeReference): void {
visitType(type.target);
visitTypeList(type.typeArguments);
}
function visitTypeParameter(type: TypeParameter): void {
visitType(getConstraintFromTypeParameter(type));
}
function visitUnionOrIntersectionType(type: UnionOrIntersectionType): void {
visitTypeList(type.types);
}
function visitIndexType(type: IndexType): void {
visitType(type.type);
}
function visitIndexedAccessType(type: IndexedAccessType): void {
visitType(type.objectType);
visitType(type.indexType);
visitType(type.constraint);
}
function visitMappedType(type: MappedType): void {
visitType(type.typeParameter);
visitType(type.constraintType);
visitType(type.templateType);
visitType(type.modifiersType);
}
function visitSignature(signature: Signature): void {
if (signature.typePredicate) {
visitType(signature.typePredicate.type);
}
visitTypeList(signature.typeParameters);
for (const parameter of signature.parameters){
visitSymbol(parameter);
}
visitType(getRestTypeOfSignature(signature));
visitType(getReturnTypeOfSignature(signature));
}
function visitInterfaceType(interfaceT: InterfaceType): void {
visitObjectType(interfaceT);
visitTypeList(interfaceT.typeParameters);
visitTypeList(getBaseTypes(interfaceT));
visitType(interfaceT.thisType);
}
function visitObjectType(type: ObjectType): void {
const stringIndexType = getIndexTypeOfStructuredType(type, IndexKind.String);
visitType(stringIndexType);
const numberIndexType = getIndexTypeOfStructuredType(type, IndexKind.Number);
visitType(numberIndexType);
// The two checks above *should* have already resolved the type (if needed), so this should be cached
const resolved = resolveStructuredTypeMembers(type);
for (const signature of resolved.callSignatures) {
visitSignature(signature);
}
for (const signature of resolved.constructSignatures) {
visitSignature(signature);
}
for (const p of resolved.properties) {
visitSymbol(p);
}
}
function visitSymbol(symbol: Symbol): boolean {
if (!symbol) {
return;
}
const symbolIdString = getSymbolId(symbol).toString();
if (visitedSymbols.has(symbolIdString)) {
return;
}
visitedSymbols.set(symbolIdString, symbol);
if (!accept(symbol)) {
return true;
}
const t = getTypeOfSymbol(symbol);
visitType(t); // Should handle members on classes and such
if (symbol.flags & SymbolFlags.HasExports) {
symbol.exports.forEach(visitSymbol);
}
forEach(symbol.declarations, d => {
// Type queries are too far resolved when we just visit the symbol's type
// (their type resolved directly to the member deeply referenced)
// So to get the intervening symbols, we need to check if there's a type
// query node on any of the symbol's declarations and get symbols there
if ((d as any).type && (d as any).type.kind === SyntaxKind.TypeQuery) {
const query = (d as any).type as TypeQueryNode;
const entity = getResolvedSymbol(getFirstIdentifier(query.exprName));
visitSymbol(entity);
}
});
}
}
}
}
+54 -20
View File
@@ -4,7 +4,25 @@ declare function setTimeout(handler: (...args: any[]) => void, timeout: number):
declare function clearTimeout(handle: any): void;
namespace ts {
export type FileWatcherCallback = (fileName: string, removed?: boolean) => void;
/**
* Set a high stack trace limit to provide more information in case of an error.
* Called for command-line and server use cases.
* Not called if TypeScript is used as a library.
*/
/* @internal */
export function setStackTraceLimit() {
if ((Error as any).stackTraceLimit < 100) { // Also tests that we won't set the property if it doesn't exist.
(Error as any).stackTraceLimit = 100;
}
}
export enum FileWatcherEventKind {
Created,
Changed,
Deleted
}
export type FileWatcherCallback = (fileName: string, eventKind: FileWatcherEventKind) => void;
export type DirectoryWatcherCallback = (fileName: string) => void;
export interface WatchedFile {
fileName: string;
@@ -17,7 +35,7 @@ namespace ts {
newLine: string;
useCaseSensitiveFileNames: boolean;
write(s: string): void;
readFile(path: string, encoding?: string): string;
readFile(path: string, encoding?: string): string | undefined;
getFileSize?(path: string): number;
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
/**
@@ -33,7 +51,7 @@ namespace ts {
getExecutingFilePath(): string;
getCurrentDirectory(): string;
getDirectories(path: string): string[];
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[];
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
getModifiedTime?(path: string): Date;
/**
* This should be cryptographically secure.
@@ -91,10 +109,10 @@ namespace ts {
directoryExists(path: string): boolean;
createDirectory(path: string): void;
resolvePath(path: string): string;
readFile(path: string): string;
readFile(path: string): string | undefined;
writeFile(path: string, contents: string): void;
getDirectories(path: string): string[];
readDirectory(path: string, extensions?: string[], basePaths?: string[], excludeEx?: string, includeFileEx?: string, includeDirEx?: string): string[];
readDirectory(path: string, extensions?: ReadonlyArray<string>, basePaths?: ReadonlyArray<string>, excludeEx?: string, includeFileEx?: string, includeDirEx?: string): string[];
watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
realpath(path: string): string;
@@ -135,7 +153,7 @@ namespace ts {
return;
}
watcher = _fs.watch(
dirPath,
dirPath || ".",
{ persistent: true },
(eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath)
);
@@ -174,7 +192,7 @@ namespace ts {
const callbacks = fileWatcherCallbacks.get(fileName);
if (callbacks) {
for (const fileCallback of callbacks) {
fileCallback(fileName);
fileCallback(fileName, FileWatcherEventKind.Changed);
}
}
}
@@ -190,15 +208,22 @@ namespace ts {
if (platform === "win32" || platform === "win64") {
return false;
}
// convert current file name to upper case / lower case and check if file exists
// (guards against cases when name is already all uppercase or lowercase)
return !fileExists(__filename.toUpperCase()) || !fileExists(__filename.toLowerCase());
// If this file exists under a different case, we must be case-insensitve.
return !fileExists(swapCase(__filename));
}
/** Convert all lowercase chars to uppercase, and vice-versa */
function swapCase(s: string): string {
return s.replace(/\w/g, (ch) => {
const up = ch.toUpperCase();
return ch === up ? ch.toLowerCase() : up;
});
}
const platform: string = _os.platform();
const useCaseSensitiveFileNames = isFileSystemCaseSensitive();
function readFile(fileName: string, _encoding?: string): string {
function readFile(fileName: string, _encoding?: string): string | undefined {
if (!fileExists(fileName)) {
return undefined;
}
@@ -281,8 +306,8 @@ namespace ts {
}
}
function readDirectory(path: string, extensions?: string[], excludes?: string[], includes?: string[]): string[] {
return matchFiles(path, extensions, excludes, includes, useCaseSensitiveFileNames, process.cwd(), getAccessibleFileSystemEntries);
function readDirectory(path: string, extensions?: ReadonlyArray<string>, excludes?: ReadonlyArray<string>, includes?: ReadonlyArray<string>, depth?: number): string[] {
return matchFiles(path, extensions, excludes, includes, useCaseSensitiveFileNames, process.cwd(), depth, getAccessibleFileSystemEntries);
}
const enum FileSystemEntryKind {
@@ -319,7 +344,7 @@ namespace ts {
const nodeSystem: System = {
args: process.argv.slice(2),
newLine: _os.EOL,
useCaseSensitiveFileNames: useCaseSensitiveFileNames,
useCaseSensitiveFileNames,
write(s: string): void {
process.stdout.write(s);
},
@@ -340,11 +365,22 @@ namespace ts {
}
function fileChanged(curr: any, prev: any) {
if (+curr.mtime <= +prev.mtime) {
const isCurrZero = +curr.mtime === 0;
const isPrevZero = +prev.mtime === 0;
const created = !isCurrZero && isPrevZero;
const deleted = isCurrZero && !isPrevZero;
const eventKind = created
? FileWatcherEventKind.Created
: deleted
? FileWatcherEventKind.Deleted
: FileWatcherEventKind.Changed;
if (eventKind === FileWatcherEventKind.Changed && +curr.mtime <= +prev.mtime) {
return;
}
callback(fileName);
callback(fileName, eventKind);
}
},
watchDirectory: (directoryName, callback, recursive) => {
@@ -377,9 +413,7 @@ namespace ts {
}
);
},
resolvePath: function(path: string): string {
return _path.resolve(path);
},
resolvePath: path => _path.resolve(path),
fileExists,
directoryExists,
createDirectory(directoryName: string) {
@@ -475,7 +509,7 @@ namespace ts {
getCurrentDirectory: () => ChakraHost.currentDirectory,
getDirectories: ChakraHost.getDirectories,
getEnvironmentVariable: ChakraHost.getEnvironmentVariable || (() => ""),
readDirectory: (path: string, extensions?: string[], excludes?: string[], includes?: string[]) => {
readDirectory(path, extensions, excludes, includes, _depth) {
const pattern = getFileMatcherPatterns(path, excludes, includes, !!ChakraHost.useCaseSensitiveFileNames, ChakraHost.currentDirectory);
return ChakraHost.readDirectory(path, extensions, pattern.basePaths, pattern.excludePattern, pattern.includeFilePattern, pattern.includeDirectoryPattern);
},
+2 -1
View File
@@ -1,4 +1,5 @@
/// <reference path="visitor.ts" />
/// <reference path="transformers/utilities.ts" />
/// <reference path="transformers/ts.ts" />
/// <reference path="transformers/jsx.ts" />
/// <reference path="transformers/esnext.ts" />
@@ -91,7 +92,7 @@ namespace ts {
* @param transforms An array of `TransformerFactory` callbacks.
* @param allowDtsFiles A value indicating whether to allow the transformation of .d.ts files.
*/
export function transformNodes<T extends Node>(resolver: EmitResolver, host: EmitHost, options: CompilerOptions, nodes: T[], transformers: TransformerFactory<T>[], allowDtsFiles: boolean): TransformationResult<T> {
export function transformNodes<T extends Node>(resolver: EmitResolver, host: EmitHost, options: CompilerOptions, nodes: ReadonlyArray<T>, transformers: ReadonlyArray<TransformerFactory<T>>, allowDtsFiles: boolean): TransformationResult<T> {
const enabledSyntaxKindFeatures = new Array<SyntaxKindFeatureFlags>(SyntaxKind.Count);
let lexicalEnvironmentVariableDeclarations: VariableDeclaration[];
let lexicalEnvironmentFunctionDeclarations: FunctionDeclaration[];
+8 -5
View File
@@ -331,11 +331,14 @@ namespace ts {
location
);
}
else if (numElements !== 1 && (flattenContext.level < FlattenLevel.ObjectRest || numElements === 0)) {
else if (numElements !== 1 && (flattenContext.level < FlattenLevel.ObjectRest || numElements === 0)
|| every(elements, isOmittedExpression)) {
// For anything other than a single-element destructuring we need to generate a temporary
// to ensure value is evaluated exactly once. Additionally, if we have zero elements
// we need to emit *something* to ensure that in case a 'var' keyword was already emitted,
// so in that case, we'll intentionally create that temporary.
// Or all the elements of the binding pattern are omitted expression such as "var [,] = [1,2]",
// then we will create temporary variable.
const reuseIdentifierExpressions = !isDeclarationBindingElement(parent) || numElements !== 0;
value = ensureIdentifier(flattenContext, value, reuseIdentifierExpressions, location);
}
@@ -406,16 +409,16 @@ namespace ts {
*/
function createDestructuringPropertyAccess(flattenContext: FlattenContext, value: Expression, propertyName: PropertyName): LeftHandSideExpression {
if (isComputedPropertyName(propertyName)) {
const argumentExpression = ensureIdentifier(flattenContext, propertyName.expression, /*reuseIdentifierExpressions*/ false, /*location*/ propertyName);
const argumentExpression = ensureIdentifier(flattenContext, visitNode(propertyName.expression, flattenContext.visitor), /*reuseIdentifierExpressions*/ false, /*location*/ propertyName);
return createElementAccess(value, argumentExpression);
}
else if (isStringOrNumericLiteral(propertyName)) {
const argumentExpression = getSynthesizedClone(propertyName);
argumentExpression.text = unescapeIdentifier(argumentExpression.text);
argumentExpression.text = argumentExpression.text;
return createElementAccess(value, argumentExpression);
}
else {
const name = createIdentifier(unescapeIdentifier(propertyName.text));
const name = createIdentifier(unescapeLeadingUnderscores(propertyName.escapedText));
return createPropertyAccess(value, name);
}
}
@@ -492,7 +495,7 @@ namespace ts {
/** Given value: o, propName: p, pattern: { a, b, ...p } from the original statement
* `{ a, b, ...p } = o`, create `p = __rest(o, ["a", "b"]);`
*/
function createRestCall(context: TransformationContext, value: Expression, elements: BindingOrAssignmentElement[], computedTempVariables: Expression[], location: TextRange): Expression {
function createRestCall(context: TransformationContext, value: Expression, elements: ReadonlyArray<BindingOrAssignmentElement>, computedTempVariables: ReadonlyArray<Expression>, location: TextRange): Expression {
context.requestEmitHelper(restHelper);
const propertyNames: Expression[] = [];
let computedTempVariableOffset = 0;
+42 -98
View File
@@ -70,7 +70,7 @@ namespace ts {
* set of labels that occurred inside the converted loop
* used to determine if labeled jump can be emitted as is or it should be dispatched to calling code
*/
labels?: Map<string>;
labels?: Map<boolean>;
/*
* collection of labeled jumps that transfer control outside the converted loop.
* maps store association 'label -> labelMarker' where
@@ -339,64 +339,12 @@ namespace ts {
&& !(<ReturnStatement>node).expression;
}
function isClassLikeVariableStatement(node: Node) {
if (!isVariableStatement(node)) return false;
const variable = singleOrUndefined((<VariableStatement>node).declarationList.declarations);
return variable
&& variable.initializer
&& isIdentifier(variable.name)
&& (isClassLike(variable.initializer)
|| (isAssignmentExpression(variable.initializer)
&& isIdentifier(variable.initializer.left)
&& isClassLike(variable.initializer.right)));
}
function isTypeScriptClassWrapper(node: Node) {
const call = tryCast(node, isCallExpression);
if (!call || isParseTreeNode(call) ||
some(call.typeArguments) ||
some(call.arguments)) {
return false;
}
const func = tryCast(skipOuterExpressions(call.expression), isFunctionExpression);
if (!func || isParseTreeNode(func) ||
some(func.typeParameters) ||
some(func.parameters) ||
func.type ||
!func.body) {
return false;
}
const statements = func.body.statements;
if (statements.length < 2) {
return false;
}
const firstStatement = statements[0];
if (isParseTreeNode(firstStatement) ||
!isClassLike(firstStatement) &&
!isClassLikeVariableStatement(firstStatement)) {
return false;
}
const lastStatement = elementAt(statements, -1);
const returnStatement = tryCast(isVariableStatement(lastStatement) ? elementAt(statements, -2) : lastStatement, isReturnStatement);
if (!returnStatement ||
!returnStatement.expression ||
!isIdentifier(skipOuterExpressions(returnStatement.expression))) {
return false;
}
return true;
}
function shouldVisitNode(node: Node): boolean {
return (node.transformFlags & TransformFlags.ContainsES2015) !== 0
|| convertedLoopState !== undefined
|| (hierarchyFacts & HierarchyFacts.ConstructorWithCapturedSuper && isStatement(node))
|| (hierarchyFacts & HierarchyFacts.ConstructorWithCapturedSuper && (isStatement(node) || (node.kind === SyntaxKind.Block)))
|| (isIterationStatement(node, /*lookInLabeledStatements*/ false) && shouldConvertIterationStatementBody(node))
|| isTypeScriptClassWrapper(node);
|| (getEmitFlags(node) & EmitFlags.TypeScriptClassWrapper) !== 0;
}
function visitor(node: Node): VisitResult<Node> {
@@ -647,7 +595,7 @@ namespace ts {
if (isGeneratedIdentifier(node)) {
return node;
}
if (node.text !== "arguments" || !resolver.isArgumentsLocalBinding(node)) {
if (node.escapedText !== "arguments" || !resolver.isArgumentsLocalBinding(node)) {
return node;
}
return convertedLoopState.argumentsName || (convertedLoopState.argumentsName = createUniqueName("arguments"));
@@ -661,7 +609,7 @@ namespace ts {
// - break/continue is non-labeled and located in non-converted loop/switch statement
const jump = node.kind === SyntaxKind.BreakStatement ? Jump.Break : Jump.Continue;
const canUseBreakOrContinue =
(node.label && convertedLoopState.labels && convertedLoopState.labels.get(node.label.text)) ||
(node.label && convertedLoopState.labels && convertedLoopState.labels.get(unescapeLeadingUnderscores(node.label.escapedText))) ||
(!node.label && (convertedLoopState.allowedNonLabeledJumps & jump));
if (!canUseBreakOrContinue) {
@@ -679,12 +627,12 @@ namespace ts {
}
else {
if (node.kind === SyntaxKind.BreakStatement) {
labelMarker = `break-${node.label.text}`;
setLabeledJump(convertedLoopState, /*isBreak*/ true, node.label.text, labelMarker);
labelMarker = `break-${node.label.escapedText}`;
setLabeledJump(convertedLoopState, /*isBreak*/ true, unescapeLeadingUnderscores(node.label.escapedText), labelMarker);
}
else {
labelMarker = `continue-${node.label.text}`;
setLabeledJump(convertedLoopState, /*isBreak*/ false, node.label.text, labelMarker);
labelMarker = `continue-${node.label.escapedText}`;
setLabeledJump(convertedLoopState, /*isBreak*/ false, unescapeLeadingUnderscores(node.label.escapedText), labelMarker);
}
}
let returnExpression: Expression = createLiteral(labelMarker);
@@ -840,7 +788,7 @@ namespace ts {
outer.end = skipTrivia(currentText, node.pos);
setEmitFlags(outer, EmitFlags.NoComments);
return createParen(
const result = createParen(
createCall(
outer,
/*typeArguments*/ undefined,
@@ -849,6 +797,8 @@ namespace ts {
: []
)
);
addSyntheticLeadingComment(result, SyntaxKind.MultiLineCommentTrivia, "* @class ");
return result;
}
/**
@@ -1963,7 +1913,7 @@ namespace ts {
updated,
setTextRange(
createNodeArray(
prependCaptureNewTargetIfNeeded(updated.statements, node, /*copyOnWrite*/ true)
prependCaptureNewTargetIfNeeded(updated.statements as MutableNodeArray<Statement>, node, /*copyOnWrite*/ true)
),
/*location*/ updated.statements
)
@@ -2105,13 +2055,14 @@ namespace ts {
setCommentRange(declarationList, node);
if (node.transformFlags & TransformFlags.ContainsBindingPattern
&& (isBindingPattern(node.declarations[0].name)
|| isBindingPattern(lastOrUndefined(node.declarations).name))) {
&& (isBindingPattern(node.declarations[0].name) || isBindingPattern(lastOrUndefined(node.declarations).name))) {
// If the first or last declaration is a binding pattern, we need to modify
// the source map range for the declaration list.
const firstDeclaration = firstOrUndefined(declarations);
const lastDeclaration = lastOrUndefined(declarations);
setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end));
if (firstDeclaration) {
const lastDeclaration = lastOrUndefined(declarations);
setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end));
}
}
return declarationList;
@@ -2236,16 +2187,16 @@ namespace ts {
}
function recordLabel(node: LabeledStatement) {
convertedLoopState.labels.set(node.label.text, node.label.text);
convertedLoopState.labels.set(unescapeLeadingUnderscores(node.label.escapedText), true);
}
function resetLabel(node: LabeledStatement) {
convertedLoopState.labels.set(node.label.text, undefined);
convertedLoopState.labels.set(unescapeLeadingUnderscores(node.label.escapedText), false);
}
function visitLabeledStatement(node: LabeledStatement): VisitResult<Statement> {
if (convertedLoopState && !convertedLoopState.labels) {
convertedLoopState.labels = createMap<string>();
convertedLoopState.labels = createMap<boolean>();
}
const statement = unwrapInnermostStatementOfLabel(node, convertedLoopState && recordLabel);
return isIterationStatement(statement, /*lookInLabeledStatements*/ false)
@@ -2491,7 +2442,7 @@ namespace ts {
const catchVariable = getGeneratedNameForNode(errorRecord);
const returnMethod = createTempVariable(/*recordTempVariable*/ undefined);
const values = createValuesHelper(context, expression, node.expression);
const next = createCall(createPropertyAccess(iterator, "next" ), /*typeArguments*/ undefined, []);
const next = createCall(createPropertyAccess(iterator, "next"), /*typeArguments*/ undefined, []);
hoistVariableDeclaration(errorRecord);
hoistVariableDeclaration(returnMethod);
@@ -3053,7 +3004,7 @@ namespace ts {
else {
loopParameters.push(createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name));
if (resolver.getNodeCheckFlags(decl) & NodeCheckFlags.NeedsLoopOutParameter) {
const outParamName = createUniqueName("out_" + unescapeIdentifier(name.text));
const outParamName = createUniqueName("out_" + unescapeLeadingUnderscores(name.escapedText));
loopOutParameters.push({ originalName: name, outParamName });
}
}
@@ -3173,6 +3124,7 @@ namespace ts {
function visitCatchClause(node: CatchClause): CatchClause {
const ancestorFacts = enterSubtree(HierarchyFacts.BlockScopeExcludes, HierarchyFacts.BlockScopeIncludes);
let updated: CatchClause;
Debug.assert(!!node.variableDeclaration, "Catch clause variable should always be present when downleveling ES2015.");
if (isBindingPattern(node.variableDeclaration.name)) {
const temp = createTempVariable(/*recordTempVariable*/ undefined);
const newVariableDeclaration = createVariableDeclaration(temp);
@@ -3199,7 +3151,7 @@ namespace ts {
function addStatementToStartOfBlock(block: Block, statement: Statement): Block {
const transformedStatements = visitNodes(block.statements, visitor, isStatement);
return updateBlock(block, [statement].concat(transformedStatements));
return updateBlock(block, [statement, ...transformedStatements]);
}
/**
@@ -3304,13 +3256,14 @@ namespace ts {
* @param node a CallExpression.
*/
function visitCallExpression(node: CallExpression) {
if (isTypeScriptClassWrapper(node)) {
if (getEmitFlags(node) & EmitFlags.TypeScriptClassWrapper) {
return visitTypeScriptClassWrapper(node);
}
if (node.transformFlags & TransformFlags.ES2015) {
return visitCallExpressionWithPotentialCapturedThisAssignment(node, /*assignToCapturedThis*/ true);
}
return updateCall(
node,
visitNode(node.expression, callExpressionVisitor, isExpression),
@@ -3353,7 +3306,7 @@ namespace ts {
// We skip any outer expressions in a number of places to get to the innermost
// expression, but we will restore them later to preserve comments and source maps.
const body = cast(skipOuterExpressions(node.expression), isFunctionExpression).body;
const body = cast(cast(skipOuterExpressions(node.expression), isArrowFunction).body, isBlock);
// The class statements are the statements generated by visiting the first statement of the
// body (1), while all other statements are added to remainingStatements (2)
@@ -3401,28 +3354,19 @@ namespace ts {
classBodyStart++;
}
// We reuse the comment and source-map positions from the original variable statement
// and class alias, while converting the function declaration for the class constructor
// into an expression.
// The next statement is the function declaration.
statements.push(funcStatements[classBodyStart]);
classBodyStart++;
// Add the class alias following the declaration.
statements.push(
updateVariableStatement(
varStatement,
/*modifiers*/ undefined,
updateVariableDeclarationList(varStatement.declarationList, [
updateVariableDeclaration(variable,
variable.name,
/*type*/ undefined,
updateBinary(aliasAssignment,
aliasAssignment.left,
convertFunctionDeclarationToExpression(
cast(funcStatements[classBodyStart], isFunctionDeclaration)
)
)
)
])
createStatement(
createAssignment(
aliasAssignment.left,
cast(variable.name, isIdentifier)
)
)
);
classBodyStart++;
}
// Find the trailing 'return' statement (4)
@@ -3588,7 +3532,7 @@ namespace ts {
// Map spans of spread expressions into their expressions and spans of other
// expressions into an array literal.
const numElements = elements.length;
const segments = flatten(
const segments = flatten<Expression>(
spanMap(elements, partitionSpread, (partition, visitPartition, _start, end) =>
visitPartition(partition, multiLine, hasTrailingComma && end === numElements)
)
@@ -3600,7 +3544,7 @@ namespace ts {
if (isCallExpression(firstSegment)
&& isIdentifier(firstSegment.expression)
&& (getEmitFlags(firstSegment.expression) & EmitFlags.HelperName)
&& firstSegment.expression.text === "___spread") {
&& firstSegment.expression.escapedText === "___spread") {
return segments[0];
}
}
@@ -3851,7 +3795,7 @@ namespace ts {
}
function visitMetaProperty(node: MetaProperty) {
if (node.keywordToken === SyntaxKind.NewKeyword && node.name.text === "target") {
if (node.keywordToken === SyntaxKind.NewKeyword && node.name.escapedText === "target") {
if (hierarchyFacts & HierarchyFacts.ComputedPropertyName) {
hierarchyFacts |= HierarchyFacts.NewTargetInComputedPropertyName;
}
@@ -4076,7 +4020,7 @@ namespace ts {
}
const expression = (<SpreadElement>callArgument).expression;
return isIdentifier(expression) && expression.text === "arguments";
return isIdentifier(expression) && expression.escapedText === "arguments";
}
}
+3 -9
View File
@@ -21,9 +21,6 @@ namespace ts {
const compilerOptions = context.getCompilerOptions();
const languageVersion = getEmitScriptTarget(compilerOptions);
// These variables contain state that changes as we descend into the tree.
let currentSourceFile: SourceFile;
/**
* Keeps track of whether expression substitution has been enabled for specific edge cases.
* They are persisted between each SourceFile transformation and should not be reset.
@@ -51,12 +48,8 @@ namespace ts {
return node;
}
currentSourceFile = node;
const visited = visitEachChild(node, visitor, context);
addEmitHelpers(visited, context.readEmitHelpers());
currentSourceFile = undefined;
return visited;
}
@@ -197,9 +190,10 @@ namespace ts {
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
node.equalsGreaterThanToken,
getFunctionFlags(node) & FunctionFlags.Async
? transformAsyncFunctionBody(node)
: visitFunctionBody(node.body, visitor, context)
: visitFunctionBody(node.body, visitor, context),
);
}
@@ -369,7 +363,7 @@ namespace ts {
function substitutePropertyAccessExpression(node: PropertyAccessExpression) {
if (node.expression.kind === SyntaxKind.SuperKeyword) {
return createSuperAccessInAsyncMethod(
createLiteral(node.name.text),
createLiteral(unescapeLeadingUnderscores(node.name.escapedText)),
node
);
}
+1 -1
View File
@@ -111,7 +111,7 @@ namespace ts {
* @param name An Identifier
*/
function trySubstituteReservedName(name: Identifier) {
const token = name.originalKeywordKind || (nodeIsSynthesized(name) ? stringToToken(name.text) : undefined);
const token = name.originalKeywordKind || (nodeIsSynthesized(name) ? stringToToken(unescapeLeadingUnderscores(name.escapedText)) : undefined);
if (token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord) {
return setTextRange(createLiteral(name), name);
}
+19 -5
View File
@@ -101,6 +101,8 @@ namespace ts {
return visitExpressionStatement(node as ExpressionStatement);
case SyntaxKind.ParenthesizedExpression:
return visitParenthesizedExpression(node as ParenthesizedExpression, noDestructuringValue);
case SyntaxKind.CatchClause:
return visitCatchClause(node as CatchClause);
default:
return visitEachChild(node, visitor, context);
}
@@ -156,8 +158,8 @@ namespace ts {
return visitEachChild(node, visitor, context);
}
function chunkObjectLiteralElements(elements: ObjectLiteralElement[]): Expression[] {
let chunkObject: (ShorthandPropertyAssignment | PropertyAssignment)[];
function chunkObjectLiteralElements(elements: ReadonlyArray<ObjectLiteralElementLike>): Expression[] {
let chunkObject: ObjectLiteralElementLike[];
const objects: Expression[] = [];
for (const e of elements) {
if (e.kind === SyntaxKind.SpreadAssignment) {
@@ -177,7 +179,7 @@ namespace ts {
chunkObject.push(createPropertyAssignment(p.name, visitNode(p.initializer, visitor, isExpression)));
}
else {
chunkObject.push(e as ShorthandPropertyAssignment);
chunkObject.push(visitNode(e, visitor, isObjectLiteralElementLike));
}
}
}
@@ -212,6 +214,17 @@ namespace ts {
return visitEachChild(node, noDestructuringValue ? visitorNoDestructuringValue : visitor, context);
}
function visitCatchClause(node: CatchClause): CatchClause {
if (!node.variableDeclaration) {
return updateCatchClause(
node,
createVariableDeclaration(createTempVariable(/*recordTempVariable*/ undefined)),
visitNode(node.block, visitor, isBlock)
);
}
return visitEachChild(node, visitor, context);
}
/**
* Visits a BinaryExpression that contains a destructuring assignment.
*
@@ -582,7 +595,8 @@ namespace ts {
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
transformFunctionBody(node)
node.equalsGreaterThanToken,
transformFunctionBody(node),
);
enclosingFunctionFlags = savedEnclosingFunctionFlags;
return updated;
@@ -776,7 +790,7 @@ namespace ts {
function substitutePropertyAccessExpression(node: PropertyAccessExpression) {
if (node.expression.kind === SyntaxKind.SuperKeyword) {
return createSuperAccessInAsyncMethod(
createLiteral(node.name.text),
createLiteral(unescapeLeadingUnderscores(node.name.escapedText)),
node
);
}
+105 -101
View File
@@ -164,12 +164,11 @@ namespace ts {
}
// A generated code block
interface CodeBlock {
kind: CodeBlockKind;
}
type CodeBlock = | ExceptionBlock | LabeledBlock | SwitchBlock | LoopBlock | WithBlock;
// a generated exception block, used for 'try' statements
interface ExceptionBlock extends CodeBlock {
interface ExceptionBlock {
kind: CodeBlockKind.Exception;
state: ExceptionBlockState;
startLabel: Label;
catchVariable?: Identifier;
@@ -179,27 +178,31 @@ namespace ts {
}
// A generated code that tracks the target for 'break' statements in a LabeledStatement.
interface LabeledBlock extends CodeBlock {
interface LabeledBlock {
kind: CodeBlockKind.Labeled;
labelText: string;
isScript: boolean;
breakLabel: Label;
}
// a generated block that tracks the target for 'break' statements in a 'switch' statement
interface SwitchBlock extends CodeBlock {
interface SwitchBlock {
kind: CodeBlockKind.Switch;
isScript: boolean;
breakLabel: Label;
}
// a generated block that tracks the targets for 'break' and 'continue' statements, used for iteration statements
interface LoopBlock extends CodeBlock {
interface LoopBlock {
kind: CodeBlockKind.Loop;
continueLabel: Label;
isScript: boolean;
breakLabel: Label;
}
// a generated block associated with a 'with' statement
interface WithBlock extends CodeBlock {
interface WithBlock {
kind: CodeBlockKind.With;
expression: Identifier;
startLabel: Label;
endLabel: Label;
@@ -241,7 +244,6 @@ namespace ts {
const previousOnSubstituteNode = context.onSubstituteNode;
context.onSubstituteNode = onSubstituteNode;
let currentSourceFile: SourceFile;
let renamedCatchVariables: Map<boolean>;
let renamedCatchVariableDeclarations: Identifier[];
@@ -297,12 +299,9 @@ namespace ts {
return node;
}
currentSourceFile = node;
const visited = visitEachChild(node, visitor, context);
addEmitHelpers(visited, context.readEmitHelpers());
currentSourceFile = undefined;
return visited;
}
@@ -1176,7 +1175,7 @@ namespace ts {
return visitEachChild(node, visitor, context);
}
function transformAndEmitStatements(statements: Statement[], start = 0) {
function transformAndEmitStatements(statements: ReadonlyArray<Statement>, start = 0) {
const numStatements = statements.length;
for (let i = start; i < numStatements; i++) {
transformAndEmitStatement(statements[i]);
@@ -1635,14 +1634,19 @@ namespace ts {
}
function transformAndEmitContinueStatement(node: ContinueStatement): void {
const label = findContinueTarget(node.label ? node.label.text : undefined);
Debug.assert(label > 0, "Expected continue statment to point to a valid Label.");
emitBreak(label, /*location*/ node);
const label = findContinueTarget(node.label ? unescapeLeadingUnderscores(node.label.escapedText) : undefined);
if (label > 0) {
emitBreak(label, /*location*/ node);
}
else {
// invalid continue without a containing loop. Leave the node as is, per #17875.
emitStatement(node);
}
}
function visitContinueStatement(node: ContinueStatement): Statement {
if (inStatementContainingYield) {
const label = findContinueTarget(node.label && node.label.text);
const label = findContinueTarget(node.label && unescapeLeadingUnderscores(node.label.escapedText));
if (label > 0) {
return createInlineBreak(label, /*location*/ node);
}
@@ -1652,14 +1656,19 @@ namespace ts {
}
function transformAndEmitBreakStatement(node: BreakStatement): void {
const label = findBreakTarget(node.label ? node.label.text : undefined);
Debug.assert(label > 0, "Expected break statment to point to a valid Label.");
emitBreak(label, /*location*/ node);
const label = findBreakTarget(node.label ? unescapeLeadingUnderscores(node.label.escapedText) : undefined);
if (label > 0) {
emitBreak(label, /*location*/ node);
}
else {
// invalid break without a containing loop, switch, or labeled statement. Leave the node as is, per #17875.
emitStatement(node);
}
}
function visitBreakStatement(node: BreakStatement): Statement {
if (inStatementContainingYield) {
const label = findBreakTarget(node.label && node.label.text);
const label = findBreakTarget(node.label && unescapeLeadingUnderscores(node.label.escapedText));
if (label > 0) {
return createInlineBreak(label, /*location*/ node);
}
@@ -1838,7 +1847,7 @@ namespace ts {
// /*body*/
// .endlabeled
// .mark endLabel
beginLabeledBlock(node.label.text);
beginLabeledBlock(unescapeLeadingUnderscores(node.label.escapedText));
transformAndEmitEmbeddedStatement(node.statement);
endLabeledBlock();
}
@@ -1849,7 +1858,7 @@ namespace ts {
function visitLabeledStatement(node: LabeledStatement) {
if (inStatementContainingYield) {
beginScriptLabeledBlock(node.label.text);
beginScriptLabeledBlock(unescapeLeadingUnderscores(node.label.escapedText));
}
node = visitEachChild(node, visitor, context);
@@ -1950,7 +1959,7 @@ namespace ts {
}
function substituteExpressionIdentifier(node: Identifier) {
if (!isGeneratedIdentifier(node) && renamedCatchVariables && renamedCatchVariables.has(node.text)) {
if (!isGeneratedIdentifier(node) && renamedCatchVariables && renamedCatchVariables.has(unescapeLeadingUnderscores(node.escapedText))) {
const original = getOriginalNode(node);
if (isIdentifier(original) && original.parent) {
const declaration = resolver.getReferencedValueDeclaration(original);
@@ -2070,7 +2079,7 @@ namespace ts {
const startLabel = defineLabel();
const endLabel = defineLabel();
markLabel(startLabel);
beginBlock(<WithBlock>{
beginBlock({
kind: CodeBlockKind.With,
expression,
startLabel,
@@ -2087,10 +2096,6 @@ namespace ts {
markLabel(block.endLabel);
}
function isWithBlock(block: CodeBlock): block is WithBlock {
return block.kind === CodeBlockKind.With;
}
/**
* Begins a code block for a generated `try` statement.
*/
@@ -2098,7 +2103,7 @@ namespace ts {
const startLabel = defineLabel();
const endLabel = defineLabel();
markLabel(startLabel);
beginBlock(<ExceptionBlock>{
beginBlock({
kind: CodeBlockKind.Exception,
state: ExceptionBlockState.Try,
startLabel,
@@ -2123,7 +2128,7 @@ namespace ts {
hoistVariableDeclaration(variable.name);
}
else {
const text = (<Identifier>variable.name).text;
const text = unescapeLeadingUnderscores((<Identifier>variable.name).escapedText);
name = declareLocal(text);
if (!renamedCatchVariables) {
renamedCatchVariables = createMap<boolean>();
@@ -2188,10 +2193,6 @@ namespace ts {
exception.state = ExceptionBlockState.Done;
}
function isExceptionBlock(block: CodeBlock): block is ExceptionBlock {
return block.kind === CodeBlockKind.Exception;
}
/**
* Begins a code block that supports `break` or `continue` statements that are defined in
* the source tree and not from generated code.
@@ -2199,7 +2200,7 @@ namespace ts {
* @param labelText Names from containing labeled statements.
*/
function beginScriptLoopBlock(): void {
beginBlock(<LoopBlock>{
beginBlock({
kind: CodeBlockKind.Loop,
isScript: true,
breakLabel: -1,
@@ -2217,11 +2218,11 @@ namespace ts {
*/
function beginLoopBlock(continueLabel: Label): Label {
const breakLabel = defineLabel();
beginBlock(<LoopBlock>{
beginBlock({
kind: CodeBlockKind.Loop,
isScript: false,
breakLabel: breakLabel,
continueLabel: continueLabel
breakLabel,
continueLabel,
});
return breakLabel;
}
@@ -2245,7 +2246,7 @@ namespace ts {
*
*/
function beginScriptSwitchBlock(): void {
beginBlock(<SwitchBlock>{
beginBlock({
kind: CodeBlockKind.Switch,
isScript: true,
breakLabel: -1
@@ -2259,10 +2260,10 @@ namespace ts {
*/
function beginSwitchBlock(): Label {
const breakLabel = defineLabel();
beginBlock(<SwitchBlock>{
beginBlock({
kind: CodeBlockKind.Switch,
isScript: false,
breakLabel: breakLabel
breakLabel,
});
return breakLabel;
}
@@ -2280,7 +2281,7 @@ namespace ts {
}
function beginScriptLabeledBlock(labelText: string) {
beginBlock(<LabeledBlock>{
beginBlock({
kind: CodeBlockKind.Labeled,
isScript: true,
labelText,
@@ -2290,7 +2291,7 @@ namespace ts {
function beginLabeledBlock(labelText: string) {
const breakLabel = defineLabel();
beginBlock(<LabeledBlock>{
beginBlock({
kind: CodeBlockKind.Labeled,
isScript: false,
labelText,
@@ -2356,27 +2357,27 @@ namespace ts {
* @param labelText An optional name of a containing labeled statement.
*/
function findBreakTarget(labelText?: string): Label {
Debug.assert(blocks !== undefined);
if (labelText) {
for (let i = blockStack.length - 1; i >= 0; i--) {
const block = blockStack[i];
if (supportsLabeledBreakOrContinue(block) && block.labelText === labelText) {
return block.breakLabel;
if (blockStack) {
if (labelText) {
for (let i = blockStack.length - 1; i >= 0; i--) {
const block = blockStack[i];
if (supportsLabeledBreakOrContinue(block) && block.labelText === labelText) {
return block.breakLabel;
}
else if (supportsUnlabeledBreak(block) && hasImmediateContainingLabeledBlock(labelText, i - 1)) {
return block.breakLabel;
}
}
else if (supportsUnlabeledBreak(block) && hasImmediateContainingLabeledBlock(labelText, i - 1)) {
return block.breakLabel;
}
else {
for (let i = blockStack.length - 1; i >= 0; i--) {
const block = blockStack[i];
if (supportsUnlabeledBreak(block)) {
return block.breakLabel;
}
}
}
}
else {
for (let i = blockStack.length - 1; i >= 0; i--) {
const block = blockStack[i];
if (supportsUnlabeledBreak(block)) {
return block.breakLabel;
}
}
}
return 0;
}
@@ -2386,24 +2387,24 @@ namespace ts {
* @param labelText An optional name of a containing labeled statement.
*/
function findContinueTarget(labelText?: string): Label {
Debug.assert(blocks !== undefined);
if (labelText) {
for (let i = blockStack.length - 1; i >= 0; i--) {
const block = blockStack[i];
if (supportsUnlabeledContinue(block) && hasImmediateContainingLabeledBlock(labelText, i - 1)) {
return block.continueLabel;
if (blockStack) {
if (labelText) {
for (let i = blockStack.length - 1; i >= 0; i--) {
const block = blockStack[i];
if (supportsUnlabeledContinue(block) && hasImmediateContainingLabeledBlock(labelText, i - 1)) {
return block.continueLabel;
}
}
}
else {
for (let i = blockStack.length - 1; i >= 0; i--) {
const block = blockStack[i];
if (supportsUnlabeledContinue(block)) {
return block.continueLabel;
}
}
}
}
else {
for (let i = blockStack.length - 1; i >= 0; i--) {
const block = blockStack[i];
if (supportsUnlabeledContinue(block)) {
return block.continueLabel;
}
}
}
return 0;
}
@@ -2448,7 +2449,7 @@ namespace ts {
* @param location An optional source map location for the statement.
*/
function createInlineBreak(label: Label, location?: TextRange): ReturnStatement {
Debug.assert(label > 0, `Invalid label: ${label}`);
Debug.assertLessThan(0, label, "Invalid label");
return setTextRange(
createReturn(
createArrayLiteral([
@@ -2878,34 +2879,37 @@ namespace ts {
for (; blockIndex < blockActions.length && blockOffsets[blockIndex] <= operationIndex; blockIndex++) {
const block = blocks[blockIndex];
const blockAction = blockActions[blockIndex];
if (isExceptionBlock(block)) {
if (blockAction === BlockAction.Open) {
if (!exceptionBlockStack) {
exceptionBlockStack = [];
}
switch (block.kind) {
case CodeBlockKind.Exception:
if (blockAction === BlockAction.Open) {
if (!exceptionBlockStack) {
exceptionBlockStack = [];
}
if (!statements) {
statements = [];
}
if (!statements) {
statements = [];
}
exceptionBlockStack.push(currentExceptionBlock);
currentExceptionBlock = block;
}
else if (blockAction === BlockAction.Close) {
currentExceptionBlock = exceptionBlockStack.pop();
}
}
else if (isWithBlock(block)) {
if (blockAction === BlockAction.Open) {
if (!withBlockStack) {
withBlockStack = [];
exceptionBlockStack.push(currentExceptionBlock);
currentExceptionBlock = block;
}
else if (blockAction === BlockAction.Close) {
currentExceptionBlock = exceptionBlockStack.pop();
}
break;
case CodeBlockKind.With:
if (blockAction === BlockAction.Open) {
if (!withBlockStack) {
withBlockStack = [];
}
withBlockStack.push(block);
}
else if (blockAction === BlockAction.Close) {
withBlockStack.pop();
}
withBlockStack.push(block);
}
else if (blockAction === BlockAction.Close) {
withBlockStack.pop();
}
break;
// default: do nothing
}
}
}
+7 -7
View File
@@ -77,7 +77,7 @@ namespace ts {
return visitJsxOpeningLikeElement(node, /*children*/ undefined, isChild, /*location*/ node);
}
function visitJsxOpeningLikeElement(node: JsxOpeningLikeElement, children: JsxChild[], isChild: boolean, location: TextRange) {
function visitJsxOpeningLikeElement(node: JsxOpeningLikeElement, children: ReadonlyArray<JsxChild>, isChild: boolean, location: TextRange) {
const tagName = getTagName(node);
let objectProperties: Expression;
const attrs = node.attributes.properties;
@@ -88,7 +88,7 @@ namespace ts {
else {
// Map spans of JsxAttribute nodes into object literals and spans
// of JsxSpreadAttribute nodes into expressions.
const segments = flatten(
const segments = flatten<Expression | ObjectLiteralExpression>(
spanMap(attrs, isJsxSpreadAttribute, (attrs, isSpread) => isSpread
? map(attrs, transformJsxSpreadAttributeToExpression)
: createObjectLiteral(map(attrs, transformJsxAttributeToObjectLiteralElement))
@@ -114,7 +114,7 @@ namespace ts {
compilerOptions.reactNamespace,
tagName,
objectProperties,
filter(map(children, transformJsxChildToExpression), isDefined),
mapDefined(children, transformJsxChildToExpression),
node,
location
);
@@ -252,8 +252,8 @@ namespace ts {
}
else {
const name = (<JsxOpeningLikeElement>node).tagName;
if (isIdentifier(name) && isIntrinsicJsxName(name.text)) {
return createLiteral(name.text);
if (isIdentifier(name) && isIntrinsicJsxName(name.escapedText)) {
return createLiteral(unescapeLeadingUnderscores(name.escapedText));
}
else {
return createExpressionFromEntityName(name);
@@ -268,11 +268,11 @@ namespace ts {
*/
function getAttributeName(node: JsxAttribute): StringLiteral | Identifier {
const name = node.name;
if (/^[A-Za-z_]\w*$/.test(name.text)) {
if (/^[A-Za-z_]\w*$/.test(unescapeLeadingUnderscores(name.escapedText))) {
return name;
}
else {
return createLiteral(name.text);
return createLiteral(unescapeLeadingUnderscores(name.escapedText));
}
}
+29 -23
View File
@@ -200,6 +200,7 @@ namespace ts {
*/
function transformUMDModule(node: SourceFile) {
const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies(node, /*includeNonAmdDependencies*/ false);
const moduleName = tryGetModuleNameFromFile(node, host, compilerOptions);
const umdHeader = createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
@@ -260,6 +261,8 @@ namespace ts {
createIdentifier("define"),
/*typeArguments*/ undefined,
[
// Add the module name (if provided).
...(moduleName ? [moduleName] : []),
createArrayLiteral([
createLiteral("require"),
createLiteral("exports"),
@@ -430,26 +433,29 @@ namespace ts {
*/
function addExportEqualsIfNeeded(statements: Statement[], emitAsReturn: boolean) {
if (currentModuleInfo.exportEquals) {
if (emitAsReturn) {
const statement = createReturn(currentModuleInfo.exportEquals.expression);
setTextRange(statement, currentModuleInfo.exportEquals);
setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoComments);
statements.push(statement);
}
else {
const statement = createStatement(
createAssignment(
createPropertyAccess(
createIdentifier("module"),
"exports"
),
currentModuleInfo.exportEquals.expression
)
);
const expressionResult = visitNode(currentModuleInfo.exportEquals.expression, importCallExpressionVisitor);
if (expressionResult) {
if (emitAsReturn) {
const statement = createReturn(expressionResult);
setTextRange(statement, currentModuleInfo.exportEquals);
setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoComments);
statements.push(statement);
}
else {
const statement = createStatement(
createAssignment(
createPropertyAccess(
createIdentifier("module"),
"exports"
),
expressionResult
)
);
setTextRange(statement, currentModuleInfo.exportEquals);
setEmitFlags(statement, EmitFlags.NoComments);
statements.push(statement);
setTextRange(statement, currentModuleInfo.exportEquals);
setEmitFlags(statement, EmitFlags.NoComments);
statements.push(statement);
}
}
}
}
@@ -497,7 +503,7 @@ namespace ts {
}
}
function importCallExpressionVisitor(node: Node): VisitResult<Node> {
function importCallExpressionVisitor(node: Expression): VisitResult<Expression> {
// This visitor does not need to descend into the tree if there is no dynamic import,
// as export/import statements are only transformed at the top level of a file.
if (!(node.transformFlags & TransformFlags.ContainsDynamicImport)) {
@@ -924,7 +930,7 @@ namespace ts {
getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true),
/*typeParameters*/ undefined,
visitNodes(node.heritageClauses, importCallExpressionVisitor),
node.members
visitNodes(node.members, importCallExpressionVisitor)
),
node
),
@@ -1204,7 +1210,7 @@ namespace ts {
}
if (hasModifier(decl, ModifierFlags.Export)) {
const exportName = hasModifier(decl, ModifierFlags.Default) ? createIdentifier("default") : decl.name;
const exportName = hasModifier(decl, ModifierFlags.Default) ? createIdentifier("default") : getDeclarationName(decl);
statements = appendExportStatement(statements, exportName, getLocalName(decl), /*location*/ decl);
}
@@ -1225,7 +1231,7 @@ namespace ts {
*/
function appendExportsOfDeclaration(statements: Statement[] | undefined, decl: Declaration): Statement[] | undefined {
const name = getDeclarationName(decl);
const exportSpecifiers = currentModuleInfo.exportSpecifiers.get(name.text);
const exportSpecifiers = currentModuleInfo.exportSpecifiers.get(unescapeLeadingUnderscores(name.escapedText));
if (exportSpecifiers) {
for (const exportSpecifier of exportSpecifiers) {
statements = appendExportStatement(statements, exportSpecifier.name, name, /*location*/ exportSpecifier.name);
+10 -9
View File
@@ -324,7 +324,7 @@ namespace ts {
const exportedNames: ObjectLiteralElementLike[] = [];
if (moduleInfo.exportedNames) {
for (const exportedLocalName of moduleInfo.exportedNames) {
if (exportedLocalName.text === "default") {
if (exportedLocalName.escapedText === "default") {
continue;
}
@@ -353,7 +353,7 @@ namespace ts {
// write name of indirectly exported entry, i.e. 'export {x} from ...'
exportedNames.push(
createPropertyAssignment(
createLiteral((element.name || element.propertyName).text),
createLiteral(unescapeLeadingUnderscores((element.name || element.propertyName).escapedText)),
createTrue()
)
);
@@ -504,10 +504,10 @@ namespace ts {
for (const e of (<ExportDeclaration>entry).exportClause.elements) {
properties.push(
createPropertyAssignment(
createLiteral(e.name.text),
createLiteral(unescapeLeadingUnderscores(e.name.escapedText)),
createElementAccess(
parameterName,
createLiteral((e.propertyName || e.name).text)
createLiteral(unescapeLeadingUnderscores((e.propertyName || e.name).escapedText))
)
)
);
@@ -1028,7 +1028,7 @@ namespace ts {
let excludeName: string;
if (exportSelf) {
statements = appendExportStatement(statements, decl.name, getLocalName(decl));
excludeName = decl.name.text;
excludeName = unescapeLeadingUnderscores(decl.name.escapedText);
}
statements = appendExportsOfDeclaration(statements, decl, excludeName);
@@ -1055,7 +1055,7 @@ namespace ts {
if (hasModifier(decl, ModifierFlags.Export)) {
const exportName = hasModifier(decl, ModifierFlags.Default) ? createLiteral("default") : decl.name;
statements = appendExportStatement(statements, exportName, getLocalName(decl));
excludeName = exportName.text;
excludeName = getTextOfIdentifierOrLiteral(exportName);
}
if (decl.name) {
@@ -1080,10 +1080,10 @@ namespace ts {
}
const name = getDeclarationName(decl);
const exportSpecifiers = moduleInfo.exportSpecifiers.get(name.text);
const exportSpecifiers = moduleInfo.exportSpecifiers.get(unescapeLeadingUnderscores(name.escapedText));
if (exportSpecifiers) {
for (const exportSpecifier of exportSpecifiers) {
if (exportSpecifier.name.text !== excludeName) {
if (exportSpecifier.name.escapedText !== excludeName) {
statements = appendExportStatement(statements, exportSpecifier.name, name);
}
}
@@ -1132,7 +1132,8 @@ namespace ts {
*/
function createExportExpression(name: Identifier | StringLiteral, value: Expression) {
const exportName = isIdentifier(name) ? createLiteral(name) : name;
return createCall(exportFunction, /*typeArguments*/ undefined, [exportName, value]);
setEmitFlags(value, getEmitFlags(value) | EmitFlags.NoComments);
return setCommentRange(createCall(exportFunction, /*typeArguments*/ undefined, [exportName, value]), value);
}
//
+75 -45
View File
@@ -65,7 +65,7 @@ namespace ts {
let currentNamespace: ModuleDeclaration;
let currentNamespaceContainerName: Identifier;
let currentScope: SourceFile | Block | ModuleBlock | CaseBlock;
let currentScopeFirstDeclarationsOfName: Map<Node>;
let currentScopeFirstDeclarationsOfName: UnderscoreEscapedMap<Node>;
/**
* Keeps track of whether expression substitution has been enabled for specific edge cases.
@@ -151,7 +151,17 @@ namespace ts {
break;
}
recordEmittedDeclarationInScope(node);
// Record these declarations provided that they have a name.
if ((node as ClassDeclaration | FunctionDeclaration).name) {
recordEmittedDeclarationInScope(node as ClassDeclaration | FunctionDeclaration);
}
else {
// These nodes should always have names unless they are default-exports;
// however, class declaration parsing allows for undefined names, so syntactically invalid
// programs may also have an undefined name.
Debug.assert(node.kind === SyntaxKind.ClassDeclaration || hasModifier(node, ModifierFlags.Default));
}
break;
}
}
@@ -198,6 +208,24 @@ namespace ts {
* @param node The node to visit.
*/
function sourceElementVisitorWorker(node: Node): VisitResult<Node> {
switch (node.kind) {
case SyntaxKind.ImportDeclaration:
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.ExportAssignment:
case SyntaxKind.ExportDeclaration:
return visitEllidableStatement(<ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration>node);
default:
return visitorWorker(node);
}
}
function visitEllidableStatement(node: ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration): VisitResult<Node> {
const parsed = getParseTreeNode(node);
if (parsed !== node) {
// If the node has been transformed by a `before` transformer, perform no ellision on it
// As the type information we would attempt to lookup to perform ellision is potentially unavailable for the synthesized nodes
return node;
}
switch (node.kind) {
case SyntaxKind.ImportDeclaration:
return visitImportDeclaration(<ImportDeclaration>node);
@@ -208,7 +236,7 @@ namespace ts {
case SyntaxKind.ExportDeclaration:
return visitExportDeclaration(<ExportDeclaration>node);
default:
return visitorWorker(node);
Debug.fail("Unhandled ellided statement");
}
}
@@ -493,7 +521,7 @@ namespace ts {
function visitSourceFile(node: SourceFile) {
const alwaysStrict = (compilerOptions.alwaysStrict === undefined ? compilerOptions.strict : compilerOptions.alwaysStrict) &&
!(isExternalModule(node) && moduleKind === ModuleKind.ES2015);
!(isExternalModule(node) && moduleKind >= ModuleKind.ES2015);
return updateSourceFileNode(
node,
visitLexicalEnvironment(node.statements, sourceElementVisitor, context, /*start*/ 0, alwaysStrict));
@@ -522,7 +550,7 @@ namespace ts {
return parameter.decorators !== undefined && parameter.decorators.length > 0;
}
function getClassFacts(node: ClassDeclaration, staticProperties: PropertyDeclaration[]) {
function getClassFacts(node: ClassDeclaration, staticProperties: ReadonlyArray<PropertyDeclaration>) {
let facts = ClassFacts.None;
if (some(staticProperties)) facts |= ClassFacts.HasStaticInitializedProperties;
if (getClassExtendsHeritageClauseElement(node)) facts |= ClassFacts.HasExtendsClause;
@@ -603,13 +631,16 @@ namespace ts {
addRange(statements, context.endLexicalEnvironment());
const iife = createImmediatelyInvokedArrowFunction(statements);
setEmitFlags(iife, EmitFlags.TypeScriptClassWrapper);
const varStatement = createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ false),
/*type*/ undefined,
createImmediatelyInvokedFunctionExpression(statements)
iife
)
])
);
@@ -1051,7 +1082,7 @@ namespace ts {
*
* @param node The constructor node.
*/
function getParametersWithPropertyAssignments(node: ConstructorDeclaration): ParameterDeclaration[] {
function getParametersWithPropertyAssignments(node: ConstructorDeclaration): ReadonlyArray<ParameterDeclaration> {
return filter(node.parameters, isParameterWithPropertyAssignment);
}
@@ -1104,7 +1135,7 @@ namespace ts {
* @param node The class node.
* @param isStatic A value indicating whether to get properties from the static or instance side of the class.
*/
function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): PropertyDeclaration[] {
function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): ReadonlyArray<PropertyDeclaration> {
return filter(node.members, isStatic ? isStaticInitializedProperty : isInstanceInitializedProperty);
}
@@ -1144,7 +1175,7 @@ namespace ts {
* @param properties An array of property declarations to transform.
* @param receiver The receiver on which each property should be assigned.
*/
function addInitializedPropertyStatements(statements: Statement[], properties: PropertyDeclaration[], receiver: LeftHandSideExpression) {
function addInitializedPropertyStatements(statements: Statement[], properties: ReadonlyArray<PropertyDeclaration>, receiver: LeftHandSideExpression) {
for (const property of properties) {
const statement = createStatement(transformInitializedProperty(property, receiver));
setSourceMapRange(statement, moveRangePastModifiers(property));
@@ -1159,7 +1190,7 @@ namespace ts {
* @param properties An array of property declarations to transform.
* @param receiver The receiver on which each property should be assigned.
*/
function generateInitializedPropertyExpressions(properties: PropertyDeclaration[], receiver: LeftHandSideExpression) {
function generateInitializedPropertyExpressions(properties: ReadonlyArray<PropertyDeclaration>, receiver: LeftHandSideExpression) {
const expressions: Expression[] = [];
for (const property of properties) {
const expression = transformInitializedProperty(property, receiver);
@@ -1194,7 +1225,7 @@ namespace ts {
* @param isStatic A value indicating whether to retrieve static or instance members of
* the class.
*/
function getDecoratedClassElements(node: ClassExpression | ClassDeclaration, isStatic: boolean): ClassElement[] {
function getDecoratedClassElements(node: ClassExpression | ClassDeclaration, isStatic: boolean): ReadonlyArray<ClassElement> {
return filter(node.members, isStatic ? isStaticDecoratedClassElement : isInstanceDecoratedClassElement);
}
@@ -1233,8 +1264,8 @@ namespace ts {
* A structure describing the decorators for a class element.
*/
interface AllDecorators {
decorators: Decorator[];
parameters?: Decorator[][];
decorators: ReadonlyArray<Decorator>;
parameters?: ReadonlyArray<ReadonlyArray<Decorator>>;
}
/**
@@ -1244,7 +1275,7 @@ namespace ts {
* @param node The function-like node.
*/
function getDecoratorsOfParameters(node: FunctionLikeDeclaration) {
let decorators: Decorator[][];
let decorators: ReadonlyArray<Decorator>[];
if (node) {
const parameters = node.parameters;
for (let i = 0; i < parameters.length; i++) {
@@ -1682,7 +1713,7 @@ namespace ts {
const valueDeclaration =
isClassLike(node)
? getFirstConstructorWithBody(node)
: isFunctionLike(node) && nodeIsPresent(node.body)
: isFunctionLike(node) && nodeIsPresent((node as FunctionLikeDeclaration).body)
? node
: undefined;
@@ -1692,7 +1723,7 @@ namespace ts {
const numParameters = parameters.length;
for (let i = 0; i < numParameters; i++) {
const parameter = parameters[i];
if (i === 0 && isIdentifier(parameter.name) && parameter.name.text === "this") {
if (i === 0 && isIdentifier(parameter.name) && parameter.name.escapedText === "this") {
continue;
}
if (parameter.dotDotDotToken) {
@@ -1707,7 +1738,7 @@ namespace ts {
return createArrayLiteral(expressions);
}
function getParametersOfDecoratedDeclaration(node: FunctionLikeDeclaration, container: ClassLikeDeclaration) {
function getParametersOfDecoratedDeclaration(node: FunctionLike, container: ClassLikeDeclaration) {
if (container && node.kind === SyntaxKind.GetAccessor) {
const { setAccessor } = getAllAccessorDeclarations(container.members, <AccessorDeclaration>node);
if (setAccessor) {
@@ -1841,7 +1872,7 @@ namespace ts {
for (const typeNode of node.types) {
const serializedIndividual = serializeTypeNode(typeNode);
if (isIdentifier(serializedIndividual) && serializedIndividual.text === "Object") {
if (isIdentifier(serializedIndividual) && serializedIndividual.escapedText === "Object") {
// One of the individual is global object, return immediately
return serializedIndividual;
}
@@ -1851,7 +1882,7 @@ namespace ts {
// Different types
if (!isIdentifier(serializedUnion) ||
!isIdentifier(serializedIndividual) ||
serializedUnion.text !== serializedIndividual.text) {
serializedUnion.escapedText !== serializedIndividual.escapedText) {
return createIdentifier("Object");
}
}
@@ -1934,7 +1965,7 @@ namespace ts {
const name = getMutableClone(<Identifier>node);
name.flags &= ~NodeFlags.Synthesized;
name.original = undefined;
name.parent = currentScope;
name.parent = getParseTreeNode(currentScope); // ensure the parent is set to a parse tree node.
if (useFallback) {
return createLogicalAnd(
createStrictInequality(
@@ -2007,7 +2038,7 @@ namespace ts {
: (<ComputedPropertyName>name).expression;
}
else if (isIdentifier(name)) {
return createLiteral(unescapeIdentifier(name.text));
return createLiteral(unescapeLeadingUnderscores(name.escapedText));
}
else {
return getSynthesizedClone(name);
@@ -2278,7 +2309,8 @@ namespace ts {
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
visitFunctionBody(node.body, visitor, context)
node.equalsGreaterThanToken,
visitFunctionBody(node.body, visitor, context),
);
return updated;
}
@@ -2633,42 +2665,40 @@ namespace ts {
return isExportOfNamespace(node)
|| (isExternalModuleExport(node)
&& moduleKind !== ModuleKind.ES2015
&& moduleKind !== ModuleKind.ESNext
&& moduleKind !== ModuleKind.System);
}
/**
* Records that a declaration was emitted in the current scope, if it was the first
* declaration for the provided symbol.
*
* NOTE: if there is ever a transformation above this one, we may not be able to rely
* on symbol names.
*/
function recordEmittedDeclarationInScope(node: Node) {
const name = node.symbol && node.symbol.name;
if (name) {
if (!currentScopeFirstDeclarationsOfName) {
currentScopeFirstDeclarationsOfName = createMap<Node>();
}
function recordEmittedDeclarationInScope(node: FunctionDeclaration | ClassDeclaration | ModuleDeclaration | EnumDeclaration) {
if (!currentScopeFirstDeclarationsOfName) {
currentScopeFirstDeclarationsOfName = createUnderscoreEscapedMap<Node>();
}
if (!currentScopeFirstDeclarationsOfName.has(name)) {
currentScopeFirstDeclarationsOfName.set(name, node);
}
const name = declaredNameInScope(node);
if (!currentScopeFirstDeclarationsOfName.has(name)) {
currentScopeFirstDeclarationsOfName.set(name, node);
}
}
/**
* Determines whether a declaration is the first declaration with the same name emitted
* in the current scope.
* Determines whether a declaration is the first declaration with
* the same name emitted in the current scope.
*/
function isFirstEmittedDeclarationInScope(node: Node) {
function isFirstEmittedDeclarationInScope(node: ModuleDeclaration | EnumDeclaration) {
if (currentScopeFirstDeclarationsOfName) {
const name = node.symbol && node.symbol.name;
if (name) {
return currentScopeFirstDeclarationsOfName.get(name) === node;
}
const name = declaredNameInScope(node);
return currentScopeFirstDeclarationsOfName.get(name) === node;
}
return true;
}
return false;
function declaredNameInScope(node: FunctionDeclaration | ClassDeclaration | ModuleDeclaration | EnumDeclaration): __String {
Debug.assertNode(node.name, isIdentifier);
return (node.name as Identifier).escapedText;
}
/**
@@ -2746,7 +2776,7 @@ namespace ts {
return createNotEmittedStatement(node);
}
Debug.assert(isIdentifier(node.name), "TypeScript module should have an Identifier name.");
Debug.assertNode(node.name, isIdentifier, "A TypeScript namespace should have an Identifier name.");
enableSubstitutionForNamespaceExports();
const statements: Statement[] = [];
@@ -3158,7 +3188,7 @@ namespace ts {
getExternalModuleOrNamespaceExportName(currentNamespaceContainerName, node, /*allowComments*/ false, /*allowSourceMaps*/ true),
getLocalName(node)
);
setSourceMapRange(expression, createRange(node.name.pos, node.end));
setSourceMapRange(expression, createRange(node.name ? node.name.pos : node.pos, node.end));
const statement = createStatement(expression);
setSourceMapRange(statement, createRange(-1, node.end));
@@ -3210,7 +3240,7 @@ namespace ts {
function getClassAliasIfNeeded(node: ClassDeclaration) {
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference) {
enableSubstitutionForClassAliases();
const classAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? unescapeIdentifier(node.name.text) : "default");
const classAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? unescapeLeadingUnderscores(node.name.escapedText) : "default");
classAliases[getOriginalNodeId(node)] = classAlias;
hoistVariableDeclaration(classAlias);
return classAlias;
+180
View File
@@ -0,0 +1,180 @@
/* @internal */
namespace ts {
export function getOriginalNodeId(node: Node) {
node = getOriginalNode(node);
return node ? getNodeId(node) : 0;
}
export interface ExternalModuleInfo {
externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[]; // imports of other external modules
externalHelpersImportDeclaration: ImportDeclaration | undefined; // import of external helpers
exportSpecifiers: Map<ExportSpecifier[]>; // export specifiers by name
exportedBindings: Identifier[][]; // exported names of local declarations
exportedNames: Identifier[]; // all exported names local to module
exportEquals: ExportAssignment | undefined; // an export= declaration if one was present
hasExportStarsToExportValues: boolean; // whether this module contains export*
}
export function collectExternalModuleInfo(sourceFile: SourceFile, resolver: EmitResolver, compilerOptions: CompilerOptions): ExternalModuleInfo {
const externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[] = [];
const exportSpecifiers = createMultiMap<ExportSpecifier>();
const exportedBindings: Identifier[][] = [];
const uniqueExports = createMap<boolean>();
let exportedNames: Identifier[];
let hasExportDefault = false;
let exportEquals: ExportAssignment = undefined;
let hasExportStarsToExportValues = false;
for (const node of sourceFile.statements) {
switch (node.kind) {
case SyntaxKind.ImportDeclaration:
// import "mod"
// import x from "mod"
// import * as x from "mod"
// import { x, y } from "mod"
externalImports.push(<ImportDeclaration>node);
break;
case SyntaxKind.ImportEqualsDeclaration:
if ((<ImportEqualsDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference) {
// import x = require("mod")
externalImports.push(<ImportEqualsDeclaration>node);
}
break;
case SyntaxKind.ExportDeclaration:
if ((<ExportDeclaration>node).moduleSpecifier) {
if (!(<ExportDeclaration>node).exportClause) {
// export * from "mod"
externalImports.push(<ExportDeclaration>node);
hasExportStarsToExportValues = true;
}
else {
// export { x, y } from "mod"
externalImports.push(<ExportDeclaration>node);
}
}
else {
// export { x, y }
for (const specifier of (<ExportDeclaration>node).exportClause.elements) {
if (!uniqueExports.get(unescapeLeadingUnderscores(specifier.name.escapedText))) {
const name = specifier.propertyName || specifier.name;
exportSpecifiers.add(unescapeLeadingUnderscores(name.escapedText), specifier);
const decl = resolver.getReferencedImportDeclaration(name)
|| resolver.getReferencedValueDeclaration(name);
if (decl) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(decl), specifier.name);
}
uniqueExports.set(unescapeLeadingUnderscores(specifier.name.escapedText), true);
exportedNames = append(exportedNames, specifier.name);
}
}
}
break;
case SyntaxKind.ExportAssignment:
if ((<ExportAssignment>node).isExportEquals && !exportEquals) {
// export = x
exportEquals = <ExportAssignment>node;
}
break;
case SyntaxKind.VariableStatement:
if (hasModifier(node, ModifierFlags.Export)) {
for (const decl of (<VariableStatement>node).declarationList.declarations) {
exportedNames = collectExportedVariableInfo(decl, uniqueExports, exportedNames);
}
}
break;
case SyntaxKind.FunctionDeclaration:
if (hasModifier(node, ModifierFlags.Export)) {
if (hasModifier(node, ModifierFlags.Default)) {
// export default function() { }
if (!hasExportDefault) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), getDeclarationName(<FunctionDeclaration>node));
hasExportDefault = true;
}
}
else {
// export function x() { }
const name = (<FunctionDeclaration>node).name;
if (!uniqueExports.get(unescapeLeadingUnderscores(name.escapedText))) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
uniqueExports.set(unescapeLeadingUnderscores(name.escapedText), true);
exportedNames = append(exportedNames, name);
}
}
}
break;
case SyntaxKind.ClassDeclaration:
if (hasModifier(node, ModifierFlags.Export)) {
if (hasModifier(node, ModifierFlags.Default)) {
// export default class { }
if (!hasExportDefault) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), getDeclarationName(<ClassDeclaration>node));
hasExportDefault = true;
}
}
else {
// export class x { }
const name = (<ClassDeclaration>node).name;
if (name && !uniqueExports.get(unescapeLeadingUnderscores(name.escapedText))) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
uniqueExports.set(unescapeLeadingUnderscores(name.escapedText), true);
exportedNames = append(exportedNames, name);
}
}
}
break;
}
}
const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(sourceFile, compilerOptions, hasExportStarsToExportValues);
const externalHelpersImportDeclaration = externalHelpersModuleName && createImportDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createImportClause(/*name*/ undefined, createNamespaceImport(externalHelpersModuleName)),
createLiteral(externalHelpersModuleNameText));
if (externalHelpersImportDeclaration) {
externalImports.unshift(externalHelpersImportDeclaration);
}
return { externalImports, exportSpecifiers, exportEquals, hasExportStarsToExportValues, exportedBindings, exportedNames, externalHelpersImportDeclaration };
}
function collectExportedVariableInfo(decl: VariableDeclaration | BindingElement, uniqueExports: Map<boolean>, exportedNames: Identifier[]) {
if (isBindingPattern(decl.name)) {
for (const element of decl.name.elements) {
if (!isOmittedExpression(element)) {
exportedNames = collectExportedVariableInfo(element, uniqueExports, exportedNames);
}
}
}
else if (!isGeneratedIdentifier(decl.name)) {
if (!uniqueExports.get(unescapeLeadingUnderscores(decl.name.escapedText))) {
uniqueExports.set(unescapeLeadingUnderscores(decl.name.escapedText), true);
exportedNames = append(exportedNames, decl.name);
}
}
return exportedNames;
}
/** Use a sparse array as a multi-map. */
function multiMapSparseArrayAdd<V>(map: V[][], key: number, value: V): V[] {
let values = map[key];
if (values) {
values.push(value);
}
else {
map[key] = values = [value];
}
return values;
}
}
+26 -22
View File
@@ -61,7 +61,7 @@ namespace ts {
}
function reportDiagnosticWithColorAndContext(diagnostic: Diagnostic, host: FormatDiagnosticsHost): void {
sys.write(ts.formatDiagnosticsWithColorAndContext([diagnostic], host) + sys.newLine + sys.newLine);
sys.write(ts.formatDiagnosticsWithColorAndContext([diagnostic], host) + sys.newLine);
}
function reportWatchDiagnostic(diagnostic: Diagnostic) {
@@ -100,7 +100,6 @@ namespace ts {
const commandLine = parseCommandLine(args);
let configFileName: string; // Configuration file name (if any)
let cachedConfigFileText: string; // Cached configuration file text, used for reparsing (if any)
let configFileWatcher: FileWatcher; // Configuration file watcher
let directoryWatcher: FileWatcher; // Directory watcher to monitor source file addition/removal
let cachedProgram: Program; // Program cached from last compilation
let rootFileNames: string[]; // Root fileNames for compilation
@@ -189,7 +188,7 @@ namespace ts {
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
}
if (configFileName) {
configFileWatcher = sys.watchFile(configFileName, configFileChanged);
sys.watchFile(configFileName, configFileChanged);
}
if (sys.watchDirectory && configFileName) {
const directory = ts.getDirectoryPath(configFileName);
@@ -223,20 +222,13 @@ namespace ts {
return;
}
const result = parseConfigFileTextToJson(configFileName, cachedConfigFileText);
const configObject = result.config;
if (!configObject) {
reportDiagnostics([result.error], /* compilerHost */ undefined);
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
return;
}
const result = parseJsonText(configFileName, cachedConfigFileText);
reportDiagnostics(result.parseDiagnostics, /* compilerHost */ undefined);
const cwd = sys.getCurrentDirectory();
const configParseResult = parseJsonConfigFileContent(configObject, sys, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), commandLine.options, getNormalizedAbsolutePath(configFileName, cwd));
if (configParseResult.errors.length > 0) {
reportDiagnostics(configParseResult.errors, /* compilerHost */ undefined);
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
return;
}
const configParseResult = parseJsonSourceFileConfigFileContent(result, sys, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), commandLine.options, getNormalizedAbsolutePath(configFileName, cwd));
reportDiagnostics(configParseResult.errors, /* compilerHost */ undefined);
if (isWatchSet(configParseResult.options)) {
if (!sys.watchFile) {
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"), /* host */ undefined);
@@ -292,6 +284,16 @@ namespace ts {
setCachedProgram(compileResult.program);
reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes));
const missingPaths = compileResult.program.getMissingFilePaths();
missingPaths.forEach(path => {
const fileWatcher = sys.watchFile(path, (_fileName, eventKind) => {
if (eventKind === FileWatcherEventKind.Created) {
fileWatcher.close();
startTimerForRecompilation();
}
});
});
}
function cachedFileExists(fileName: string): boolean {
@@ -315,7 +317,7 @@ namespace ts {
const sourceFile = hostGetSourceFile(fileName, languageVersion, onError);
if (sourceFile && isWatchSet(compilerOptions) && sys.watchFile) {
// Attach a file watcher
sourceFile.fileWatcher = sys.watchFile(sourceFile.fileName, (_fileName: string, removed?: boolean) => sourceFileChanged(sourceFile, removed));
sourceFile.fileWatcher = sys.watchFile(sourceFile.fileName, (_fileName, eventKind) => sourceFileChanged(sourceFile, eventKind));
}
return sourceFile;
}
@@ -337,10 +339,10 @@ namespace ts {
}
// If a source file changes, mark it as unwatched and start the recompilation timer
function sourceFileChanged(sourceFile: SourceFile, removed?: boolean) {
function sourceFileChanged(sourceFile: SourceFile, eventKind: FileWatcherEventKind) {
sourceFile.fileWatcher.close();
sourceFile.fileWatcher = undefined;
if (removed) {
if (eventKind === FileWatcherEventKind.Deleted) {
unorderedRemoveItem(rootFileNames, sourceFile.fileName);
}
startTimerForRecompilation();
@@ -466,7 +468,7 @@ namespace ts {
let diagnostics: Diagnostic[];
// First get and report any syntactic errors.
diagnostics = program.getSyntacticDiagnostics();
diagnostics = program.getSyntacticDiagnostics().slice();
// If we didn't have any syntactic errors, then also try getting the global and
// semantic errors.
@@ -474,13 +476,13 @@ namespace ts {
diagnostics = program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics());
if (diagnostics.length === 0) {
diagnostics = program.getSemanticDiagnostics();
diagnostics = program.getSemanticDiagnostics().slice();
}
}
// Otherwise, emit and report any errors we ran into.
const emitOutput = program.emit();
diagnostics = diagnostics.concat(emitOutput.diagnostics);
addRange(diagnostics, emitOutput.diagnostics);
reportDiagnostics(sortAndDeduplicateDiagnostics(diagnostics), compilerHost);
@@ -662,6 +664,8 @@ namespace ts {
}
}
ts.setStackTraceLimit();
if (ts.Debug.isDebugging) {
ts.Debug.enableDebugInfo();
}
+2 -1
View File
@@ -14,9 +14,11 @@
"parser.ts",
"utilities.ts",
"binder.ts",
"symbolWalker.ts",
"checker.ts",
"factory.ts",
"visitor.ts",
"transformers/utilities.ts",
"transformers/ts.ts",
"transformers/jsx.ts",
"transformers/esnext.ts",
@@ -25,7 +27,6 @@
"transformers/es2015.ts",
"transformers/es5.ts",
"transformers/generators.ts",
"transformers/es5.ts",
"transformers/destructuring.ts",
"transformers/module/module.ts",
"transformers/module/system.ts",
+447 -260
View File
File diff suppressed because it is too large Load Diff
+810 -652
View File
File diff suppressed because it is too large Load Diff
+27 -27
View File
@@ -86,7 +86,7 @@ namespace ts {
return nodes;
}
let updated: NodeArray<T>;
let updated: MutableNodeArray<T>;
// Ensure start and count have valid values
const length = nodes.length;
@@ -270,12 +270,13 @@ namespace ts {
nodesVisitor((<PropertyDeclaration>node).decorators, visitor, isDecorator),
nodesVisitor((<PropertyDeclaration>node).modifiers, visitor, isModifier),
visitNode((<PropertyDeclaration>node).name, visitor, isPropertyName),
visitNode((<PropertyDeclaration>node).questionToken, tokenVisitor, isToken),
visitNode((<PropertyDeclaration>node).type, visitor, isTypeNode),
visitNode((<PropertyDeclaration>node).initializer, visitor, isExpression));
case SyntaxKind.MethodSignature:
return updateMethodSignature(<MethodSignature>node,
nodesVisitor((<MethodSignature>node).typeParameters, visitor, isTypeParameter),
nodesVisitor((<MethodSignature>node).typeParameters, visitor, isTypeParameterDeclaration),
nodesVisitor((<MethodSignature>node).parameters, visitor, isParameterDeclaration),
visitNode((<MethodSignature>node).type, visitor, isTypeNode),
visitNode((<MethodSignature>node).name, visitor, isPropertyName),
@@ -288,7 +289,7 @@ namespace ts {
visitNode((<MethodDeclaration>node).asteriskToken, tokenVisitor, isToken),
visitNode((<MethodDeclaration>node).name, visitor, isPropertyName),
visitNode((<MethodDeclaration>node).questionToken, tokenVisitor, isToken),
nodesVisitor((<MethodDeclaration>node).typeParameters, visitor, isTypeParameter),
nodesVisitor((<MethodDeclaration>node).typeParameters, visitor, isTypeParameterDeclaration),
visitParameterList((<MethodDeclaration>node).parameters, visitor, context, nodesVisitor),
visitNode((<MethodDeclaration>node).type, visitor, isTypeNode),
visitFunctionBody((<MethodDeclaration>node).body, visitor, context));
@@ -319,13 +320,13 @@ namespace ts {
case SyntaxKind.CallSignature:
return updateCallSignature(<CallSignatureDeclaration>node,
nodesVisitor((<CallSignatureDeclaration>node).typeParameters, visitor, isTypeParameter),
nodesVisitor((<CallSignatureDeclaration>node).typeParameters, visitor, isTypeParameterDeclaration),
nodesVisitor((<CallSignatureDeclaration>node).parameters, visitor, isParameterDeclaration),
visitNode((<CallSignatureDeclaration>node).type, visitor, isTypeNode));
case SyntaxKind.ConstructSignature:
return updateConstructSignature(<ConstructSignatureDeclaration>node,
nodesVisitor((<ConstructSignatureDeclaration>node).typeParameters, visitor, isTypeParameter),
nodesVisitor((<ConstructSignatureDeclaration>node).typeParameters, visitor, isTypeParameterDeclaration),
nodesVisitor((<ConstructSignatureDeclaration>node).parameters, visitor, isParameterDeclaration),
visitNode((<ConstructSignatureDeclaration>node).type, visitor, isTypeNode));
@@ -350,13 +351,13 @@ namespace ts {
case SyntaxKind.FunctionType:
return updateFunctionTypeNode(<FunctionTypeNode>node,
nodesVisitor((<FunctionTypeNode>node).typeParameters, visitor, isTypeParameter),
nodesVisitor((<FunctionTypeNode>node).typeParameters, visitor, isTypeParameterDeclaration),
nodesVisitor((<FunctionTypeNode>node).parameters, visitor, isParameterDeclaration),
visitNode((<FunctionTypeNode>node).type, visitor, isTypeNode));
case SyntaxKind.ConstructorType:
return updateConstructorTypeNode(<ConstructorTypeNode>node,
nodesVisitor((<ConstructorTypeNode>node).typeParameters, visitor, isTypeParameter),
nodesVisitor((<ConstructorTypeNode>node).typeParameters, visitor, isTypeParameterDeclaration),
nodesVisitor((<ConstructorTypeNode>node).parameters, visitor, isParameterDeclaration),
visitNode((<ConstructorTypeNode>node).type, visitor, isTypeNode));
@@ -400,7 +401,7 @@ namespace ts {
case SyntaxKind.MappedType:
return updateMappedTypeNode((<MappedTypeNode>node),
visitNode((<MappedTypeNode>node).readonlyToken, tokenVisitor, isToken),
visitNode((<MappedTypeNode>node).typeParameter, visitor, isTypeParameter),
visitNode((<MappedTypeNode>node).typeParameter, visitor, isTypeParameterDeclaration),
visitNode((<MappedTypeNode>node).questionToken, tokenVisitor, isToken),
visitNode((<MappedTypeNode>node).type, visitor, isTypeNode));
@@ -476,7 +477,7 @@ namespace ts {
nodesVisitor((<FunctionExpression>node).modifiers, visitor, isModifier),
visitNode((<FunctionExpression>node).asteriskToken, tokenVisitor, isToken),
visitNode((<FunctionExpression>node).name, visitor, isIdentifier),
nodesVisitor((<FunctionExpression>node).typeParameters, visitor, isTypeParameter),
nodesVisitor((<FunctionExpression>node).typeParameters, visitor, isTypeParameterDeclaration),
visitParameterList((<FunctionExpression>node).parameters, visitor, context, nodesVisitor),
visitNode((<FunctionExpression>node).type, visitor, isTypeNode),
visitFunctionBody((<FunctionExpression>node).body, visitor, context));
@@ -484,9 +485,10 @@ namespace ts {
case SyntaxKind.ArrowFunction:
return updateArrowFunction(<ArrowFunction>node,
nodesVisitor((<ArrowFunction>node).modifiers, visitor, isModifier),
nodesVisitor((<ArrowFunction>node).typeParameters, visitor, isTypeParameter),
nodesVisitor((<ArrowFunction>node).typeParameters, visitor, isTypeParameterDeclaration),
visitParameterList((<ArrowFunction>node).parameters, visitor, context, nodesVisitor),
visitNode((<ArrowFunction>node).type, visitor, isTypeNode),
visitNode((<ArrowFunction>node).equalsGreaterThanToken, visitor, isToken),
visitFunctionBody((<ArrowFunction>node).body, visitor, context));
case SyntaxKind.DeleteExpression:
@@ -522,7 +524,9 @@ namespace ts {
case SyntaxKind.ConditionalExpression:
return updateConditional(<ConditionalExpression>node,
visitNode((<ConditionalExpression>node).condition, visitor, isExpression),
visitNode((<ConditionalExpression>node).questionToken, visitor, isToken),
visitNode((<ConditionalExpression>node).whenTrue, visitor, isExpression),
visitNode((<ConditionalExpression>node).colonToken, visitor, isToken),
visitNode((<ConditionalExpression>node).whenFalse, visitor, isExpression));
case SyntaxKind.TemplateExpression:
@@ -543,7 +547,7 @@ namespace ts {
return updateClassExpression(<ClassExpression>node,
nodesVisitor((<ClassExpression>node).modifiers, visitor, isModifier),
visitNode((<ClassExpression>node).name, visitor, isIdentifier),
nodesVisitor((<ClassExpression>node).typeParameters, visitor, isTypeParameter),
nodesVisitor((<ClassExpression>node).typeParameters, visitor, isTypeParameterDeclaration),
nodesVisitor((<ClassExpression>node).heritageClauses, visitor, isHeritageClause),
nodesVisitor((<ClassExpression>node).members, visitor, isClassElement));
@@ -676,7 +680,7 @@ namespace ts {
nodesVisitor((<FunctionDeclaration>node).modifiers, visitor, isModifier),
visitNode((<FunctionDeclaration>node).asteriskToken, tokenVisitor, isToken),
visitNode((<FunctionDeclaration>node).name, visitor, isIdentifier),
nodesVisitor((<FunctionDeclaration>node).typeParameters, visitor, isTypeParameter),
nodesVisitor((<FunctionDeclaration>node).typeParameters, visitor, isTypeParameterDeclaration),
visitParameterList((<FunctionDeclaration>node).parameters, visitor, context, nodesVisitor),
visitNode((<FunctionDeclaration>node).type, visitor, isTypeNode),
visitFunctionBody((<FunctionExpression>node).body, visitor, context));
@@ -686,7 +690,7 @@ namespace ts {
nodesVisitor((<ClassDeclaration>node).decorators, visitor, isDecorator),
nodesVisitor((<ClassDeclaration>node).modifiers, visitor, isModifier),
visitNode((<ClassDeclaration>node).name, visitor, isIdentifier),
nodesVisitor((<ClassDeclaration>node).typeParameters, visitor, isTypeParameter),
nodesVisitor((<ClassDeclaration>node).typeParameters, visitor, isTypeParameterDeclaration),
nodesVisitor((<ClassDeclaration>node).heritageClauses, visitor, isHeritageClause),
nodesVisitor((<ClassDeclaration>node).members, visitor, isClassElement));
@@ -695,7 +699,7 @@ namespace ts {
nodesVisitor((<InterfaceDeclaration>node).decorators, visitor, isDecorator),
nodesVisitor((<InterfaceDeclaration>node).modifiers, visitor, isModifier),
visitNode((<InterfaceDeclaration>node).name, visitor, isIdentifier),
nodesVisitor((<InterfaceDeclaration>node).typeParameters, visitor, isTypeParameter),
nodesVisitor((<InterfaceDeclaration>node).typeParameters, visitor, isTypeParameterDeclaration),
nodesVisitor((<InterfaceDeclaration>node).heritageClauses, visitor, isHeritageClause),
nodesVisitor((<InterfaceDeclaration>node).members, visitor, isTypeElement));
@@ -704,7 +708,7 @@ namespace ts {
nodesVisitor((<TypeAliasDeclaration>node).decorators, visitor, isDecorator),
nodesVisitor((<TypeAliasDeclaration>node).modifiers, visitor, isModifier),
visitNode((<TypeAliasDeclaration>node).name, visitor, isIdentifier),
nodesVisitor((<TypeAliasDeclaration>node).typeParameters, visitor, isTypeParameter),
nodesVisitor((<TypeAliasDeclaration>node).typeParameters, visitor, isTypeParameterDeclaration),
visitNode((<TypeAliasDeclaration>node).type, visitor, isTypeNode));
case SyntaxKind.EnumDeclaration:
@@ -900,7 +904,7 @@ namespace ts {
*
* @param nodes The NodeArray.
*/
function extractSingleNode(nodes: Node[]): Node {
function extractSingleNode(nodes: ReadonlyArray<Node>): Node {
Debug.assert(nodes.length <= 1, "Too many nodes written to output.");
return singleOrUndefined(nodes);
}
@@ -1148,10 +1152,6 @@ namespace ts {
result = reduceNode((<AsExpression>node).type, cbNode, result);
break;
case SyntaxKind.NonNullExpression:
result = reduceNode((<NonNullExpression>node).expression, cbNode, result);
break;
// Misc
case SyntaxKind.TemplateSpan:
result = reduceNode((<TemplateSpan>node).expression, cbNode, result);
@@ -1198,9 +1198,9 @@ namespace ts {
case SyntaxKind.ForInStatement:
case SyntaxKind.ForOfStatement:
result = reduceNode((<ForInStatement | ForOfStatement>node).initializer, cbNode, result);
result = reduceNode((<ForInStatement | ForOfStatement>node).expression, cbNode, result);
result = reduceNode((<ForInStatement | ForOfStatement>node).statement, cbNode, result);
result = reduceNode((<ForInOrOfStatement>node).initializer, cbNode, result);
result = reduceNode((<ForInOrOfStatement>node).expression, cbNode, result);
result = reduceNode((<ForInOrOfStatement>node).statement, cbNode, result);
break;
case SyntaxKind.ReturnStatement:
@@ -1424,13 +1424,13 @@ namespace ts {
/**
* Merges generated lexical declarations into a new statement list.
*/
export function mergeLexicalEnvironment(statements: NodeArray<Statement>, declarations: Statement[]): NodeArray<Statement>;
export function mergeLexicalEnvironment(statements: NodeArray<Statement>, declarations: ReadonlyArray<Statement>): NodeArray<Statement>;
/**
* Appends generated lexical declarations to an array of statements.
*/
export function mergeLexicalEnvironment(statements: Statement[], declarations: Statement[]): Statement[];
export function mergeLexicalEnvironment(statements: Statement[], declarations: Statement[]) {
export function mergeLexicalEnvironment(statements: Statement[], declarations: ReadonlyArray<Statement>): Statement[];
export function mergeLexicalEnvironment(statements: Statement[] | NodeArray<Statement>, declarations: ReadonlyArray<Statement>) {
if (!some(declarations)) {
return statements;
}
@@ -1445,7 +1445,7 @@ namespace ts {
*
* @param nodes The NodeArray.
*/
export function liftToBlock(nodes: Node[]): Statement {
export function liftToBlock(nodes: ReadonlyArray<Node>): Statement {
Debug.assert(every(nodes, isStatement), "Cannot lift nodes to a Block.");
return <Statement>singleOrUndefined(nodes) || createBlock(<NodeArray<Statement>>nodes);
}
+16 -25
View File
@@ -11,19 +11,13 @@ const enum CompilerTestType {
class CompilerBaselineRunner extends RunnerBase {
private basePath = "tests/cases";
private testSuiteName: TestRunnerKind;
private errors: boolean;
private emit: boolean;
private decl: boolean;
private output: boolean;
public options: string;
constructor(public testType: CompilerTestType) {
super();
this.errors = true;
this.emit = true;
this.decl = true;
this.output = true;
if (testType === CompilerTestType.Conformance) {
this.testSuiteName = "conformance";
}
@@ -64,6 +58,7 @@ class CompilerBaselineRunner extends RunnerBase {
let result: Harness.Compiler.CompilerResult;
let options: ts.CompilerOptions;
let tsConfigFiles: Harness.Compiler.TestFile[];
// equivalent to the files that will be passed on the command line
let toBeCompiled: Harness.Compiler.TestFile[];
// equivalent to other files on the file system not directly passed to the compiler (ie things that are referenced by other files)
@@ -77,10 +72,12 @@ class CompilerBaselineRunner extends RunnerBase {
const units = testCaseContent.testUnitData;
harnessSettings = testCaseContent.settings;
let tsConfigOptions: ts.CompilerOptions;
tsConfigFiles = [];
if (testCaseContent.tsConfig) {
assert.equal(testCaseContent.tsConfig.fileNames.length, 0, `list of files in tsconfig is not currently supported`);
tsConfigOptions = ts.clone(testCaseContent.tsConfig.options);
tsConfigOptions = ts.cloneCompilerOptions(testCaseContent.tsConfig.options);
tsConfigFiles.push(this.createHarnessTestFile(testCaseContent.tsConfigFileUnitData, rootDir, ts.combinePaths(rootDir, tsConfigOptions.configFilePath)));
}
else {
const baseUrl = harnessSettings["baseUrl"];
@@ -90,7 +87,7 @@ class CompilerBaselineRunner extends RunnerBase {
}
lastUnit = units[units.length - 1];
hasNonDtsFiles = ts.forEach(units, unit => !ts.fileExtensionIs(unit.name, ".d.ts"));
hasNonDtsFiles = ts.forEach(units, unit => !ts.fileExtensionIs(unit.name, ts.Extension.Dts));
// We need to assemble the list of input files for the compiler and other related files on the 'filesystem' (ie in a multi-file test)
// If the last file in a test uses require or a triple slash reference we'll assume all other files will be brought in via references,
// otherwise, assume all files are just meant to be in the same compilation session without explicit references to one another.
@@ -98,21 +95,22 @@ class CompilerBaselineRunner extends RunnerBase {
otherFiles = [];
if (testCaseContent.settings["noImplicitReferences"] || /require\(/.test(lastUnit.content) || /reference\spath/.test(lastUnit.content)) {
toBeCompiled.push({ unitName: this.makeUnitName(lastUnit.name, rootDir), content: lastUnit.content, fileOptions: lastUnit.fileOptions });
toBeCompiled.push(this.createHarnessTestFile(lastUnit, rootDir));
units.forEach(unit => {
if (unit.name !== lastUnit.name) {
otherFiles.push({ unitName: this.makeUnitName(unit.name, rootDir), content: unit.content, fileOptions: unit.fileOptions });
otherFiles.push(this.createHarnessTestFile(unit, rootDir));
}
});
}
else {
toBeCompiled = units.map(unit => {
return { unitName: this.makeUnitName(unit.name, rootDir), content: unit.content, fileOptions: unit.fileOptions };
return this.createHarnessTestFile(unit, rootDir);
});
}
if (tsConfigOptions && tsConfigOptions.configFilePath !== undefined) {
tsConfigOptions.configFilePath = ts.combinePaths(rootDir, tsConfigOptions.configFilePath);
tsConfigOptions.configFile.fileName = tsConfigOptions.configFilePath;
}
const output = Harness.Compiler.compileFiles(
@@ -132,11 +130,12 @@ class CompilerBaselineRunner extends RunnerBase {
options = undefined;
toBeCompiled = undefined;
otherFiles = undefined;
tsConfigFiles = undefined;
});
// check errors
it("Correct errors for " + fileName, () => {
Harness.Compiler.doErrorBaseline(justName, toBeCompiled.concat(otherFiles), result.errors);
Harness.Compiler.doErrorBaseline(justName, tsConfigFiles.concat(toBeCompiled, otherFiles), result.errors, !!options.pretty);
});
it (`Correct module resolution tracing for ${fileName}`, () => {
@@ -165,7 +164,7 @@ class CompilerBaselineRunner extends RunnerBase {
it("Correct JS output for " + fileName, () => {
if (hasNonDtsFiles && this.emit) {
Harness.Compiler.doJsEmitBaseline(justName, fileName, options, result, toBeCompiled, otherFiles, harnessSettings);
Harness.Compiler.doJsEmitBaseline(justName, fileName, options, result, tsConfigFiles, toBeCompiled, otherFiles, harnessSettings);
}
});
@@ -183,6 +182,10 @@ class CompilerBaselineRunner extends RunnerBase {
});
}
private createHarnessTestFile(lastUnit: Harness.TestCaseParser.TestUnitData, rootDir: string, unitName?: string): Harness.Compiler.TestFile {
return { unitName: unitName || this.makeUnitName(lastUnit.name, rootDir), content: lastUnit.content, fileOptions: lastUnit.fileOptions };
}
public initializeTests() {
describe(this.testSuiteName + " tests", () => {
describe("Setup compiler for compiler baselines", () => {
@@ -205,26 +208,14 @@ class CompilerBaselineRunner extends RunnerBase {
private parseOptions() {
if (this.options && this.options.length > 0) {
this.errors = false;
this.emit = false;
this.decl = false;
this.output = false;
const opts = this.options.split(",");
for (let i = 0; i < opts.length; i++) {
switch (opts[i]) {
case "error":
this.errors = true;
break;
case "emit":
this.emit = true;
break;
case "decl":
this.decl = true;
break;
case "output":
this.output = true;
break;
default:
throw new Error("unsupported flag");
}
+383 -229
View File
File diff suppressed because it is too large Load Diff
+269 -112
View File
@@ -67,17 +67,16 @@ namespace Utils {
export let currentExecutionEnvironment = getExecutionEnvironment();
const Buffer: typeof global.Buffer = currentExecutionEnvironment !== ExecutionEnvironment.Browser
? require("buffer").Buffer
: undefined;
// Thanks to browserify, Buffer is always available nowadays
const Buffer: typeof global.Buffer = require("buffer").Buffer;
export function encodeString(s: string): string {
return Buffer ? (new Buffer(s)).toString("utf8") : s;
return Buffer.from(s).toString("utf8");
}
export function byteLength(s: string, encoding?: string): number {
// stub implementation if Buffer is not available (in-browser case)
return Buffer ? Buffer.byteLength(s, encoding) : s.length;
return Buffer.byteLength(s, encoding);
}
export function evalFile(fileContents: string, fileName: string, nodeContext?: any) {
@@ -133,17 +132,18 @@ namespace Utils {
return content;
}
export function memoize<T extends Function>(f: T): T {
const cache: { [idx: string]: any } = {};
export function memoize<T extends Function>(f: T, memoKey: (...anything: any[]) => string): T {
const cache = ts.createMap<any>();
return <any>(function(this: any) {
const key = Array.prototype.join.call(arguments);
const cachedResult = cache[key];
if (cachedResult) {
return cachedResult;
return <any>(function(this: any, ...args: any[]) {
const key = memoKey(...args);
if (cache.has(key)) {
return cache.get(key);
}
else {
return cache[key] = f.apply(this, arguments);
const value = f.apply(this, args);
cache.set(key, value);
return value;
}
});
}
@@ -207,7 +207,7 @@ namespace Utils {
return a !== undefined && typeof a.pos === "number";
}
export function convertDiagnostics(diagnostics: ts.Diagnostic[]) {
export function convertDiagnostics(diagnostics: ReadonlyArray<ts.Diagnostic>) {
return diagnostics.map(convertDiagnostic);
}
@@ -337,7 +337,7 @@ namespace Utils {
}
}
export function assertDiagnosticsEquals(array1: ts.Diagnostic[], array2: ts.Diagnostic[]) {
export function assertDiagnosticsEquals(array1: ReadonlyArray<ts.Diagnostic>, array2: ReadonlyArray<ts.Diagnostic>) {
if (array1 === array2) {
return;
}
@@ -420,7 +420,7 @@ namespace Utils {
const maxHarnessFrames = 1;
export function filterStack(error: Error, stackTraceLimit: number = Infinity) {
export function filterStack(error: Error, stackTraceLimit = Infinity) {
const stack = <string>(<any>error).stack;
if (stack) {
const lines = stack.split(/\r\n?|\n/g);
@@ -479,7 +479,7 @@ namespace Harness {
getCurrentDirectory(): string;
useCaseSensitiveFileNames(): boolean;
resolvePath(path: string): string;
readFile(path: string): string;
readFile(path: string): string | undefined;
writeFile(path: string, contents: string): void;
directoryName(path: string): string;
getDirectories(path: string): string[];
@@ -493,14 +493,15 @@ namespace Harness {
args(): string[];
getExecutingFilePath(): string;
exit(exitCode?: number): void;
readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[]): string[];
readDirectory(path: string, extension?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
tryEnableSourceMapsForHost?(): void;
getEnvironmentVariable?(name: string): string;
}
export let IO: IO;
// harness always uses one kind of new line
const harnessNewLine = "\r\n";
// But note that `parseTestData` in `fourslash.ts` uses "\n"
export const harnessNewLine = "\r\n";
// Root for file paths that are stored in a virtual file system
export const virtualFileSystemRoot = "/";
@@ -537,7 +538,7 @@ namespace Harness {
ts.sys.tryEnableSourceMapsForHost();
}
}
export const readDirectory: typeof IO.readDirectory = (path, extension, exclude, include) => ts.sys.readDirectory(path, extension, exclude, include);
export const readDirectory: typeof IO.readDirectory = (path, extension, exclude, include, depth) => ts.sys.readDirectory(path, extension, exclude, include, depth);
export function createDirectory(path: string) {
if (!directoryExists(path)) {
@@ -564,7 +565,7 @@ namespace Harness {
}
export let listFiles: typeof IO.listFiles = (path, spec?, options?) => {
options = options || <{ recursive?: boolean; }>{};
options = options || {};
function filesInFolder(folder: string): string[] {
let paths: string[] = [];
@@ -686,7 +687,7 @@ namespace Harness {
return dirPath;
}
export let directoryName: typeof IO.directoryName = Utils.memoize(directoryNameImpl);
export let directoryName: typeof IO.directoryName = Utils.memoize(directoryNameImpl, path => path);
export function resolvePath(path: string) {
const response = Http.getFileFromServerSync(serverRoot + path + "?resolve=true");
@@ -703,23 +704,24 @@ namespace Harness {
return response.status === 200;
}
export let listFiles = Utils.memoize((path: string, spec?: RegExp): string[] => {
export const listFiles = Utils.memoize((path: string, spec?: RegExp, options?: { recursive?: boolean }): string[] => {
const response = Http.getFileFromServerSync(serverRoot + path);
if (response.status === 200) {
const results = response.responseText.split(",");
let results = response.responseText.split(",");
if (spec) {
return results.filter(file => spec.test(file));
results = results.filter(file => spec.test(file));
}
else {
return results;
if (options && !options.recursive) {
results = results.filter(file => (ts.getDirectoryPath(ts.normalizeSlashes(file)) === path));
}
return results;
}
else {
return [""];
}
});
}, (path: string, spec?: RegExp, options?: { recursive?: boolean }) => `${path}|${spec}|${options ? options.recursive : undefined}`);
export function readFile(file: string) {
export function readFile(file: string): string | undefined {
const response = Http.getFileFromServerSync(serverRoot + file);
if (response.status === 200) {
return response.responseText;
@@ -733,12 +735,12 @@ namespace Harness {
Http.writeToServerSync(serverRoot + path, "WRITE", contents);
}
export function readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[]) {
export function readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[], depth?: number) {
const fs = new Utils.VirtualFileSystem(path, useCaseSensitiveFileNames());
for (const file of listFiles(path)) {
fs.addFile(file);
}
return ts.matchFiles(path, extension, exclude, include, useCaseSensitiveFileNames(), getCurrentDirectory(), path => {
return ts.matchFiles(path, extension, exclude, include, useCaseSensitiveFileNames(), getCurrentDirectory(), depth, path => {
const entry = fs.traversePath(path);
if (entry && entry.isDirectory()) {
const directory = <Utils.VirtualDirectory>entry;
@@ -893,13 +895,13 @@ namespace Harness {
const getCanonicalFileName = ts.createGetCanonicalFileName(useCaseSensitiveFileNames);
/** Maps a symlink name to a realpath. Used only for exposing `realpath`. */
const realPathMap = ts.createFileMap<string>();
const realPathMap = ts.createMap<string>();
/**
* Maps a file name to a source file.
* This will have a different SourceFile for every symlink pointing to that file;
* if the program resolves realpaths then symlink entries will be ignored.
*/
const fileMap = ts.createFileMap<ts.SourceFile>();
const fileMap = ts.createMap<ts.SourceFile>();
for (const file of inputFiles) {
if (file.content !== undefined) {
const fileName = ts.normalizePath(file.unitName);
@@ -975,8 +977,8 @@ namespace Harness {
getCanonicalFileName,
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
getNewLine: () => newLine,
fileExists: fileName => fileMap.contains(toPath(fileName)),
readFile: (fileName: string): string => {
fileExists: fileName => fileMap.has(toPath(fileName)),
readFile(fileName: string): string | undefined {
const file = fileMap.get(toPath(fileName));
if (ts.endsWith(fileName, "json")) {
// strip comments
@@ -999,7 +1001,7 @@ namespace Harness {
getDirectories: d => {
const path = ts.toPath(d, currentDirectory, getCanonicalFileName);
const result: string[] = [];
fileMap.forEachValue(key => {
ts.forEachKey(fileMap, key => {
if (key.indexOf(path) === 0 && key.lastIndexOf("/") > path.length) {
let dirName = key.substr(path.length, key.indexOf("/", path.length + 1) - path.length);
if (dirName[0] === "/") {
@@ -1015,12 +1017,12 @@ namespace Harness {
};
}
function mapHasFileInDirectory(directoryPath: ts.Path, map: ts.FileMap<any>): boolean {
function mapHasFileInDirectory(directoryPath: ts.Path, map: ts.Map<{}>): boolean {
if (!map) {
return false;
}
let exists = false;
map.forEachValue(fileName => {
ts.forEachKey(map, fileName => {
if (!exists && ts.startsWith(fileName, directoryPath) && fileName[directoryPath.length] === "/") {
exists = true;
}
@@ -1053,7 +1055,7 @@ namespace Harness {
];
let optionsIndex: ts.Map<ts.CommandLineOption>;
function getCommandLineOption(name: string): ts.CommandLineOption {
function getCommandLineOption(name: string): ts.CommandLineOption | undefined {
if (!optionsIndex) {
optionsIndex = ts.createMap<ts.CommandLineOption>();
const optionDeclarations = harnessOptionDeclarations.concat(ts.optionDeclarations);
@@ -1125,7 +1127,7 @@ namespace Harness {
compilerOptions: ts.CompilerOptions,
// Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file
currentDirectory: string): CompilationOutput {
const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.clone(compilerOptions) : { noResolve: false };
const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.cloneCompilerOptions(compilerOptions) : { noResolve: false };
options.target = options.target || ts.ScriptTarget.ES3;
options.newLine = options.newLine || ts.NewLineKind.CarriageReturnLineFeed;
options.noErrorTruncation = true;
@@ -1194,13 +1196,21 @@ namespace Harness {
return { result, options };
}
export function compileDeclarationFiles(inputFiles: TestFile[],
export interface DeclarationCompilationContext {
declInputFiles: TestFile[];
declOtherFiles: TestFile[];
harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions;
options: ts.CompilerOptions;
currentDirectory: string;
}
export function prepareDeclarationCompilationContext(inputFiles: TestFile[],
otherFiles: TestFile[],
result: CompilerResult,
harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions,
options: ts.CompilerOptions,
// Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file
currentDirectory: string) {
currentDirectory: string): DeclarationCompilationContext | undefined {
if (options.declaration && result.errors.length === 0 && result.declFilesCode.length !== result.files.length) {
throw new Error("There were no errors and declFiles generated did not match number of js files generated");
}
@@ -1212,8 +1222,7 @@ namespace Harness {
if (options.declaration && result.errors.length === 0 && result.declFilesCode.length > 0) {
ts.forEach(inputFiles, file => addDtsFile(file, declInputFiles));
ts.forEach(otherFiles, file => addDtsFile(file, declOtherFiles));
const output = compileFiles(declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory || harnessSettings["currentDirectory"]);
return { declInputFiles, declOtherFiles, declResult: output.result };
return { declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory: currentDirectory || harnessSettings["currentDirectory"] };
}
function addDtsFile(file: TestFile, dtsFiles: TestFile[]) {
@@ -1249,7 +1258,7 @@ namespace Harness {
sourceFileName = outFile;
}
const dTsFileName = ts.removeFileExtension(sourceFileName) + ".d.ts";
const dTsFileName = ts.removeFileExtension(sourceFileName) + ts.Extension.Dts;
return ts.forEach(result.declFilesCode, declFile => declFile.fileName === dTsFileName ? declFile : undefined);
}
@@ -1259,6 +1268,15 @@ namespace Harness {
}
}
export function compileDeclarationFiles(context: DeclarationCompilationContext | undefined) {
if (!context) {
return;
}
const { declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory } = context;
const output = compileFiles(declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory);
return { declInputFiles, declOtherFiles, declResult: output.result };
}
function normalizeLineEndings(text: string, lineEnding: string): string {
let normalized = text.replace(/\r\n?/g, "\n");
if (lineEnding !== "\n") {
@@ -1267,16 +1285,40 @@ namespace Harness {
return normalized;
}
export function minimalDiagnosticsToString(diagnostics: ts.Diagnostic[]) {
return ts.formatDiagnostics(diagnostics, { getCanonicalFileName, getCurrentDirectory: () => "", getNewLine: () => Harness.IO.newLine() });
export function minimalDiagnosticsToString(diagnostics: ReadonlyArray<ts.Diagnostic>, pretty?: boolean) {
const host = { getCanonicalFileName, getCurrentDirectory: () => "", getNewLine: () => Harness.IO.newLine() };
return (pretty ? ts.formatDiagnosticsWithColorAndContext : ts.formatDiagnostics)(diagnostics, host);
}
export function getErrorBaseline(inputFiles: TestFile[], diagnostics: ts.Diagnostic[]) {
diagnostics.sort(ts.compareDiagnostics);
const outputLines: string[] = [];
export function getErrorBaseline(inputFiles: ReadonlyArray<TestFile>, diagnostics: ReadonlyArray<ts.Diagnostic>, pretty?: boolean) {
let outputLines = "";
const gen = iterateErrorBaseline(inputFiles, diagnostics, pretty);
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
const [, content] = value;
outputLines += content;
}
return outputLines;
}
export const diagnosticSummaryMarker = "__diagnosticSummary";
export const globalErrorsMarker = "__globalErrors";
export function *iterateErrorBaseline(inputFiles: ReadonlyArray<TestFile>, diagnostics: ReadonlyArray<ts.Diagnostic>, pretty?: boolean): IterableIterator<[string, string, number]> {
diagnostics = diagnostics.slice().sort(ts.compareDiagnostics);
let outputLines = "";
// Count up all errors that were found in files other than lib.d.ts so we don't miss any
let totalErrorsReportedInNonLibraryFiles = 0;
let errorsReported = 0;
let firstLine = true;
function newLine() {
if (firstLine) {
firstLine = false;
return "";
}
return "\r\n";
}
function outputErrorText(error: ts.Diagnostic) {
const message = ts.flattenDiagnosticMessageText(error.messageText, Harness.IO.newLine());
@@ -1285,7 +1327,8 @@ namespace Harness {
.map(s => s.length > 0 && s.charAt(s.length - 1) === "\r" ? s.substr(0, s.length - 1) : s)
.filter(s => s.length > 0)
.map(s => "!!! " + ts.DiagnosticCategory[error.category].toLowerCase() + " TS" + error.code + ": " + s);
errLines.forEach(e => outputLines.push(e));
errLines.forEach(e => outputLines += (newLine() + e));
errorsReported++;
// do not count errors from lib.d.ts here, they are computed separately as numLibraryDiagnostics
// if lib.d.ts is explicitly included in input files and there are some errors in it (i.e. because of duplicate identifiers)
@@ -1297,12 +1340,18 @@ namespace Harness {
}
}
yield [diagnosticSummaryMarker, minimalDiagnosticsToString(diagnostics, pretty) + Harness.IO.newLine() + Harness.IO.newLine(), diagnostics.length];
// Report global errors
const globalErrors = diagnostics.filter(err => !err.file);
globalErrors.forEach(outputErrorText);
yield [globalErrorsMarker, outputLines, errorsReported];
outputLines = "";
errorsReported = 0;
// 'merge' the lines of each input file with any errors associated with it
inputFiles.filter(f => f.content !== undefined).forEach(inputFile => {
const dupeCase = ts.createMap<number>();
for (const inputFile of inputFiles.filter(f => f.content !== undefined)) {
// Filter down to the errors in the file
const fileErrors = diagnostics.filter(e => {
const errFn = e.file;
@@ -1311,7 +1360,7 @@ namespace Harness {
// Header
outputLines.push("==== " + inputFile.unitName + " (" + fileErrors.length + " errors) ====");
outputLines += (newLine() + "==== " + inputFile.unitName + " (" + fileErrors.length + " errors) ====");
// Make sure we emit something for every error
let markedErrorCount = 0;
@@ -1340,7 +1389,7 @@ namespace Harness {
nextLineStart = lineStarts[lineIndex + 1];
}
// Emit this line from the original file
outputLines.push(" " + line);
outputLines += (newLine() + " " + line);
fileErrors.forEach(err => {
// Does any error start or continue on to this line? Emit squiggles
const end = ts.textSpanEnd(err);
@@ -1352,7 +1401,7 @@ namespace Harness {
// Calculate the start of the squiggle
const squiggleStart = Math.max(0, relativeOffset);
// TODO/REVIEW: this doesn't work quite right in the browser if a multi file test has files whose names are just the right length relative to one another
outputLines.push(" " + line.substr(0, squiggleStart).replace(/[^\s]/g, " ") + new Array(Math.min(length, line.length - squiggleStart) + 1).join("~"));
outputLines += (newLine() + " " + line.substr(0, squiggleStart).replace(/[^\s]/g, " ") + new Array(Math.min(length, line.length - squiggleStart) + 1).join("~"));
// If the error ended here, or we're at the end of the file, emit its message
if ((lineIndex === lines.length - 1) || nextLineStart > end) {
@@ -1368,7 +1417,10 @@ namespace Harness {
// Verify we didn't miss any errors in this file
assert.equal(markedErrorCount, fileErrors.length, "count of errors in " + inputFile.unitName);
});
yield [checkDuplicatedFileName(inputFile.unitName, dupeCase), outputLines, errorsReported];
outputLines = "";
errorsReported = 0;
}
const numLibraryDiagnostics = ts.countWhere(diagnostics, diagnostic => {
return diagnostic.file && (isDefaultLibraryFile(diagnostic.file.fileName) || isBuiltFile(diagnostic.file.fileName));
@@ -1381,23 +1433,20 @@ namespace Harness {
// Verify we didn't miss any errors in total
assert.equal(totalErrorsReportedInNonLibraryFiles + numLibraryDiagnostics + numTest262HarnessDiagnostics, diagnostics.length, "total number of errors");
return minimalDiagnosticsToString(diagnostics) +
Harness.IO.newLine() + Harness.IO.newLine() + outputLines.join("\r\n");
}
export function doErrorBaseline(baselinePath: string, inputFiles: TestFile[], errors: ts.Diagnostic[]) {
export function doErrorBaseline(baselinePath: string, inputFiles: TestFile[], errors: ts.Diagnostic[], pretty?: boolean) {
Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?$/, ".errors.txt"), (): string => {
if (!errors || (errors.length === 0)) {
/* tslint:disable:no-null-keyword */
return null;
/* tslint:enable:no-null-keyword */
}
return getErrorBaseline(inputFiles, errors);
return getErrorBaseline(inputFiles, errors, pretty);
});
}
export function doTypeAndSymbolBaseline(baselinePath: string, result: CompilerResult, allFiles: {unitName: string, content: string}[], opts?: Harness.Baseline.BaselineOptions) {
export function doTypeAndSymbolBaseline(baselinePath: string, result: CompilerResult, allFiles: {unitName: string, content: string}[], opts?: Harness.Baseline.BaselineOptions, multifile?: boolean) {
if (result.errors.length !== 0) {
return;
}
@@ -1458,24 +1507,42 @@ namespace Harness {
return;
function checkBaseLines(isSymbolBaseLine: boolean) {
const fullBaseLine = generateBaseLine(fullResults, isSymbolBaseLine);
const fullExtension = isSymbolBaseLine ? ".symbols" : ".types";
// When calling this function from rwc-runner, the baselinePath will have no extension.
// As rwc test- file is stored in json which ".json" will get stripped off.
// When calling this function from compiler-runner, the baselinePath will then has either ".ts" or ".tsx" extension
const outputFileName = ts.endsWith(baselinePath, ".ts") || ts.endsWith(baselinePath, ".tsx") ?
baselinePath.replace(/\.tsx?/, fullExtension) : baselinePath.concat(fullExtension);
Harness.Baseline.runBaseline(outputFileName, () => fullBaseLine, opts);
const outputFileName = ts.endsWith(baselinePath, ts.Extension.Ts) || ts.endsWith(baselinePath, ts.Extension.Tsx) ?
baselinePath.replace(/\.tsx?/, "") : baselinePath;
if (!multifile) {
const fullBaseLine = generateBaseLine(fullResults, isSymbolBaseLine);
Harness.Baseline.runBaseline(outputFileName + fullExtension, () => fullBaseLine, opts);
}
else {
Harness.Baseline.runMultifileBaseline(outputFileName, fullExtension, () => {
return iterateBaseLine(fullResults, isSymbolBaseLine);
}, opts);
}
}
function generateBaseLine(typeWriterResults: ts.Map<TypeWriterResult[]>, isSymbolBaseline: boolean): string {
const typeLines: string[] = [];
const typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {};
let result = "";
const gen = iterateBaseLine(typeWriterResults, isSymbolBaseline);
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
const [, content] = value;
result += content;
}
return result;
}
allFiles.forEach(file => {
function *iterateBaseLine(typeWriterResults: ts.Map<TypeWriterResult[]>, isSymbolBaseline: boolean): IterableIterator<[string, string]> {
let typeLines = "";
const typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {};
const dupeCase = ts.createMap<number>();
for (const file of allFiles) {
const codeLines = file.content.split("\n");
const key = file.unitName;
typeWriterResults.get(file.unitName).forEach(result => {
if (isSymbolBaseline && !result.symbol) {
return;
@@ -1483,42 +1550,42 @@ namespace Harness {
const typeOrSymbolString = isSymbolBaseline ? result.symbol : result.type;
const formattedLine = result.sourceText.replace(/\r?\n/g, "") + " : " + typeOrSymbolString;
if (!typeMap[file.unitName]) {
typeMap[file.unitName] = {};
if (!typeMap[key]) {
typeMap[key] = {};
}
let typeInfo = [formattedLine];
const existingTypeInfo = typeMap[file.unitName][result.line];
const existingTypeInfo = typeMap[key][result.line];
if (existingTypeInfo) {
typeInfo = existingTypeInfo.concat(typeInfo);
}
typeMap[file.unitName][result.line] = typeInfo;
typeMap[key][result.line] = typeInfo;
});
typeLines.push("=== " + file.unitName + " ===\r\n");
typeLines += "=== " + file.unitName + " ===\r\n";
for (let i = 0; i < codeLines.length; i++) {
const currentCodeLine = codeLines[i];
typeLines.push(currentCodeLine + "\r\n");
if (typeMap[file.unitName]) {
const typeInfo = typeMap[file.unitName][i];
typeLines += currentCodeLine + "\r\n";
if (typeMap[key]) {
const typeInfo = typeMap[key][i];
if (typeInfo) {
typeInfo.forEach(ty => {
typeLines.push(">" + ty + "\r\n");
typeLines += ">" + ty + "\r\n";
});
if (i + 1 < codeLines.length && (codeLines[i + 1].match(/^\s*[{|}]\s*$/) || codeLines[i + 1].trim() === "")) {
}
else {
typeLines.push("\r\n");
typeLines += "\r\n";
}
}
}
else {
typeLines.push("No type information for this code.");
typeLines += "No type information for this code.";
}
}
});
return typeLines.join("");
yield [checkDuplicatedFileName(file.unitName, dupeCase), typeLines];
typeLines = "";
}
}
}
@@ -1557,13 +1624,13 @@ namespace Harness {
}
}
export function doJsEmitBaseline(baselinePath: string, header: string, options: ts.CompilerOptions, result: CompilerResult, toBeCompiled: Harness.Compiler.TestFile[], otherFiles: Harness.Compiler.TestFile[], harnessSettings: Harness.TestCaseParser.CompilerSettings) {
export function doJsEmitBaseline(baselinePath: string, header: string, options: ts.CompilerOptions, result: CompilerResult, tsConfigFiles: Harness.Compiler.TestFile[], toBeCompiled: Harness.Compiler.TestFile[], otherFiles: Harness.Compiler.TestFile[], harnessSettings: Harness.TestCaseParser.CompilerSettings) {
if (!options.noEmit && result.files.length === 0 && result.errors.length === 0) {
throw new Error("Expected at least one js file to be emitted or at least one error to be created.");
}
// check js output
Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ".js"), () => {
Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ts.Extension.Js), () => {
let tsCode = "";
const tsSources = otherFiles.concat(toBeCompiled);
if (tsSources.length > 1) {
@@ -1586,14 +1653,15 @@ namespace Harness {
}
}
const declFileCompilationResult =
Harness.Compiler.compileDeclarationFiles(
toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined);
const declFileContext = Harness.Compiler.prepareDeclarationCompilationContext(
toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined
);
const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(declFileContext);
if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) {
jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n";
jsCode += "\r\n\r\n";
jsCode += Harness.Compiler.getErrorBaseline(declFileCompilationResult.declInputFiles.concat(declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
jsCode += Harness.Compiler.getErrorBaseline(tsConfigFiles.concat(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
}
if (jsCode.length > 0) {
@@ -1613,24 +1681,29 @@ namespace Harness {
}
export function collateOutputs(outputFiles: Harness.Compiler.GeneratedFile[]): string {
// Collect, test, and sort the fileNames
outputFiles.sort((a, b) => ts.compareStrings(cleanName(a.fileName), cleanName(b.fileName)));
const gen = iterateOutputs(outputFiles);
// Emit them
let result = "";
for (const outputFile of outputFiles) {
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
// Some extra spacing if this isn't the first file
if (result.length) {
result += "\r\n\r\n";
}
// FileName header + content
result += "/*====== " + outputFile.fileName + " ======*/\r\n";
result += outputFile.code;
const [, content] = value;
result += content;
}
return result;
}
export function *iterateOutputs(outputFiles: Harness.Compiler.GeneratedFile[]): IterableIterator<[string, string]> {
// Collect, test, and sort the fileNames
outputFiles.sort((a, b) => ts.compareStrings(cleanName(a.fileName), cleanName(b.fileName)));
const dupeCase = ts.createMap<number>();
// Yield them
for (const outputFile of outputFiles) {
yield [checkDuplicatedFileName(outputFile.fileName, dupeCase), "/*====== " + outputFile.fileName + " ======*/\r\n" + outputFile.code];
}
function cleanName(fn: string) {
const lastSlash = ts.normalizeSlashes(fn).lastIndexOf("/");
@@ -1638,6 +1711,24 @@ namespace Harness {
}
}
function checkDuplicatedFileName(resultName: string, dupeCase: ts.Map<number>): string {
resultName = sanitizeTestFilePath(resultName);
if (dupeCase.has(resultName)) {
// A different baseline filename should be manufactured if the names differ only in case, for windows compat
const count = 1 + dupeCase.get(resultName);
dupeCase.set(resultName, count);
resultName = `${resultName}.dupe${count}`;
}
else {
dupeCase.set(resultName, 0);
}
return resultName;
}
function sanitizeTestFilePath(name: string) {
return ts.normalizeSlashes(name.replace(/[\^<>:"|?*%]/g, "_")).replace(/\.\.\//g, "__dotdot/").toLowerCase();
}
// This does not need to exist strictly speaking, but many tests will need to be updated if it's removed
export function compileString(_code: string, _unitName: string, _callback: (result: CompilerResult) => void) {
// NEWTODO: Re-implement 'compileString'
@@ -1651,22 +1742,22 @@ namespace Harness {
}
export function isTS(fileName: string) {
return ts.endsWith(fileName, ".ts");
return ts.endsWith(fileName, ts.Extension.Ts);
}
export function isTSX(fileName: string) {
return ts.endsWith(fileName, ".tsx");
return ts.endsWith(fileName, ts.Extension.Tsx);
}
export function isDTS(fileName: string) {
return ts.endsWith(fileName, ".d.ts");
return ts.endsWith(fileName, ts.Extension.Dts);
}
export function isJS(fileName: string) {
return ts.endsWith(fileName, ".js");
return ts.endsWith(fileName, ts.Extension.Js);
}
export function isJSX(fileName: string) {
return ts.endsWith(fileName, ".jsx");
return ts.endsWith(fileName, ts.Extension.Jsx);
}
export function isJSMap(fileName: string) {
@@ -1744,7 +1835,12 @@ namespace Harness {
}
/** Given a test file containing // @FileName directives, return an array of named units of code to be added to an existing compiler instance */
export function makeUnitsFromTest(code: string, fileName: string, rootDir?: string): { settings: CompilerSettings; testUnitData: TestUnitData[]; tsConfig: ts.ParsedCommandLine } {
export function makeUnitsFromTest(code: string, fileName: string, rootDir?: string): {
settings: CompilerSettings;
testUnitData: TestUnitData[];
tsConfig: ts.ParsedCommandLine;
tsConfigFileUnitData: TestUnitData;
} {
const settings = extractCompilerSettings(code);
// List of all the subfiles we've parsed out
@@ -1830,17 +1926,19 @@ namespace Harness {
// check if project has tsconfig.json in the list of files
let tsConfig: ts.ParsedCommandLine;
let tsConfigFileUnitData: TestUnitData;
for (let i = 0; i < testUnitData.length; i++) {
const data = testUnitData[i];
if (ts.getBaseFileName(data.name).toLowerCase() === "tsconfig.json") {
const configJson = ts.parseConfigFileTextToJson(data.name, data.content);
assert.isTrue(configJson.config !== undefined);
const configJson = ts.parseJsonText(data.name, data.content);
assert.isTrue(configJson.endOfFileToken !== undefined);
let baseDir = ts.normalizePath(ts.getDirectoryPath(data.name));
if (rootDir) {
baseDir = ts.getNormalizedAbsolutePath(baseDir, rootDir);
}
tsConfig = ts.parseJsonConfigFileContent(configJson.config, parseConfigHost, baseDir);
tsConfig = ts.parseJsonSourceFileConfigFileContent(configJson, parseConfigHost, baseDir);
tsConfig.options.configFilePath = data.name;
tsConfigFileUnitData = data;
// delete entry from the list
ts.orderedRemoveItemAt(testUnitData, i);
@@ -1848,7 +1946,7 @@ namespace Harness {
break;
}
}
return { settings, testUnitData, tsConfig };
return { settings, testUnitData, tsConfig, tsConfigFileUnitData };
}
}
@@ -1956,7 +2054,7 @@ namespace Harness {
IO.writeFile(actualFileName + ".delete", "");
}
else {
IO.writeFile(actualFileName, actual);
IO.writeFile(actualFileName, encoded_actual);
}
throw new Error(`The baseline file ${relativeFileName} has changed.`);
}
@@ -1968,12 +2066,71 @@ namespace Harness {
const comparison = compareToBaseline(actual, relativeFileName, opts);
writeComparison(comparison.expected, comparison.actual, relativeFileName, actualFileName);
}
export function runMultifileBaseline(relativeFileBase: string, extension: string, generateContent: () => IterableIterator<[string, string, number]> | IterableIterator<[string, string]>, opts?: BaselineOptions, referencedExtensions?: string[]): void {
const gen = generateContent();
const writtenFiles = ts.createMap<true>();
const canonicalize = ts.createGetCanonicalFileName(/*caseSensitive*/ false); // This is done so tests work on windows _and_ linux
/* tslint:disable-next-line:no-null-keyword */
const errors: Error[] = [];
if (gen !== null) {
for (let {done, value} = gen.next(); !done; { done, value } = gen.next()) {
const [name, content, count] = value as [string, string, number | undefined];
if (count === 0) continue; // Allow error reporter to skip writing files without errors
const relativeFileName = relativeFileBase + (ts.startsWith(name, "/") ? "" : "/") + name + extension;
const actualFileName = localPath(relativeFileName, opts && opts.Baselinefolder, opts && opts.Subfolder);
const comparison = compareToBaseline(content, relativeFileName, opts);
try {
writeComparison(comparison.expected, comparison.actual, relativeFileName, actualFileName);
}
catch (e) {
errors.push(e);
}
const path = ts.toPath(relativeFileName, "", canonicalize);
writtenFiles.set(path, true);
}
}
const referenceDir = referencePath(relativeFileBase, opts && opts.Baselinefolder, opts && opts.Subfolder);
let existing = Harness.IO.readDirectory(referenceDir, referencedExtensions || [extension]);
if (extension === ".ts" || referencedExtensions && referencedExtensions.indexOf(".ts") > -1 && referencedExtensions.indexOf(".d.ts") === -1) {
// special-case and filter .d.ts out of .ts results
existing = existing.filter(f => !ts.endsWith(f, ".d.ts"));
}
const missing: string[] = [];
for (const name of existing) {
const localCopy = name.substring(referenceDir.length - relativeFileBase.length);
const path = ts.toPath(localCopy, "", canonicalize);
if (!writtenFiles.has(path)) {
missing.push(localCopy);
}
}
if (missing.length) {
for (const file of missing) {
IO.writeFile(localPath(file + ".delete", opts && opts.Baselinefolder, opts && opts.Subfolder), "");
}
}
if (errors.length || missing.length) {
let errorMsg = "";
if (errors.length) {
errorMsg += `The baseline for ${relativeFileBase} has changed:${"\n " + errors.map(e => e.message).join("\n ")}`;
}
if (errors.length && missing.length) {
errorMsg += "\n";
}
if (missing.length) {
errorMsg += `Baseline missing files:${"\n " + missing.join("\n ") + "\n"}Written:${"\n " + ts.arrayFrom(writtenFiles.keys()).join("\n ")}`;
}
throw new Error(errorMsg);
}
}
}
export function isDefaultLibraryFile(filePath: string): boolean {
// We need to make sure that the filePath is prefixed with "lib." not just containing "lib." and end with ".d.ts"
const fileName = ts.getBaseFileName(ts.normalizeSlashes(filePath));
return ts.startsWith(fileName, "lib.") && ts.endsWith(fileName, ".d.ts");
return ts.startsWith(fileName, "lib.") && ts.endsWith(fileName, ts.Extension.Dts);
}
export function isBuiltFile(filePath: string): boolean {
+21 -22
View File
@@ -108,7 +108,7 @@ namespace Harness.LanguageService {
}
class DefaultHostCancellationToken implements ts.HostCancellationToken {
public static Instance = new DefaultHostCancellationToken();
public static readonly Instance = new DefaultHostCancellationToken();
public isCancellationRequested() {
return false;
@@ -130,7 +130,7 @@ namespace Harness.LanguageService {
}
public getNewLine(): string {
return "\r\n";
return harnessNewLine;
}
public getFilenames(): string[] {
@@ -193,7 +193,9 @@ namespace Harness.LanguageService {
}
getCurrentDirectory(): string { return virtualFileSystemRoot; }
getDefaultLibFileName(): string { return Harness.Compiler.defaultLibFileName; }
getScriptFileNames(): string[] { return this.getFilenames(); }
getScriptFileNames(): string[] {
return this.getFilenames().filter(ts.isAnySupportedFileExtension);
}
getScriptSnapshot(fileName: string): ts.IScriptSnapshot {
const script = this.getScriptInfo(fileName);
return script ? new ScriptSnapshot(script) : undefined;
@@ -208,13 +210,14 @@ namespace Harness.LanguageService {
const script = this.getScriptSnapshot(fileName);
return script !== undefined;
}
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[] {
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[] {
return ts.matchFiles(path, extensions, exclude, include,
/*useCaseSensitiveFileNames*/ false,
this.getCurrentDirectory(),
depth,
(p) => this.virtualFileSystem.getAccessibleFileSystemEntries(p));
}
readFile(path: string): string {
readFile(path: string): string | undefined {
const snapshot = this.getScriptSnapshot(path);
return snapshot.getText(0, snapshot.getLength());
}
@@ -312,9 +315,7 @@ namespace Harness.LanguageService {
getScriptVersion(fileName: string): string { return this.nativeHost.getScriptVersion(fileName); }
getLocalizedDiagnosticMessages(): string { return JSON.stringify({}); }
readDirectory(_rootDir: string, _extension: string): string {
return ts.notImplemented();
}
readDirectory = ts.notImplemented;
readDirectoryNames = ts.notImplemented;
readFileNames = ts.notImplemented;
fileExists(fileName: string) { return this.getScriptInfo(fileName) !== undefined; }
@@ -486,6 +487,9 @@ namespace Harness.LanguageService {
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean {
return unwrapJSONCallResult(this.shim.isValidBraceCompletionAtPosition(fileName, position, openingBrace));
}
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): ts.TextSpan {
return unwrapJSONCallResult(this.shim.getSpanOfEnclosingComment(fileName, position, onlyMultiLine));
}
getCodeFixesAtPosition(): ts.CodeAction[] {
throw new Error("Not supported on the shim.");
}
@@ -620,7 +624,7 @@ namespace Harness.LanguageService {
this.writeMessage(message);
}
readFile(fileName: string): string {
readFile(fileName: string): string | undefined {
if (fileName.indexOf(Harness.Compiler.defaultLibFileName) >= 0) {
fileName = Harness.Compiler.defaultLibFileName;
}
@@ -668,9 +672,7 @@ namespace Harness.LanguageService {
return ts.sys.getEnvironmentVariable(name);
}
readDirectory(_path: string, _extension?: string[], _exclude?: string[], _include?: string[]): string[] {
return ts.notImplemented();
}
readDirectory() { return ts.notImplemented(); }
watchFile(): ts.FileWatcher {
return { close: ts.noop };
@@ -684,11 +686,11 @@ namespace Harness.LanguageService {
}
info(message: string): void {
return this.host.log(message);
this.host.log(message);
}
msg(message: string) {
return this.host.log(message);
msg(message: string): void {
this.host.log(message);
}
loggingEnabled() {
@@ -703,17 +705,13 @@ namespace Harness.LanguageService {
return false;
}
endGroup(): void {
}
startGroup() { throw ts.notImplemented(); }
endGroup() { throw ts.notImplemented(); }
perftrc(message: string): void {
return this.host.log(message);
}
startGroup(): void {
}
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any {
return setTimeout(callback, ms, args);
}
@@ -798,7 +796,7 @@ namespace Harness.LanguageService {
default:
return {
module: undefined,
error: "Could not resolve module"
error: new Error("Could not resolve module")
};
}
@@ -831,6 +829,7 @@ namespace Harness.LanguageService {
host: serverHost,
cancellationToken: ts.server.nullCancellationToken,
useSingleInferredProject: false,
useInferredProjectPerProjectRoot: false,
typingsInstaller: undefined,
byteLength: Utils.byteLength,
hrtime: process.hrtime,
+5 -3
View File
@@ -1,5 +1,5 @@
const fs: any = require("fs");
const path: any = require("path");
import fs = require("fs");
import path = require("path");
function instrumentForRecording(fn: string, tscPath: string) {
instrument(tscPath, `
@@ -38,7 +38,9 @@ function instrument(tscPath: string, prepareCode: string, cleanupCode = "") {
const index2 = index1 + invocationLine.length;
const newContent = tscContent.substr(0, index1) + loggerContent + prepareCode + invocationLine + cleanupCode + tscContent.substr(index2) + "\r\n";
fs.writeFile(tscPath, newContent);
fs.writeFile(tscPath, newContent, err => {
if (err) throw err;
});
});
});
});
+17 -9
View File
@@ -64,11 +64,13 @@ interface IOLog {
}[];
directoriesRead: {
path: string,
extensions: string[],
exclude: string[],
include: string[],
result: string[]
extensions: ReadonlyArray<string>,
exclude: ReadonlyArray<string>,
include: ReadonlyArray<string>,
depth: number,
result: ReadonlyArray<string>,
}[];
useCaseSensitiveFileNames?: boolean;
}
interface PlaybackControl {
@@ -150,7 +152,7 @@ namespace Playback {
wrapper.startRecord = (fileNameBase) => {
recordLogFileNameBase = fileNameBase;
recordLog = createEmptyLog();
recordLog.useCaseSensitiveFileNames = typeof underlying.useCaseSensitiveFileNames === "function" ? underlying.useCaseSensitiveFileNames() : underlying.useCaseSensitiveFileNames;
if (typeof underlying.args !== "function") {
recordLog.arguments = underlying.args;
}
@@ -220,10 +222,9 @@ namespace Playback {
memoize(path => findFileByPath(replayLog.filesRead, path, /*throwFileNotFoundError*/ true).contents));
wrapper.readDirectory = recordReplay(wrapper.readDirectory, underlying)(
(path, extensions, exclude, include) => {
const result = (<ts.System>underlying).readDirectory(path, extensions, exclude, include);
const logEntry = { path, extensions, exclude, include, result };
recordLog.directoriesRead.push(logEntry);
(path, extensions, exclude, include, depth) => {
const result = (<ts.System>underlying).readDirectory(path, extensions, exclude, include, depth);
recordLog.directoriesRead.push({ path, extensions, exclude, include, depth, result });
return result;
},
path => {
@@ -249,6 +250,13 @@ namespace Playback {
}
underlying.exit(exitCode);
};
wrapper.useCaseSensitiveFileNames = () => {
if (replayLog !== undefined) {
return !!replayLog.useCaseSensitiveFileNames;
}
return typeof underlying.useCaseSensitiveFileNames === "function" ? underlying.useCaseSensitiveFileNames() : underlying.useCaseSensitiveFileNames;
};
}
function recordReplay<T extends Function>(original: T, underlying: any) {
+472
View File
@@ -0,0 +1,472 @@
if (typeof describe === "undefined") {
(global as any).describe = undefined; // If launched without mocha for parallel mode, we still need a global describe visible to satisfy the parsing of the unit tests
(global as any).it = undefined;
}
namespace Harness.Parallel.Host {
interface ChildProcessPartial {
send(message: ParallelHostMessage, callback?: (error: Error) => void): boolean;
on(event: "error", listener: (err: Error) => void): this;
on(event: "exit", listener: (code: number, signal: string) => void): this;
on(event: "message", listener: (message: ParallelClientMessage) => void): this;
}
interface ProgressBarsOptions {
open: string;
close: string;
complete: string;
incomplete: string;
width: number;
noColors: boolean;
}
interface ProgressBar {
lastN?: number;
title?: string;
progressColor?: string;
text?: string;
}
const perfdataFileName = ".parallelperf.json";
function readSavedPerfData(): {[testHash: string]: number} {
const perfDataContents = Harness.IO.readFile(perfdataFileName);
if (perfDataContents) {
return JSON.parse(perfDataContents);
}
return undefined;
}
function hashName(runner: TestRunnerKind, test: string) {
return `tsrunner-${runner}://${test}`;
}
export function start() {
initializeProgressBarsDependencies();
console.log("Discovering tests...");
const discoverStart = +(new Date());
const { statSync }: { statSync(path: string): { size: number }; } = require("fs");
const tasks: { runner: TestRunnerKind, file: string, size: number }[] = [];
const perfData = readSavedPerfData();
let totalCost = 0;
let unknownValue: string | undefined;
for (const runner of runners) {
const files = runner.enumerateTestFiles();
for (const file of files) {
let size: number;
if (!perfData) {
size = statSync(file).size;
}
else {
const hashedName = hashName(runner.kind(), file);
size = perfData[hashedName];
if (size === undefined) {
size = Number.MAX_SAFE_INTEGER;
unknownValue = hashedName;
}
}
tasks.push({ runner: runner.kind(), file, size });
totalCost += size;
}
}
tasks.sort((a, b) => a.size - b.size);
// 1 fewer batches than threads to account for unittests running on the final thread
const batchCount = runners.length === 1 ? workerCount : workerCount - 1;
const packfraction = 0.9;
const chunkSize = 1000; // ~1KB or 1s for sending batches near the end of a test
const batchSize = (totalCost / workerCount) * packfraction; // Keep spare tests for unittest thread in reserve
console.log(`Discovered ${tasks.length} test files in ${+(new Date()) - discoverStart}ms.`);
console.log(`Starting to run tests using ${workerCount} threads...`);
const { fork }: { fork(modulePath: string, args?: string[], options?: {}): ChildProcessPartial; } = require("child_process");
const totalFiles = tasks.length;
let passingFiles = 0;
let failingFiles = 0;
let errorResults: ErrorInfo[] = [];
let totalPassing = 0;
const startTime = Date.now();
const progressBars = new ProgressBars({ noColors });
const progressUpdateInterval = 1 / progressBars._options.width;
let nextProgress = progressUpdateInterval;
const newPerfData: {[testHash: string]: number} = {};
const workers: ChildProcessPartial[] = [];
let closedWorkers = 0;
for (let i = 0; i < workerCount; i++) {
// TODO: Just send the config over the IPC channel or in the command line arguments
const config: TestConfig = { light: Harness.lightMode, listenForWork: true, runUnitTests: runners.length === 1 ? false : i === workerCount - 1 };
const configPath = ts.combinePaths(taskConfigsFolder, `task-config${i}.json`);
Harness.IO.writeFile(configPath, JSON.stringify(config));
const child = fork(__filename, [`--config="${configPath}"`]);
child.on("error", err => {
console.error("Unexpected error in child process:");
console.error(err);
return process.exit(2);
});
child.on("exit", (code, _signal) => {
if (code !== 0) {
console.error("Test worker process exited with nonzero exit code!");
return process.exit(2);
}
});
child.on("message", (data: ParallelClientMessage) => {
switch (data.type) {
case "error": {
console.error(`Test worker encounted unexpected error and was forced to close:
Message: ${data.payload.error}
Stack: ${data.payload.stack}`);
return process.exit(2);
}
case "progress":
case "result": {
totalPassing += data.payload.passing;
if (data.payload.errors.length) {
errorResults = errorResults.concat(data.payload.errors);
failingFiles++;
}
else {
passingFiles++;
}
newPerfData[hashName(data.payload.runner, data.payload.file)] = data.payload.duration;
const progress = (failingFiles + passingFiles) / totalFiles;
if (progress >= nextProgress) {
while (nextProgress < progress) {
nextProgress += progressUpdateInterval;
}
updateProgress(progress, errorResults.length ? `${errorResults.length} failing` : `${totalPassing} passing`, errorResults.length ? "fail" : undefined);
}
if (data.type === "result") {
if (tasks.length === 0) {
// No more tasks to distribute
child.send({ type: "close" });
closedWorkers++;
if (closedWorkers === workerCount) {
outputFinalResult();
}
return;
}
// Send tasks in blocks if the tasks are small
const taskList = [tasks.pop()];
while (tasks.length && taskList.reduce((p, c) => p + c.size, 0) < chunkSize) {
taskList.push(tasks.pop());
}
if (taskList.length === 1) {
child.send({ type: "test", payload: taskList[0] });
}
else {
child.send({ type: "batch", payload: taskList });
}
}
}
}
});
workers.push(child);
}
// It's only really worth doing an initial batching if there are a ton of files to go through
if (totalFiles > 1000) {
console.log("Batching initial test lists...");
const batches: { runner: TestRunnerKind, file: string, size: number }[][] = new Array(batchCount);
const doneBatching = new Array(batchCount);
let scheduledTotal = 0;
batcher: while (true) {
for (let i = 0; i < batchCount; i++) {
if (tasks.length === 0) {
console.log(`Suboptimal packing detected: no tests remain to be stolen. Reduce packing fraction from ${packfraction} to fix.`);
break batcher;
}
if (doneBatching[i]) {
continue;
}
if (!batches[i]) {
batches[i] = [];
}
const total = batches[i].reduce((p, c) => p + c.size, 0);
if (total >= batchSize) {
doneBatching[i] = true;
continue;
}
const task = tasks.pop();
batches[i].push(task);
scheduledTotal += task.size;
}
for (let j = 0; j < batchCount; j++) {
if (!doneBatching[j]) {
continue batcher;
}
}
break;
}
const prefix = `Batched into ${batchCount} groups`;
if (unknownValue) {
console.log(`${prefix}. Unprofiled tests including ${unknownValue} will be run first.`);
}
else {
console.log(`${prefix} with approximate total ${perfData ? "time" : "file sizes"} of ${perfData ? ms(batchSize) : `${Math.floor(batchSize)} bytes`} in each group. (${(scheduledTotal / totalCost * 100).toFixed(1)}% of total tests batched)`);
}
for (const worker of workers) {
const payload = batches.pop();
if (payload) {
worker.send({ type: "batch", payload });
}
else { // Unittest thread - send off just one test
worker.send({ type: "test", payload: tasks.pop() });
}
}
}
else {
for (let i = 0; i < workerCount; i++) {
workers[i].send({ type: "test", payload: tasks.pop() });
}
}
progressBars.enable();
updateProgress(0);
let duration: number;
function completeBar() {
const isPartitionFail = failingFiles !== 0;
const summaryColor = isPartitionFail ? "fail" : "green";
const summarySymbol = isPartitionFail ? Base.symbols.err : Base.symbols.ok;
const summaryTests = (isPartitionFail ? totalPassing + "/" + (errorResults.length + totalPassing) : totalPassing) + " passing";
const summaryDuration = "(" + ms(duration) + ")";
const savedUseColors = Base.useColors;
Base.useColors = !noColors;
const summary = color(summaryColor, summarySymbol + " " + summaryTests) + " " + color("light", summaryDuration);
Base.useColors = savedUseColors;
updateProgress(1, summary);
}
function updateProgress(percentComplete: number, title?: string, titleColor?: string) {
let progressColor = "pending";
if (failingFiles) {
progressColor = "fail";
}
progressBars.update(
0,
percentComplete,
progressColor,
title,
titleColor
);
}
function outputFinalResult() {
duration = Date.now() - startTime;
completeBar();
progressBars.disable();
const reporter = new Base();
const stats = reporter.stats;
const failures = reporter.failures;
stats.passes = totalPassing;
stats.failures = errorResults.length;
stats.tests = totalPassing + errorResults.length;
stats.duration = duration;
for (let j = 0; j < errorResults.length; j++) {
const failure = errorResults[j];
failures.push(makeMochaTest(failure));
}
if (noColors) {
const savedUseColors = Base.useColors;
Base.useColors = false;
reporter.epilogue();
Base.useColors = savedUseColors;
}
else {
reporter.epilogue();
}
Harness.IO.writeFile(perfdataFileName, JSON.stringify(newPerfData, null, 4)); // tslint:disable-line:no-null-keyword
process.exit(errorResults.length);
}
function makeMochaTest(test: ErrorInfo) {
return {
fullTitle: () => {
return test.name;
},
err: {
message: test.error,
stack: test.stack
}
};
}
describe = ts.noop as any; // Disable unit tests
return;
}
let Mocha: any;
let Base: any;
let color: any;
let cursor: any;
let readline: any;
let os: any;
let tty: { isatty(x: number): boolean };
let isatty: boolean;
const s = 1000;
const m = s * 60;
const h = m * 60;
const d = h * 24;
function ms(ms: number) {
let result = "";
if (ms >= d) {
const count = Math.floor(ms / d);
result += count + "d";
ms -= count * d;
}
if (ms >= h) {
const count = Math.floor(ms / h);
result += count + "h";
ms -= count * h;
}
if (ms >= m) {
const count = Math.floor(ms / m);
result += count + "m";
ms -= count * m;
}
if (ms >= s) {
const count = Math.round(ms / s);
result += count + "s";
return result;
}
if (ms > 0) {
result += Math.round(ms) + "ms";
}
return result;
}
function initializeProgressBarsDependencies() {
Mocha = require("mocha");
Base = Mocha.reporters.Base;
color = Base.color;
cursor = Base.cursor;
readline = require("readline");
os = require("os");
tty = require("tty");
isatty = tty.isatty(1) && tty.isatty(2);
}
class ProgressBars {
public readonly _options: Readonly<ProgressBarsOptions>;
private _enabled: boolean;
private _lineCount: number;
private _progressBars: ProgressBar[];
constructor(options?: Partial<ProgressBarsOptions>) {
if (!options) options = {};
const open = options.open || "[";
const close = options.close || "]";
const complete = options.complete || "▬";
const incomplete = options.incomplete || Base.symbols.dot;
const maxWidth = Base.window.width - open.length - close.length - 34;
const width = minMax(options.width || maxWidth, 10, maxWidth);
this._options = {
open,
complete,
incomplete,
close,
width,
noColors: options.noColors || false
};
this._progressBars = [];
this._lineCount = 0;
this._enabled = false;
}
enable() {
if (!this._enabled) {
process.stdout.write(os.EOL);
this._enabled = true;
}
}
disable() {
if (this._enabled) {
process.stdout.write(os.EOL);
this._enabled = false;
}
}
update(index: number, percentComplete: number, color: string, title: string, titleColor?: string) {
percentComplete = minMax(percentComplete, 0, 1);
const progressBar = this._progressBars[index] || (this._progressBars[index] = { });
const width = this._options.width;
const n = Math.floor(width * percentComplete);
const i = width - n;
if (n === progressBar.lastN && title === progressBar.title && color === progressBar.progressColor) {
return;
}
progressBar.lastN = n;
progressBar.title = title;
progressBar.progressColor = color;
let progress = " ";
progress += this._color("progress", this._options.open);
progress += this._color(color, fill(this._options.complete, n));
progress += this._color("progress", fill(this._options.incomplete, i));
progress += this._color("progress", this._options.close);
if (title) {
progress += this._color(titleColor || "progress", " " + title);
}
if (progressBar.text !== progress) {
progressBar.text = progress;
this._render(index);
}
}
private _render(index: number) {
if (!this._enabled || !isatty) {
return;
}
cursor.hide();
readline.moveCursor(process.stdout, -process.stdout.columns, -this._lineCount);
let lineCount = 0;
const numProgressBars = this._progressBars.length;
for (let i = 0; i < numProgressBars; i++) {
if (i === index) {
readline.clearLine(process.stdout, 1);
process.stdout.write(this._progressBars[i].text + os.EOL);
}
else {
readline.moveCursor(process.stdout, -process.stdout.columns, +1);
}
lineCount++;
}
this._lineCount = lineCount;
cursor.show();
}
private _color(type: string, text: string) {
return type && !this._options.noColors ? color(type, text) : text;
}
}
function fill(ch: string, size: number) {
let s = "";
while (s.length < size) {
s += ch;
}
return s.length > size ? s.substr(0, size) : s;
}
function minMax(value: number, min: number, max: number) {
if (value < min) return min;
if (value > max) return max;
return value;
}
}
+14
View File
@@ -0,0 +1,14 @@
/// <reference path="./host.ts" />
/// <reference path="./worker.ts" />
namespace Harness.Parallel {
export type ParallelTestMessage = { type: "test", payload: { runner: TestRunnerKind, file: string } } | never;
export type ParallelBatchMessage = { type: "batch", payload: ParallelTestMessage["payload"][] } | never;
export type ParallelCloseMessage = { type: "close" } | never;
export type ParallelHostMessage = ParallelTestMessage | ParallelCloseMessage | ParallelBatchMessage;
export type ParallelErrorMessage = { type: "error", payload: { error: string, stack: string } } | never;
export type ErrorInfo = ParallelErrorMessage["payload"] & { name: string };
export type ParallelResultMessage = { type: "result", payload: { passing: number, errors: ErrorInfo[], duration: number, runner: TestRunnerKind, file: string } } | never;
export type ParallelBatchProgressMessage = { type: "progress", payload: ParallelResultMessage["payload"] } | never;
export type ParallelClientMessage = ParallelErrorMessage | ParallelResultMessage | ParallelBatchProgressMessage;
}
+202
View File
@@ -0,0 +1,202 @@
namespace Harness.Parallel.Worker {
let errors: ErrorInfo[] = [];
let passing = 0;
let reportedUnitTests = false;
type Executor = {name: string, callback: Function, kind: "suite" | "test"} | never;
function resetShimHarnessAndExecute(runner: RunnerBase) {
if (reportedUnitTests) {
errors = [];
passing = 0;
testList.length = 0;
}
reportedUnitTests = true;
const start = +(new Date());
runner.initializeTests();
testList.forEach(({ name, callback, kind }) => executeCallback(name, callback, kind));
return { errors, passing, duration: +(new Date()) - start };
}
let beforeEachFunc: Function;
const namestack: string[] = [];
let testList: Executor[] = [];
function shimMochaHarness() {
(global as any).before = undefined;
(global as any).after = undefined;
(global as any).beforeEach = undefined;
describe = ((name, callback) => {
testList.push({ name, callback, kind: "suite" });
}) as Mocha.IContextDefinition;
it = ((name, callback) => {
if (!testList) {
throw new Error("Tests must occur within a describe block");
}
testList.push({ name, callback, kind: "test" });
}) as Mocha.ITestDefinition;
}
function executeSuiteCallback(name: string, callback: Function) {
const fakeContext: Mocha.ISuiteCallbackContext = {
retries() { return this; },
slow() { return this; },
timeout() { return this; },
};
namestack.push(name);
let beforeFunc: Function;
(before as any) = (cb: Function) => beforeFunc = cb;
let afterFunc: Function;
(after as any) = (cb: Function) => afterFunc = cb;
const savedBeforeEach = beforeEachFunc;
(beforeEach as any) = (cb: Function) => beforeEachFunc = cb;
const savedTestList = testList;
testList = [];
callback.call(fakeContext);
beforeFunc && beforeFunc();
beforeFunc = undefined;
testList.forEach(({ name, callback, kind }) => executeCallback(name, callback, kind));
testList.length = 0;
testList = savedTestList;
afterFunc && afterFunc();
afterFunc = undefined;
beforeEachFunc = savedBeforeEach;
namestack.pop();
}
function executeCallback(name: string, callback: Function, kind: "suite" | "test") {
if (kind === "suite") {
executeSuiteCallback(name, callback);
}
else {
executeTestCallback(name, callback);
}
}
function executeTestCallback(name: string, callback: Function) {
const fakeContext: Mocha.ITestCallbackContext = {
skip() { return this; },
timeout() { return this; },
retries() { return this; },
slow() { return this; },
};
name = [...namestack, name].join(" ");
if (beforeEachFunc) {
try {
beforeEachFunc();
}
catch (error) {
errors.push({ error: error.message, stack: error.stack, name });
return;
}
}
if (callback.length === 0) {
try {
// TODO: If we ever start using async test completions, polyfill promise return handling
callback.call(fakeContext);
}
catch (error) {
errors.push({ error: error.message, stack: error.stack, name });
return;
}
passing++;
}
else {
// Uses `done` callback
let completed = false;
try {
callback.call(fakeContext, (err: any) => {
if (completed) {
throw new Error(`done() callback called multiple times; ensure it is only called once.`);
}
if (err) {
errors.push({ error: err.toString(), stack: "", name });
}
else {
passing++;
}
completed = true;
});
}
catch (error) {
errors.push({ error: error.message, stack: error.stack, name });
return;
}
if (!completed) {
errors.push({ error: "Test completes asynchronously, which is unsupported by the parallel harness", stack: "", name });
}
}
}
export function start() {
let initialized = false;
const runners = ts.createMap<RunnerBase>();
process.on("message", (data: ParallelHostMessage) => {
if (!initialized) {
initialized = true;
shimMochaHarness();
}
switch (data.type) {
case "test":
const { runner, file } = data.payload;
if (!runner) {
console.error(data);
}
const message: ParallelResultMessage = { type: "result", payload: handleTest(runner, file) };
process.send(message);
break;
case "close":
process.exit(0);
break;
case "batch": {
const items = data.payload;
for (let i = 0; i < items.length; i++) {
const { runner, file } = items[i];
if (!runner) {
console.error(data);
}
let message: ParallelBatchProgressMessage | ParallelResultMessage;
const payload = handleTest(runner, file);
if (i === (items.length - 1)) {
message = { type: "result", payload };
}
else {
message = { type: "progress", payload };
}
process.send(message);
}
break;
}
}
});
process.on("uncaughtException", error => {
const message: ParallelErrorMessage = { type: "error", payload: { error: error.message, stack: error.stack } };
try {
process.send(message);
}
catch (e) {
console.error(error);
throw error;
}
});
if (!runUnitTests) {
// ensure unit tests do not get run
describe = ts.noop as any;
}
else {
initialized = true;
shimMochaHarness();
}
function handleTest(runner: TestRunnerKind, file: string) {
if (!runners.has(runner)) {
runners.set(runner, createRunner(runner));
}
const instance = runners.get(runner);
instance.tests = [file];
return { ...resetShimHarnessAndExecute(instance), runner, file };
}
}
}
+44 -45
View File
@@ -5,7 +5,7 @@
interface ProjectRunnerTestCase {
scenario: string;
projectRoot: string; // project where it lives - this also is the current directory when compiling
inputFiles: string[]; // list of input files to be given to program
inputFiles: ReadonlyArray<string>; // list of input files to be given to program
resolveMapRoot?: boolean; // should we resolve this map root and give compiler the absolute disk path as map root?
resolveSourceRoot?: boolean; // should we resolve this source root and give compiler the absolute disk path as map root?
baselineCheck?: boolean; // Verify the baselines of output files, if this is false, we will write to output to the disk but there is no verification of baselines
@@ -15,8 +15,8 @@ interface ProjectRunnerTestCase {
interface ProjectRunnerTestCaseResolutionInfo extends ProjectRunnerTestCase {
// Apart from actual test case the results of the resolution
resolvedInputFiles: string[]; // List of files that were asked to read by compiler
emittedFiles: string[]; // List of files that were emitted by the compiler
resolvedInputFiles: ReadonlyArray<string>; // List of files that were asked to read by compiler
emittedFiles: ReadonlyArray<string>; // List of files that were emitted by the compiler
}
interface BatchCompileProjectTestCaseEmittedFile extends Harness.Compiler.GeneratedFile {
@@ -24,11 +24,12 @@ interface BatchCompileProjectTestCaseEmittedFile extends Harness.Compiler.Genera
}
interface CompileProjectFilesResult {
configFileSourceFiles: ReadonlyArray<ts.SourceFile>;
moduleKind: ts.ModuleKind;
program?: ts.Program;
compilerOptions?: ts.CompilerOptions;
errors: ts.Diagnostic[];
sourceMapData?: ts.SourceMapData[];
errors: ReadonlyArray<ts.Diagnostic>;
sourceMapData?: ReadonlyArray<ts.SourceMapData>;
}
interface BatchCompileProjectTestCaseResult extends CompileProjectFilesResult {
@@ -124,16 +125,17 @@ class ProjectRunner extends RunnerBase {
return Harness.IO.resolvePath(testCase.projectRoot);
}
function compileProjectFiles(moduleKind: ts.ModuleKind, getInputFiles: () => string[],
function compileProjectFiles(moduleKind: ts.ModuleKind, configFileSourceFiles: ReadonlyArray<ts.SourceFile>,
getInputFiles: () => ReadonlyArray<string>,
getSourceFileTextImpl: (fileName: string) => string,
writeFile: (fileName: string, data: string, writeByteOrderMark: boolean) => void,
compilerOptions: ts.CompilerOptions): CompileProjectFilesResult {
const program = ts.createProgram(getInputFiles(), compilerOptions, createCompilerHost());
let errors = ts.getPreEmitDiagnostics(program);
const errors = ts.getPreEmitDiagnostics(program);
const emitResult = program.emit();
errors = ts.concatenate(errors, emitResult.diagnostics);
ts.addRange(errors, emitResult.diagnostics);
const sourceMapData = emitResult.sourceMaps;
// Clean up source map data that will be used in baselining
@@ -148,6 +150,7 @@ class ProjectRunner extends RunnerBase {
}
return {
configFileSourceFiles,
moduleKind,
program,
errors,
@@ -196,6 +199,7 @@ class ProjectRunner extends RunnerBase {
const outputFiles: BatchCompileProjectTestCaseEmittedFile[] = [];
let inputFiles = testCase.inputFiles;
let compilerOptions = createCompilerOptions();
const configFileSourceFiles: ts.SourceFile[] = [];
let configFileName: string;
if (compilerOptions.project) {
@@ -207,41 +211,31 @@ class ProjectRunner extends RunnerBase {
configFileName = ts.findConfigFile("", fileExists);
}
let errors: ts.Diagnostic[];
if (configFileName) {
const result = ts.readConfigFile(configFileName, getSourceFileText);
if (result.error) {
return {
moduleKind,
errors: [result.error]
};
}
const configObject = result.config;
const result = ts.readJsonConfigFile(configFileName, getSourceFileText);
configFileSourceFiles.push(result);
const configParseHost: ts.ParseConfigHost = {
useCaseSensitiveFileNames: Harness.IO.useCaseSensitiveFileNames(),
fileExists,
readDirectory,
readFile
};
const configParseResult = ts.parseJsonConfigFileContent(configObject, configParseHost, ts.getDirectoryPath(configFileName), compilerOptions);
if (configParseResult.errors.length > 0) {
return {
moduleKind,
errors: configParseResult.errors
};
}
const configParseResult = ts.parseJsonSourceFileConfigFileContent(result, configParseHost, ts.getDirectoryPath(configFileName), compilerOptions);
inputFiles = configParseResult.fileNames;
compilerOptions = configParseResult.options;
errors = result.parseDiagnostics.concat(configParseResult.errors);
}
const projectCompilerResult = compileProjectFiles(moduleKind, () => inputFiles, getSourceFileText, writeFile, compilerOptions);
const projectCompilerResult = compileProjectFiles(moduleKind, configFileSourceFiles, () => inputFiles, getSourceFileText, writeFile, compilerOptions);
return {
configFileSourceFiles,
moduleKind,
program: projectCompilerResult.program,
compilerOptions,
sourceMapData: projectCompilerResult.sourceMapData,
outputFiles,
errors: projectCompilerResult.errors,
errors: errors ? ts.concatenate(errors, projectCompilerResult.errors) : projectCompilerResult.errors,
};
function createCompilerOptions() {
@@ -281,8 +275,8 @@ class ProjectRunner extends RunnerBase {
: ts.normalizeSlashes(testCase.projectRoot) + "/" + ts.normalizeSlashes(fileName);
}
function readDirectory(rootDir: string, extension: string[], exclude: string[], include: string[]): string[] {
const harnessReadDirectoryResult = Harness.IO.readDirectory(getFileNameInTheProjectTest(rootDir), extension, exclude, include);
function readDirectory(rootDir: string, extension: string[], exclude: string[], include: string[], depth: number): string[] {
const harnessReadDirectoryResult = Harness.IO.readDirectory(getFileNameInTheProjectTest(rootDir), extension, exclude, include, depth);
const result: string[] = [];
for (let i = 0; i < harnessReadDirectoryResult.length; i++) {
result[i] = ts.getRelativePathToDirectoryOrUrl(testCase.projectRoot, harnessReadDirectoryResult[i],
@@ -295,7 +289,7 @@ class ProjectRunner extends RunnerBase {
return Harness.IO.fileExists(getFileNameInTheProjectTest(fileName));
}
function readFile(fileName: string): string {
function readFile(fileName: string): string | undefined {
return Harness.IO.readFile(getFileNameInTheProjectTest(fileName));
}
@@ -325,8 +319,8 @@ class ProjectRunner extends RunnerBase {
// we need to instead create files that can live in the project reference folder
// but make sure extension of these files matches with the fileName the compiler asked to write
diskRelativeName = "diskFile" + nonSubfolderDiskFiles +
(Harness.Compiler.isDTS(fileName) ? ".d.ts" :
Harness.Compiler.isJS(fileName) ? ".js" : ".js.map");
(Harness.Compiler.isDTS(fileName) ? ts.Extension.Dts :
Harness.Compiler.isJS(fileName) ? ts.Extension.Js : ".js.map");
nonSubfolderDiskFiles++;
}
@@ -360,7 +354,7 @@ class ProjectRunner extends RunnerBase {
ensureDirectoryStructure(ts.getDirectoryPath(ts.normalizePath(outputFilePath)));
Harness.IO.writeFile(outputFilePath, data);
outputFiles.push({ emittedFileName: fileName, code: data, fileName: diskRelativeName, writeByteOrderMark: writeByteOrderMark });
outputFiles.push({ emittedFileName: fileName, code: data, fileName: diskRelativeName, writeByteOrderMark });
}
}
@@ -386,14 +380,14 @@ class ProjectRunner extends RunnerBase {
emitOutputFilePathWithoutExtension = ts.removeFileExtension(sourceFile.fileName);
}
const outputDtsFileName = emitOutputFilePathWithoutExtension + ".d.ts";
const outputDtsFileName = emitOutputFilePathWithoutExtension + ts.Extension.Dts;
const file = findOutputDtsFile(outputDtsFileName);
if (file) {
allInputFiles.unshift(file);
}
}
else {
const outputDtsFileName = ts.removeFileExtension(compilerOptions.outFile || compilerOptions.out) + ".d.ts";
const outputDtsFileName = ts.removeFileExtension(compilerOptions.outFile || compilerOptions.out) + ts.Extension.Dts;
const outputDtsFile = findOutputDtsFile(outputDtsFileName);
if (!ts.contains(allInputFiles, outputDtsFile)) {
allInputFiles.unshift(outputDtsFile);
@@ -402,7 +396,7 @@ class ProjectRunner extends RunnerBase {
});
// Dont allow config files since we are compiling existing source options
return compileProjectFiles(compilerResult.moduleKind, getInputFiles, getSourceFileText, writeFile, compilerResult.compilerOptions);
return compileProjectFiles(compilerResult.moduleKind, compilerResult.configFileSourceFiles, getInputFiles, getSourceFileText, writeFile, compilerResult.compilerOptions);
function findOutputDtsFile(fileName: string) {
return ts.forEach(compilerResult.outputFiles, outputFile => outputFile.emittedFileName === fileName ? outputFile : undefined);
@@ -428,16 +422,21 @@ class ProjectRunner extends RunnerBase {
}
function getErrorsBaseline(compilerResult: CompileProjectFilesResult) {
const inputFiles = compilerResult.program ? ts.map(ts.filter(compilerResult.program.getSourceFiles(),
sourceFile => !Harness.isDefaultLibraryFile(sourceFile.fileName)),
sourceFile => {
return {
unitName: ts.isRootedDiskPath(sourceFile.fileName) ?
RunnerBase.removeFullPaths(sourceFile.fileName) :
sourceFile.fileName,
content: sourceFile.text
};
}) : [];
const inputSourceFiles = compilerResult.configFileSourceFiles.slice();
if (compilerResult.program) {
for (const sourceFile of compilerResult.program.getSourceFiles()) {
if (!Harness.isDefaultLibraryFile(sourceFile.fileName)) {
inputSourceFiles.push(sourceFile);
}
}
}
const inputFiles = inputSourceFiles.map<Harness.Compiler.TestFile>(sourceFile => ({
unitName: ts.isRootedDiskPath(sourceFile.fileName) ?
RunnerBase.removeFullPaths(sourceFile.fileName) :
sourceFile.fileName,
content: sourceFile.text
}));
return Harness.Compiler.getErrorBaseline(inputFiles, compilerResult.errors);
}
+106 -118
View File
@@ -19,6 +19,7 @@
/// <reference path="projectsRunner.ts" />
/// <reference path="rwcRunner.ts" />
/// <reference path="harness.ts" />
/// <reference path="./parallel/shared.ts" />
let runners: RunnerBase[] = [];
let iterations = 1;
@@ -59,6 +60,7 @@ function createRunner(kind: TestRunnerKind): RunnerBase {
case "test262":
return new Test262BaselineRunner();
}
ts.Debug.fail(`Unknown runner kind ${kind}`);
}
if (Harness.IO.tryEnableSourceMapsForHost && /^development$/i.test(Harness.IO.getEnvironmentVariable("NODE_ENV"))) {
@@ -81,15 +83,17 @@ let testConfigContent =
let taskConfigsFolder: string;
let workerCount: number;
let runUnitTests = true;
let noColors = false;
interface TestConfig {
light?: boolean;
taskConfigsFolder?: string;
listenForWork?: boolean;
workerCount?: number;
stackTraceLimit?: number | "full";
tasks?: TaskSet[];
test?: string[];
runUnitTests?: boolean;
noColors?: boolean;
}
interface TaskSet {
@@ -97,138 +101,122 @@ interface TaskSet {
files: string[];
}
if (testConfigContent !== "") {
const testConfig = <TestConfig>JSON.parse(testConfigContent);
if (testConfig.light) {
Harness.lightMode = true;
}
if (testConfig.taskConfigsFolder) {
taskConfigsFolder = testConfig.taskConfigsFolder;
}
if (testConfig.runUnitTests !== undefined) {
runUnitTests = testConfig.runUnitTests;
}
if (testConfig.workerCount) {
workerCount = testConfig.workerCount;
}
if (testConfig.tasks) {
for (const taskSet of testConfig.tasks) {
const runner = createRunner(taskSet.runner);
for (const file of taskSet.files) {
runner.addTest(file);
}
runners.push(runner);
function handleTestConfig() {
if (testConfigContent !== "") {
const testConfig = <TestConfig>JSON.parse(testConfigContent);
if (testConfig.light) {
Harness.lightMode = true;
}
}
if (testConfig.stackTraceLimit === "full") {
(<any>Error).stackTraceLimit = Infinity;
}
else if ((+testConfig.stackTraceLimit | 0) > 0) {
(<any>Error).stackTraceLimit = testConfig.stackTraceLimit;
}
if (testConfig.test && testConfig.test.length > 0) {
for (const option of testConfig.test) {
if (!option) {
continue;
}
switch (option) {
case "compiler":
runners.push(new CompilerBaselineRunner(CompilerTestType.Conformance));
runners.push(new CompilerBaselineRunner(CompilerTestType.Regressions));
runners.push(new ProjectRunner());
break;
case "conformance":
runners.push(new CompilerBaselineRunner(CompilerTestType.Conformance));
break;
case "project":
runners.push(new ProjectRunner());
break;
case "fourslash":
runners.push(new FourSlashRunner(FourSlashTestType.Native));
break;
case "fourslash-shims":
runners.push(new FourSlashRunner(FourSlashTestType.Shims));
break;
case "fourslash-shims-pp":
runners.push(new FourSlashRunner(FourSlashTestType.ShimsWithPreprocess));
break;
case "fourslash-server":
runners.push(new FourSlashRunner(FourSlashTestType.Server));
break;
case "fourslash-generated":
runners.push(new GeneratedFourslashRunner(FourSlashTestType.Native));
break;
case "rwc":
runners.push(new RWCRunner());
break;
case "test262":
runners.push(new Test262BaselineRunner());
break;
}
if (testConfig.runUnitTests !== undefined) {
runUnitTests = testConfig.runUnitTests;
}
if (testConfig.workerCount) {
workerCount = +testConfig.workerCount;
}
if (testConfig.taskConfigsFolder) {
taskConfigsFolder = testConfig.taskConfigsFolder;
}
if (testConfig.noColors !== undefined) {
noColors = testConfig.noColors;
}
}
}
if (runners.length === 0) {
// compiler
runners.push(new CompilerBaselineRunner(CompilerTestType.Conformance));
runners.push(new CompilerBaselineRunner(CompilerTestType.Regressions));
if (testConfig.stackTraceLimit === "full") {
(<any>Error).stackTraceLimit = Infinity;
}
else if ((+testConfig.stackTraceLimit | 0) > 0) {
(<any>Error).stackTraceLimit = testConfig.stackTraceLimit;
}
if (testConfig.listenForWork) {
return true;
}
// TODO: project tests don't work in the browser yet
if (Utils.getExecutionEnvironment() !== Utils.ExecutionEnvironment.Browser) {
runners.push(new ProjectRunner());
}
if (testConfig.test && testConfig.test.length > 0) {
for (const option of testConfig.test) {
if (!option) {
continue;
}
// language services
runners.push(new FourSlashRunner(FourSlashTestType.Native));
runners.push(new FourSlashRunner(FourSlashTestType.Shims));
runners.push(new FourSlashRunner(FourSlashTestType.ShimsWithPreprocess));
runners.push(new FourSlashRunner(FourSlashTestType.Server));
// runners.push(new GeneratedFourslashRunner());
}
if (taskConfigsFolder) {
// this instance of mocha should only partition work but not run actual tests
runUnitTests = false;
const workerConfigs: TestConfig[] = [];
for (let i = 0; i < workerCount; i++) {
// pass light mode settings to workers
workerConfigs.push({ light: Harness.lightMode, tasks: [] });
}
for (const runner of runners) {
const files = runner.enumerateTestFiles();
const chunkSize = Math.floor(files.length / workerCount) + 1; // add extra 1 to prevent missing tests due to rounding
for (let i = 0; i < workerCount; i++) {
const startPos = i * chunkSize;
const len = Math.min(chunkSize, files.length - startPos);
if (len > 0) {
workerConfigs[i].tasks.push({
runner: runner.kind(),
files: files.slice(startPos, startPos + len)
});
switch (option) {
case "compiler":
runners.push(new CompilerBaselineRunner(CompilerTestType.Conformance));
runners.push(new CompilerBaselineRunner(CompilerTestType.Regressions));
runners.push(new ProjectRunner());
break;
case "conformance":
runners.push(new CompilerBaselineRunner(CompilerTestType.Conformance));
break;
case "project":
runners.push(new ProjectRunner());
break;
case "fourslash":
runners.push(new FourSlashRunner(FourSlashTestType.Native));
break;
case "fourslash-shims":
runners.push(new FourSlashRunner(FourSlashTestType.Shims));
break;
case "fourslash-shims-pp":
runners.push(new FourSlashRunner(FourSlashTestType.ShimsWithPreprocess));
break;
case "fourslash-server":
runners.push(new FourSlashRunner(FourSlashTestType.Server));
break;
case "fourslash-generated":
runners.push(new GeneratedFourslashRunner(FourSlashTestType.Native));
break;
case "rwc":
runners.push(new RWCRunner());
break;
case "test262":
runners.push(new Test262BaselineRunner());
break;
}
}
}
}
for (let i = 0; i < workerCount; i++) {
const config = workerConfigs[i];
// use last worker to run unit tests
config.runUnitTests = i === workerCount - 1;
Harness.IO.writeFile(ts.combinePaths(taskConfigsFolder, `task-config${i}.json`), JSON.stringify(workerConfigs[i]));
if (runners.length === 0) {
// compiler
runners.push(new CompilerBaselineRunner(CompilerTestType.Conformance));
runners.push(new CompilerBaselineRunner(CompilerTestType.Regressions));
// TODO: project tests don"t work in the browser yet
if (Utils.getExecutionEnvironment() !== Utils.ExecutionEnvironment.Browser) {
runners.push(new ProjectRunner());
}
// language services
runners.push(new FourSlashRunner(FourSlashTestType.Native));
runners.push(new FourSlashRunner(FourSlashTestType.Shims));
runners.push(new FourSlashRunner(FourSlashTestType.ShimsWithPreprocess));
runners.push(new FourSlashRunner(FourSlashTestType.Server));
// runners.push(new GeneratedFourslashRunner());
}
}
else {
function beginTests() {
if (ts.Debug.isDebugging) {
ts.Debug.enableDebugInfo();
}
runTests(runners);
if (!runUnitTests) {
// patch `describe` to skip unit tests
describe = ts.noop as any;
}
}
if (!runUnitTests) {
// patch `describe` to skip unit tests
describe = ts.noop as any;
function startTestEnvironment() {
const isWorker = handleTestConfig();
if (Utils.getExecutionEnvironment() !== Utils.ExecutionEnvironment.Browser) {
if (isWorker) {
return Harness.Parallel.Worker.start();
}
else if (taskConfigsFolder && workerCount && workerCount > 1) {
return Harness.Parallel.Host.start();
}
}
beginTests();
}
startTestEnvironment();
+56 -45
View File
@@ -22,14 +22,14 @@ namespace RWC {
}
function isTsConfigFile(file: { path: string }): boolean {
const tsConfigFileName = "tsconfig.json";
return file.path.substr(file.path.length - tsConfigFileName.length).toLowerCase() === tsConfigFileName;
return file.path.indexOf("tsconfig") !== -1 && file.path.indexOf("json") !== -1;
}
export function runRWCTest(jsonPath: string) {
describe("Testing a RWC project: " + jsonPath, () => {
let inputFiles: Harness.Compiler.TestFile[] = [];
let otherFiles: Harness.Compiler.TestFile[] = [];
let tsconfigFiles: Harness.Compiler.TestFile[] = [];
let compilerResult: Harness.Compiler.CompilerResult;
let compilerOptions: ts.CompilerOptions;
const baselineOpts: Harness.Baseline.BaselineOptions = {
@@ -44,6 +44,7 @@ namespace RWC {
// Therefore we have to clean out large objects after the test is done.
inputFiles = [];
otherFiles = [];
tsconfigFiles = [];
compilerResult = undefined;
compilerOptions = undefined;
currentDirectory = undefined;
@@ -53,7 +54,8 @@ namespace RWC {
useCustomLibraryFile = undefined;
});
it("can compile", () => {
it("can compile", function(this: Mocha.ITestCallbackContext) {
this.timeout(800000); // Allow long timeouts for RWC compilations
let opts: ts.ParsedCommandLine;
const ioLog: IOLog = JSON.parse(Harness.IO.readFile(jsonPath));
@@ -74,21 +76,30 @@ namespace RWC {
const tsconfigFile = ts.forEach(ioLog.filesRead, f => isTsConfigFile(f) ? f : undefined);
if (tsconfigFile) {
const tsconfigFileContents = getHarnessCompilerInputUnit(tsconfigFile.path);
const parsedTsconfigFileContents = ts.parseConfigFileTextToJson(tsconfigFile.path, tsconfigFileContents.content);
tsconfigFiles.push({ unitName: tsconfigFile.path, content: tsconfigFileContents.content });
const parsedTsconfigFileContents = ts.parseJsonText(tsconfigFile.path, tsconfigFileContents.content);
const configParseHost: ts.ParseConfigHost = {
useCaseSensitiveFileNames: Harness.IO.useCaseSensitiveFileNames(),
fileExists: Harness.IO.fileExists,
readDirectory: Harness.IO.readDirectory,
readFile: Harness.IO.readFile
};
const configParseResult = ts.parseJsonConfigFileContent(parsedTsconfigFileContents.config, configParseHost, ts.getDirectoryPath(tsconfigFile.path));
const configParseResult = ts.parseJsonSourceFileConfigFileContent(parsedTsconfigFileContents, configParseHost, ts.getDirectoryPath(tsconfigFile.path));
fileNames = configParseResult.fileNames;
opts.options = ts.extend(opts.options, configParseResult.options);
ts.setConfigFileInOptions(opts.options, configParseResult.options.configFile);
}
// Load the files
// Deduplicate files so they are only printed once in baselines (they are deduplicated within the compiler already)
const uniqueNames = ts.createMap<true>();
for (const fileName of fileNames) {
inputFiles.push(getHarnessCompilerInputUnit(fileName));
// Must maintain order, build result list while checking map
const normalized = ts.normalizeSlashes(fileName);
if (!uniqueNames.has(normalized)) {
uniqueNames.set(normalized, true);
// Load the file
inputFiles.push(getHarnessCompilerInputUnit(fileName));
}
}
// Add files to compilation
@@ -159,29 +170,29 @@ namespace RWC {
it("has the expected emitted code", () => {
Harness.Baseline.runBaseline(`${baseName}.output.js`, () => {
return Harness.Compiler.collateOutputs(compilerResult.files);
}, baselineOpts);
Harness.Baseline.runMultifileBaseline(baseName, "", () => {
return Harness.Compiler.iterateOutputs(compilerResult.files);
}, baselineOpts, [".js", ".jsx"]);
});
it("has the expected declaration file content", () => {
Harness.Baseline.runBaseline(`${baseName}.d.ts`, () => {
Harness.Baseline.runMultifileBaseline(baseName, "", () => {
if (!compilerResult.declFilesCode.length) {
return null;
}
return Harness.Compiler.collateOutputs(compilerResult.declFilesCode);
}, baselineOpts);
return Harness.Compiler.iterateOutputs(compilerResult.declFilesCode);
}, baselineOpts, [".d.ts"]);
});
it("has the expected source maps", () => {
Harness.Baseline.runBaseline(`${baseName}.map`, () => {
Harness.Baseline.runMultifileBaseline(baseName, "", () => {
if (!compilerResult.sourceMaps.length) {
return null;
}
return Harness.Compiler.collateOutputs(compilerResult.sourceMaps);
}, baselineOpts);
return Harness.Compiler.iterateOutputs(compilerResult.sourceMaps);
}, baselineOpts, [".map"]);
});
/*it("has correct source map record", () => {
@@ -193,52 +204,52 @@ namespace RWC {
});*/
it("has the expected errors", () => {
Harness.Baseline.runBaseline(`${baseName}.errors.txt`, () => {
Harness.Baseline.runMultifileBaseline(baseName, ".errors.txt", () => {
if (compilerResult.errors.length === 0) {
return null;
}
// Do not include the library in the baselines to avoid noise
const baselineFiles = inputFiles.concat(otherFiles).filter(f => !Harness.isDefaultLibraryFile(f.unitName));
const errors = compilerResult.errors.filter(e => e.file && !Harness.isDefaultLibraryFile(e.file.fileName));
return Harness.Compiler.getErrorBaseline(baselineFiles, errors);
const baselineFiles = tsconfigFiles.concat(inputFiles, otherFiles).filter(f => !Harness.isDefaultLibraryFile(f.unitName));
const errors = compilerResult.errors.filter(e => !e.file || !Harness.isDefaultLibraryFile(e.file.fileName));
return Harness.Compiler.iterateErrorBaseline(baselineFiles, errors);
}, baselineOpts);
});
// Ideally, a generated declaration file will have no errors. But we allow generated
// declaration file errors as part of the baseline.
it("has the expected errors in generated declaration files", () => {
if (compilerOptions.declaration && !compilerResult.errors.length) {
Harness.Baseline.runBaseline(`${baseName}.dts.errors.txt`, () => {
const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(
inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined, compilerOptions, currentDirectory);
if (declFileCompilationResult.declResult.errors.length === 0) {
return null;
}
return Harness.Compiler.minimalDiagnosticsToString(declFileCompilationResult.declResult.errors) +
Harness.IO.newLine() + Harness.IO.newLine() +
Harness.Compiler.getErrorBaseline(declFileCompilationResult.declInputFiles.concat(declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
}, baselineOpts);
}
});
it("has the expected types", () => {
// We don't need to pass the extension here because "doTypeAndSymbolBaseline" will append appropriate extension of ".types" or ".symbols"
Harness.Compiler.doTypeAndSymbolBaseline(baseName, compilerResult, inputFiles
.concat(otherFiles)
.filter(file => !!compilerResult.program.getSourceFile(file.unitName))
.filter(e => !Harness.isDefaultLibraryFile(e.unitName)), baselineOpts);
.filter(e => !Harness.isDefaultLibraryFile(e.unitName)), baselineOpts, /*multifile*/ true);
});
// Ideally, a generated declaration file will have no errors. But we allow generated
// declaration file errors as part of the baseline.
it("has the expected errors in generated declaration files", () => {
if (compilerOptions.declaration && !compilerResult.errors.length) {
Harness.Baseline.runMultifileBaseline(baseName, ".dts.errors.txt", () => {
if (compilerResult.errors.length === 0) {
return null;
}
const declContext = Harness.Compiler.prepareDeclarationCompilationContext(
inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined, compilerOptions, currentDirectory
);
// Reset compilerResult before calling into `compileDeclarationFiles` so the memory from the original compilation can be freed
compilerResult = undefined;
const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(declContext);
return Harness.Compiler.iterateErrorBaseline(tsconfigFiles.concat(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
}, baselineOpts);
}
});
});
}
}
class RWCRunner extends RunnerBase {
private static sourcePath = "internal/cases/rwc/";
public enumerateTestFiles() {
return Harness.IO.listFiles(RWCRunner.sourcePath, /.+\.json$/);
return Harness.IO.listFiles("internal/cases/rwc/", /.+\.json$/);
}
public kind(): TestRunnerKind {
@@ -250,7 +261,7 @@ class RWCRunner extends RunnerBase {
*/
public initializeTests(): void {
// Read in and evaluate the test list
const testList = this.enumerateTestFiles();
const testList = this.tests && this.tests.length ? this.tests : this.enumerateTestFiles();
for (let i = 0; i < testList.length; i++) {
this.runTest(testList[i]);
}
@@ -259,4 +270,4 @@ class RWCRunner extends RunnerBase {
private runTest(jsonFileName: string) {
RWC.runRWCTest(jsonFileName);
}
}
}
+6 -8
View File
@@ -259,7 +259,7 @@ namespace Harness.SourceMapRecorder {
export function recordSourceMapSpan(sourceMapSpan: ts.SourceMapSpan) {
// verify the decoded span is same as the new span
const decodeResult = SourceMapDecoder.decodeNextEncodedSourceMapSpan();
let decodedErrors: string[];
let decodeErrors: string[];
if (decodeResult.error
|| decodeResult.sourceMapSpan.emittedLine !== sourceMapSpan.emittedLine
|| decodeResult.sourceMapSpan.emittedColumn !== sourceMapSpan.emittedColumn
@@ -268,22 +268,20 @@ namespace Harness.SourceMapRecorder {
|| decodeResult.sourceMapSpan.sourceIndex !== sourceMapSpan.sourceIndex
|| decodeResult.sourceMapSpan.nameIndex !== sourceMapSpan.nameIndex) {
if (decodeResult.error) {
decodedErrors = ["!!^^ !!^^ There was decoding error in the sourcemap at this location: " + decodeResult.error];
decodeErrors = ["!!^^ !!^^ There was decoding error in the sourcemap at this location: " + decodeResult.error];
}
else {
decodedErrors = ["!!^^ !!^^ The decoded span from sourcemap's mapping entry does not match what was encoded for this span:"];
decodeErrors = ["!!^^ !!^^ The decoded span from sourcemap's mapping entry does not match what was encoded for this span:"];
}
decodedErrors.push("!!^^ !!^^ Decoded span from sourcemap's mappings entry: " + getSourceMapSpanString(decodeResult.sourceMapSpan, /*getAbsentNameIndex*/ true) + " Span encoded by the emitter:" + getSourceMapSpanString(sourceMapSpan, /*getAbsentNameIndex*/ true));
decodeErrors.push("!!^^ !!^^ Decoded span from sourcemap's mappings entry: " + getSourceMapSpanString(decodeResult.sourceMapSpan, /*getAbsentNameIndex*/ true) + " Span encoded by the emitter:" + getSourceMapSpanString(sourceMapSpan, /*getAbsentNameIndex*/ true));
}
if (spansOnSingleLine.length && spansOnSingleLine[0].sourceMapSpan.emittedLine !== sourceMapSpan.emittedLine) {
// On different line from the one that we have been recording till now,
writeRecordedSpans();
spansOnSingleLine = [{ sourceMapSpan: sourceMapSpan, decodeErrors: decodedErrors }];
}
else {
spansOnSingleLine.push({ sourceMapSpan: sourceMapSpan, decodeErrors: decodedErrors });
spansOnSingleLine = [];
}
spansOnSingleLine.push({ sourceMapSpan, decodeErrors });
}
export function recordNewSourceFileSpan(sourceMapSpan: ts.SourceMapSpan, newSourceFileCode: string) {
+7 -7
View File
@@ -4,19 +4,19 @@
/* tslint:disable:no-null-keyword */
class Test262BaselineRunner extends RunnerBase {
private static basePath = "internal/cases/test262";
private static helpersFilePath = "tests/cases/test262-harness/helpers.d.ts";
private static helperFile: Harness.Compiler.TestFile = {
private static readonly basePath = "internal/cases/test262";
private static readonly helpersFilePath = "tests/cases/test262-harness/helpers.d.ts";
private static readonly helperFile: Harness.Compiler.TestFile = {
unitName: Test262BaselineRunner.helpersFilePath,
content: Harness.IO.readFile(Test262BaselineRunner.helpersFilePath),
};
private static testFileExtensionRegex = /\.js$/;
private static options: ts.CompilerOptions = {
private static readonly testFileExtensionRegex = /\.js$/;
private static readonly options: ts.CompilerOptions = {
allowNonTsExtensions: true,
target: ts.ScriptTarget.Latest,
module: ts.ModuleKind.CommonJS
};
private static baselineOptions: Harness.Baseline.BaselineOptions = {
private static readonly baselineOptions: Harness.Baseline.BaselineOptions = {
Subfolder: "test262",
Baselinefolder: "internal/baselines"
};
@@ -48,7 +48,7 @@ class Test262BaselineRunner extends RunnerBase {
// Emit the results
testState = {
filename: testFilename,
inputFiles: inputFiles,
inputFiles,
compilerResult: undefined,
};

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