Merge branch 'master' into completionWithMeaning

This commit is contained in:
Sheetal Nandi
2017-06-13 11:16:32 -07:00
643 changed files with 18326 additions and 4660 deletions
+20 -1
View File
@@ -248,4 +248,23 @@ rdosanjh <me@rajdeep.io> # Raj Dosanjh
gdh1995 <gdh1995@qq.com> # Dahan Gong
cedvdb <cedvandenbosch@gmail.com> # @cedvdb
kpreisser <kpreisser@users.noreply.github.com> # K. Preißer
e-cloud <saintscott119@gmail.com> # @e-cloud
e-cloud <saintscott119@gmail.com> # @e-cloud
Andrew Casey <amcasey@users.noreply.github.com> Andrew Casey <andrew.casey@microsoft.com>
Andrew Stegmaier <andrew.stegmaier@gmail.com>
Benny Neugebauer <bn@bennyn.de>
Blaine Bublitz <blaine.bublitz@gmail.com>
Charles Pierce <cpierce.grad@gmail.com>
Daniel Król <daniel@krol.me>
Diogo Franco (Kovensky) <diogomfranco@gmail.com>
Donald Pipowitch <pipo@senaeh.de>
Halasi Tamás <trusted.tomato@gmail.com>
Ika <ikatyang@gmail.com>
Joe Chung <joechung@microsoft.com>
Kate Miháliková <kate@katemihalikova.cz>
Mohsen Azimi <mazimi@lyft.com>
Noel Varanda <ncwvaranda@gmail.com>
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>
+19
View File
@@ -15,7 +15,9 @@ TypeScript is authored by:
* Anders Hejlsberg
* Andreas Martin
* Andrej Baran
* Andrew Casey
* Andrew Ochsner
* Andrew Stegmaier
* Andrew Z Allen
* András Parditka
* Andy Hanson
@@ -31,7 +33,9 @@ TypeScript is authored by:
* Ben Duffield
* Ben Mosher
* Benjamin Bock
* Benny Neugebauer
* Bill Ticehurst
* Blaine Bublitz
* Blake Embrey
* @bootstraponline
* Bowden Kelly
@@ -39,6 +43,7 @@ TypeScript is authored by:
* Bryan Forbes
* Caitlin Potter
* @cedvdb
* Charles Pierce
* Charly POLY
* Chris Bubernak
* Christophe Vidal
@@ -52,6 +57,7 @@ TypeScript is authored by:
* Dan Corder
* Dan Quirk
* Daniel Hollocher
* Daniel Król
* Daniel Lehenbauer
* Daniel Rosenwasser
* David Kmenta
@@ -60,9 +66,11 @@ TypeScript is authored by:
* David Souther
* Denis Nedelyaev
* Dick van den Brink
* Diogo Franco (Kovensky)
* Dirk Bäumer
* Dirk Holtwick
* Dom Chen
* Donald Pipowitch
* Doug Ilijev
* @e-cloud
* Elisée Maurer
@@ -89,12 +97,14 @@ TypeScript is authored by:
* Guilherme Oenning
* Guillaume Salles
* Guy Bedford
* Halasi Tamás
* Harald Niesche
* Hendrik Liebau
* Herrington Darkholme
* Homa Wong
* Iain Monro
* Igor Novozhilov
* Ika
* Ingvar Stepanyan
* Isiah Meadows
* Ivo Gabe de Wolff
@@ -111,6 +121,7 @@ TypeScript is authored by:
* Jeffrey Morlan
* Jesse Schalken
* Jiri Tobisek
* Joe Chung
* Joel Day
* Joey Wilson
* Johannes Rieken
@@ -131,6 +142,7 @@ TypeScript is authored by:
* K. Preißer
* Kagami Sascha Rosylight
* Kanchalai Tanglertsampan
* Kate Miháliková
* Keith Mashinter
* Ken Howard
* Kenji Imamula
@@ -159,6 +171,7 @@ TypeScript is authored by:
* Mike Busyrev
* Mine Starks
* Mohamed Hegazy
* Mohsen Azimi
* Myles Megyesi
* Natalie Coley
* Nathan Shively-Sanders
@@ -166,6 +179,7 @@ TypeScript is authored by:
* Nicolas Henry
* Nima Zahedi
* Noah Chen
* Noel Varanda
* Noj Vek
* Oleg Mihailik
* Oleksandr Chekhovskyi
@@ -186,6 +200,7 @@ TypeScript is authored by:
* Punya Biswal
* Rado Kirov
* Raj Dosanjh
* Reiner Dolp
* Richard Karmazín
* Richard Knoll
* Richard Sentino
@@ -213,6 +228,7 @@ TypeScript is authored by:
* Sudheesh Singanamalla
* Sébastien Arod
* @T18970237136
* @t_
* Tarik Ozket
* Tetsuharu Ohzeki
* Thomas Loubiou
@@ -225,13 +241,16 @@ TypeScript is authored by:
* togru
* Tomas Grubliauskas
* Torben Fitschen
* @TravCav
* TruongSinh Tran-Nguyen
* Vadi Taslim
* Vidar Tonaas Fauske
* Viktor Zozulyak
* Vilic Vane
* Vladimir Kurchatkin
* Vladimir Matveev
* Wesley Wigham
* William Orr
* York Yao
* @yortus
* Yuichi Nukiyama
+20 -17
View File
@@ -39,25 +39,25 @@ Error.stackTraceLimit = 1000;
const cmdLineOptions = minimist(process.argv.slice(2), {
boolean: ["debug", "inspect", "light", "colors", "lint", "soft"],
string: ["browser", "tests", "host", "reporter", "stackTraceLimit"],
string: ["browser", "tests", "host", "reporter", "stackTraceLimit", "timeout"],
alias: {
b: "browser",
d: "debug",
t: "tests",
test: "tests",
d: "debug", "debug-brk": "debug",
i: "inspect", "inspect-brk": "inspect",
t: "tests", test: "tests",
r: "reporter",
color: "colors",
f: "files",
file: "files",
c: "colors", color: "colors",
f: "files", file: "files",
w: "workers",
},
default: {
soft: false,
colors: process.env.colors || process.env.color || true,
debug: process.env.debug || process.env.d,
inspect: process.env.inspect,
debug: process.env.debug || process.env["debug-brk"] || process.env.d,
inspect: process.env.inspect || process.env["inspect-brk"] || process.env.i,
host: process.env.TYPESCRIPT_HOST || process.env.host || "node",
browser: process.env.browser || process.env.b || "IE",
timeout: process.env.timeout || 40000,
tests: process.env.test || process.env.tests || process.env.t,
light: process.env.light || false,
reporter: process.env.reporter || process.env.r,
@@ -594,11 +594,11 @@ function restoreSavedNodeEnv() {
process.env.NODE_ENV = savedNodeEnv;
}
let testTimeout = 40000;
function runConsoleTests(defaultReporter: string, runInParallel: boolean, done: (e?: any) => void) {
const lintFlag = cmdLineOptions["lint"];
cleanTestDirs((err) => {
if (err) { console.error(err); failWithStatus(err, 1); }
let testTimeout = cmdLineOptions["timeout"];
const debug = cmdLineOptions["debug"];
const inspect = cmdLineOptions["inspect"];
const tests = cmdLineOptions["tests"];
@@ -637,12 +637,6 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done:
// default timeout is 2sec which really should be enough, but maybe we just need a small amount longer
if (!runInParallel) {
const args = [];
if (inspect) {
args.push("--inspect");
}
if (inspect || debug) {
args.push("--debug-brk");
}
args.push("-R", reporter);
if (tests) {
args.push("-g", `"${tests}"`);
@@ -653,7 +647,15 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done:
else {
args.push("--no-colors");
}
args.push("-t", testTimeout);
if (inspect) {
args.unshift("--inspect-brk");
}
else if (debug) {
args.unshift("--debug-brk");
}
else {
args.push("-t", testTimeout);
}
args.push(run);
setNodeEnvToDevelopment();
exec(mocha, args, lintThenFinish, function(e, status) {
@@ -838,6 +840,7 @@ gulp.task("runtests-browser", "Runs the tests using the built run.js file like '
});
gulp.task("generate-code-coverage", "Generates code coverage data via istanbul", ["tests"], (done) => {
const testTimeout = cmdLineOptions["timeout"];
exec("istanbul", ["cover", "node_modules/mocha/bin/_mocha", "--", "-R", "min", "-t", testTimeout.toString(), run], done, done);
});
+24 -19
View File
@@ -25,6 +25,8 @@ var LKGDirectory = "lib/";
var copyright = "CopyrightNotice.txt";
var thirdParty = "ThirdPartyNoticeText.txt";
var defaultTestTimeout = 40000;
// add node_modules to path so we don't need global modules, prefer the modules by adding them first
var nodeModulesPathPrefix = path.resolve("./node_modules/.bin/") + path.delimiter;
if (process.env.path !== undefined) {
@@ -74,6 +76,10 @@ function measure(marker) {
console.log("travis_time:end:" + marker.id + ":start=" + toNs(marker.stamp) + ",finish=" + toNs(total) + ",duration=" + toNs(diff) + "\r");
}
function removeConstModifierFromEnumDeclarations(text) {
return text.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, '$1$2enum $3 {$4');
}
var compilerSources = filesFromConfig("./src/compiler/tsconfig.json");
var servicesSources = filesFromConfig("./src/services/tsconfig.json");
var cancellationTokenSources = filesFromConfig(path.join(serverDirectory, "cancellationToken/tsconfig.json"));
@@ -268,7 +274,6 @@ var builtLocalCompiler = path.join(builtLocalDirectory, compilerFilename);
* @param {boolean} opts.preserveConstEnums: true if compiler should keep const enums in code
* @param {boolean} opts.noResolve: true if compiler should not include non-rooted files in compilation
* @param {boolean} opts.stripInternal: true if compiler should remove declarations marked as @internal
* @param {boolean} opts.noMapRoot: true if compiler omit mapRoot option
* @param {boolean} opts.inlineSourceMap: true if compiler should inline sourceMap
* @param {Array} opts.types: array of types to include in compilation
* @param callback: a function to execute after the compilation process ends
@@ -321,9 +326,6 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, opts
}
else {
options += " -sourcemap";
if (!opts.noMapRoot) {
options += " -mapRoot file:///" + path.resolve(path.dirname(outFile));
}
}
}
else {
@@ -527,7 +529,7 @@ task("importDefinitelyTypedTests", [importDefinitelyTypedTestsJs], function () {
// Local target to build the compiler and services
var tscFile = path.join(builtLocalDirectory, compilerFilename);
compileFile(tscFile, compilerSources, [builtLocalDirectory, copyright].concat(compilerSources), [copyright], /*useBuiltCompiler:*/ false, { noMapRoot: true });
compileFile(tscFile, compilerSources, [builtLocalDirectory, copyright].concat(compilerSources), [copyright], /*useBuiltCompiler:*/ false);
var servicesFile = path.join(builtLocalDirectory, "typescriptServices.js");
var servicesFileInBrowserTest = path.join(builtLocalDirectory, "typescriptServicesInBrowserTest.js");
@@ -555,7 +557,7 @@ compileFile(servicesFile, servicesSources, [builtLocalDirectory, copyright].conc
// Stanalone/web definition file using global 'ts' namespace
jake.cpR(standaloneDefinitionsFile, nodeDefinitionsFile, { silent: true });
var definitionFileContents = fs.readFileSync(nodeDefinitionsFile).toString();
definitionFileContents = definitionFileContents.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, '$1$2enum $3 {$4');
definitionFileContents = removeConstModifierFromEnumDeclarations(definitionFileContents)
fs.writeFileSync(standaloneDefinitionsFile, definitionFileContents);
// Official node package definition file, pointed to by 'typings' in package.json
@@ -582,7 +584,6 @@ compileFile(
keepComments: true,
noResolve: false,
stripInternal: true,
noMapRoot: true,
inlineSourceMap: true
});
@@ -616,6 +617,7 @@ compileFile(
fs.readFileSync(tsserverLibraryDefinitionFile).toString() +
"\r\nexport = ts;" +
"\r\nexport as namespace ts;";
tsserverLibraryDefinitionFileContents = removeConstModifierFromEnumDeclarations(tsserverLibraryDefinitionFileContents);
fs.writeFileSync(tsserverLibraryDefinitionFile, tsserverLibraryDefinitionFileContents);
});
@@ -805,9 +807,10 @@ function runConsoleTests(defaultReporter, runInParallel) {
cleanTestDirs();
}
var debug = process.env.debug || process.env.d;
var inspect = process.env.inspect;
tests = process.env.test || process.env.tests || process.env.t;
var debug = process.env.debug || process.env["debug-brk"] || process.env.d;
var inspect = process.env.inspect || process.env["inspect-brk"] || process.env.i;
var testTimeout = process.env.timeout || defaultTestTimeout;
var tests = process.env.test || process.env.tests || process.env.t;
var light = process.env.light || false;
var stackTraceLimit = process.env.stackTraceLimit;
var testConfigFile = 'test.config';
@@ -825,7 +828,7 @@ function runConsoleTests(defaultReporter, runInParallel) {
} while (fs.existsSync(taskConfigsFolder));
fs.mkdirSync(taskConfigsFolder);
workerCount = process.env.workerCount || os.cpus().length;
workerCount = process.env.workerCount || process.env.p || os.cpus().length;
}
if (tests || light || taskConfigsFolder) {
@@ -846,12 +849,6 @@ function runConsoleTests(defaultReporter, runInParallel) {
if (!runInParallel) {
var startTime = mark();
var args = [];
if (inspect) {
args.push("--inspect");
}
if (inspect || debug) {
args.push("--debug-brk");
}
args.push("-R", reporter);
if (tests) {
args.push("-g", `"${tests}"`);
@@ -865,7 +862,15 @@ function runConsoleTests(defaultReporter, runInParallel) {
if (bail) {
args.push("--bail");
}
args.push("-t", testTimeout);
if (inspect) {
args.unshift("--inspect-brk");
}
else if (debug) {
args.unshift("--debug-brk");
}
else {
args.push("-t", testTimeout);
}
args.push(run);
var cmd = "mocha " + args.join(" ");
@@ -930,7 +935,6 @@ function runConsoleTests(defaultReporter, runInParallel) {
}
}
var testTimeout = 20000;
desc("Runs all the tests in parallel using the built run.js file. Optional arguments are: t[ests]=category1|category2|... d[ebug]=true.");
task("runtests-parallel", ["build-rules", "tests", builtLocalDirectory], function () {
runConsoleTests('min', /*runInParallel*/ true);
@@ -943,6 +947,7 @@ task("runtests", ["build-rules", "tests", builtLocalDirectory], function() {
desc("Generates code coverage data via instanbul");
task("generate-code-coverage", ["tests", builtLocalDirectory], function () {
var testTimeout = process.env.timeout || defaultTestTimeout;
var cmd = 'istanbul cover node_modules/mocha/bin/_mocha -- -R min -t ' + testTimeout + ' ' + run;
console.log(cmd);
exec(cmd);
+6 -4
View File
@@ -113,7 +113,7 @@ class DeclarationsWalker {
}
}
function generateProtocolFile(protocolTs: string, typeScriptServicesDts: string): string {
function writeProtocolFile(outputFile: string, protocolTs: string, typeScriptServicesDts: string) {
const options = { target: ts.ScriptTarget.ES5, declaration: true, noResolve: true, types: <string[]>[], stripInternal: true };
/**
@@ -163,14 +163,17 @@ function generateProtocolFile(protocolTs: string, typeScriptServicesDts: string)
protocolDts += "\nimport protocol = ts.server.protocol;";
protocolDts += "\nexport = protocol;";
protocolDts += "\nexport as namespace protocol;";
// do sanity check and try to compile generated text as standalone program
const sanityCheckProgram = getProgramWithProtocolText(protocolDts, /*includeTypeScriptServices*/ false);
const diagnostics = [...sanityCheckProgram.getSyntacticDiagnostics(), ...sanityCheckProgram.getSemanticDiagnostics(), ...sanityCheckProgram.getGlobalDiagnostics()];
ts.sys.writeFile(outputFile, protocolDts);
if (diagnostics.length) {
const flattenedDiagnostics = diagnostics.map(d => `${ts.flattenDiagnosticMessageText(d.messageText, "\n")} at ${d.file.fileName} line ${d.start}`).join("\n");
throw new Error(`Unexpected errors during sanity check: ${flattenedDiagnostics}`);
}
return protocolDts;
}
if (process.argv.length < 5) {
@@ -181,5 +184,4 @@ if (process.argv.length < 5) {
const protocolTs = process.argv[2];
const typeScriptServicesDts = process.argv[3];
const outputFile = process.argv[4];
const generatedProtocolDts = generateProtocolFile(protocolTs, typeScriptServicesDts);
ts.sys.writeFile(outputFile, generatedProtocolDts);
writeProtocolFile(outputFile, protocolTs, typeScriptServicesDts);
+2 -2
View File
@@ -18,7 +18,7 @@ export class Rule extends Lint.Rules.AbstractRule {
function walk(ctx: Lint.WalkContext<void>, checkCatch: boolean, checkElse: boolean): void {
const { sourceFile } = ctx;
function recur(node: ts.Node): void {
ts.forEachChild(sourceFile, function recur(node) {
switch (node.kind) {
case ts.SyntaxKind.IfStatement:
checkIf(node as ts.IfStatement);
@@ -28,7 +28,7 @@ function walk(ctx: Lint.WalkContext<void>, checkCatch: boolean, checkElse: boole
break;
}
ts.forEachChild(node, recur);
}
});
function checkIf(node: ts.IfStatement): void {
const { thenStatement, elseStatement } = node;
+17 -8
View File
@@ -612,7 +612,7 @@ namespace ts {
break;
case SyntaxKind.ForInStatement:
case SyntaxKind.ForOfStatement:
bindForInOrForOfStatement(<ForInStatement | ForOfStatement>node);
bindForInOrForOfStatement(<ForInOrOfStatement>node);
break;
case SyntaxKind.IfStatement:
bindIfStatement(<IfStatement>node);
@@ -950,7 +950,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);
@@ -1328,7 +1328,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);
}
}
@@ -1521,7 +1521,7 @@ namespace ts {
// All the children of these container types are never visible through another
// symbol (i.e. through another symbol's 'exports' or 'members'). Instead,
// they're only accessed 'lexically' (i.e. from code that exists underneath
// their container in the tree. To accomplish this, we simply add their declared
// their container in the tree). To accomplish this, we simply add their declared
// symbol to the 'locals' of the container. These symbols can then be found as
// the type checker walks up the containers, checking them for matching names.
return declareSymbol(container.locals, /*parent*/ undefined, node, symbolFlags, symbolExcludes);
@@ -2053,7 +2053,10 @@ namespace ts {
case SyntaxKind.TypePredicate:
return checkTypePredicate(node as TypePredicateNode);
case SyntaxKind.TypeParameter:
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
if (node.parent.kind !== ts.SyntaxKind.JSDocTemplateTag || isInJavaScriptFile(node)) {
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
}
return;
case SyntaxKind.Parameter:
return bindParameter(<ParameterDeclaration>node);
case SyntaxKind.VariableDeclaration:
@@ -2135,8 +2138,10 @@ namespace ts {
case SyntaxKind.EnumDeclaration:
return bindEnumDeclaration(<EnumDeclaration>node);
case SyntaxKind.ModuleDeclaration:
return bindModuleDeclaration(<ModuleDeclaration>node);
if (node.parent.kind !== ts.SyntaxKind.JSDocTypedefTag || isInJavaScriptFile(node)) {
return bindModuleDeclaration(<ModuleDeclaration>node);
}
return undefined;
// Jsx-attributes
case SyntaxKind.JsxAttributes:
return bindJsxAttributes(<JsxAttributes>node);
@@ -2333,7 +2338,7 @@ namespace ts {
// A common practice in node modules is to set 'export = module.exports = {}', this ensures that 'exports'
// is still pointing to 'module.exports'.
// We do not want to consider this as 'export=' since a module can have only one of these.
// Similarlly we do not want to treat 'module.exports = exports' as an 'export='.
// Similarly we do not want to treat 'module.exports = exports' as an 'export='.
const assignedExpression = getRightMostAssignedExpression(node.right);
if (isEmptyObjectLiteral(assignedExpression) || isExportsOrModuleExportsOrAlias(assignedExpression)) {
// Mark it as a module in case there are no other exports in the file
@@ -2741,6 +2746,10 @@ namespace ts {
transformFlags |= TransformFlags.AssertES2015;
}
if (expression.kind === SyntaxKind.ImportKeyword) {
transformFlags |= TransformFlags.ContainsDynamicImport;
}
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
return transformFlags & ~TransformFlags.ArrayLiteralOrCallOrNewExcludes;
}
+475 -311
View File
File diff suppressed because it is too large Load Diff
+21 -10
View File
@@ -100,11 +100,12 @@ namespace ts {
"umd": ModuleKind.UMD,
"es6": ModuleKind.ES2015,
"es2015": ModuleKind.ES2015,
"esnext": ModuleKind.ESNext
}),
paramType: Diagnostics.KIND,
showInSimplifiedHelpView: true,
category: Diagnostics.Basic_Options,
description: Diagnostics.Specify_module_code_generation_Colon_commonjs_amd_system_umd_or_es2015,
description: Diagnostics.Specify_module_code_generation_Colon_commonjs_amd_system_umd_es2015_or_ESNext,
},
{
name: "lib",
@@ -619,6 +620,12 @@ namespace ts {
category: Diagnostics.Advanced_Options,
description: Diagnostics.The_maximum_dependency_depth_to_search_under_node_modules_and_load_JavaScript_files
},
{
name: "noStrictGenericChecks",
type: "boolean",
category: Diagnostics.Advanced_Options,
description: Diagnostics.Disable_strict_checking_of_generic_signatures_in_function_types,
},
{
// A list of plugins to load in the language service
name: "plugins",
@@ -1042,7 +1049,7 @@ namespace ts {
for (let i = 0; i < nameColumn.length; i++) {
const optionName = nameColumn[i];
const description = descriptionColumn[i];
result.push(tab + tab + optionName + makePadding(marginLength - optionName.length + 2) + description);
result.push(optionName && `${tab}${tab}${optionName}${ description && (makePadding(marginLength - optionName.length + 2) + description)}`);
}
if (configurations.files && configurations.files.length) {
result.push(`${tab}},`);
@@ -1625,10 +1632,12 @@ namespace ts {
}
// Remove any subpaths under an existing recursively watched directory.
for (const key in wildcardDirectories) if (hasProperty(wildcardDirectories, key)) {
for (const recursiveKey of recursiveKeys) {
if (key !== recursiveKey && containsPath(recursiveKey, key, path, !useCaseSensitiveFileNames)) {
delete wildcardDirectories[key];
for (const key in wildcardDirectories) {
if (hasProperty(wildcardDirectories, key)) {
for (const recursiveKey of recursiveKeys) {
if (key !== recursiveKey && containsPath(recursiveKey, key, path, !useCaseSensitiveFileNames)) {
delete wildcardDirectories[key];
}
}
}
}
@@ -1716,10 +1725,12 @@ namespace ts {
/* @internal */
export function convertCompilerOptionsForTelemetry(opts: ts.CompilerOptions): ts.CompilerOptions {
const out: ts.CompilerOptions = {};
for (const key in opts) if (opts.hasOwnProperty(key)) {
const type = getOptionFromName(key);
if (type !== undefined) { // Ignore unknown options
out[key] = getOptionValueWithEmptyStrings(opts[key], type);
for (const key in opts) {
if (opts.hasOwnProperty(key)) {
const type = getOptionFromName(key);
if (type !== undefined) { // Ignore unknown options
out[key] = getOptionValueWithEmptyStrings(opts[key], type);
}
}
}
return out;
+57 -44
View File
@@ -51,8 +51,10 @@ namespace ts {
// Copies keys/values from template. Note that for..in will not throw if
// template is undefined, and instead will just exit the loop.
for (const key in template) if (hasOwnProperty.call(template, key)) {
map.set(key, template[key]);
for (const key in template) {
if (hasOwnProperty.call(template, key)) {
map.set(key, template[key]);
}
}
return map;
@@ -473,7 +475,7 @@ namespace ts {
* @param array The array to map.
* @param mapfn The callback used to map the result into one or more values.
*/
export function flatMap<T, U>(array: T[], mapfn: (x: T, i: number) => U | U[]): U[] {
export function flatMap<T, U>(array: T[] | undefined, mapfn: (x: T, i: number) => U | U[] | undefined): U[] | undefined {
let result: U[];
if (array) {
result = [];
@@ -521,8 +523,8 @@ namespace ts {
return result || array;
}
export function mapDefined<T>(array: ReadonlyArray<T>, mapFn: (x: T, i: number) => T | undefined): ReadonlyArray<T> {
const result: T[] = [];
export function mapDefined<T, U>(array: ReadonlyArray<T>, mapFn: (x: T, i: number) => U | undefined): U[] {
const result: U[] = [];
for (let i = 0; i < array.length; i++) {
const item = array[i];
const mapped = mapFn(item, i);
@@ -977,9 +979,12 @@ namespace ts {
*/
export function getOwnKeys<T>(map: MapLike<T>): string[] {
const keys: string[] = [];
for (const key in map) if (hasOwnProperty.call(map, key)) {
keys.push(key);
for (const key in map) {
if (hasOwnProperty.call(map, key)) {
keys.push(key);
}
}
return keys;
}
@@ -1042,8 +1047,10 @@ namespace ts {
export function assign<T1 extends MapLike<{}>>(t: T1, ...args: any[]): any;
export function assign<T1 extends MapLike<{}>>(t: T1, ...args: any[]) {
for (const arg of args) {
for (const p in arg) if (hasProperty(arg, p)) {
t[p] = arg[p];
for (const p in arg) {
if (hasProperty(arg, p)) {
t[p] = arg[p];
}
}
}
return t;
@@ -1058,13 +1065,19 @@ namespace ts {
export function equalOwnProperties<T>(left: MapLike<T>, right: MapLike<T>, equalityComparer?: (left: T, right: T) => boolean) {
if (left === right) return true;
if (!left || !right) return false;
for (const key in left) if (hasOwnProperty.call(left, key)) {
if (!hasOwnProperty.call(right, key) === undefined) return false;
if (equalityComparer ? !equalityComparer(left[key], right[key]) : left[key] !== right[key]) return false;
for (const key in left) {
if (hasOwnProperty.call(left, key)) {
if (!hasOwnProperty.call(right, key) === undefined) return false;
if (equalityComparer ? !equalityComparer(left[key], right[key]) : left[key] !== right[key]) return false;
}
}
for (const key in right) if (hasOwnProperty.call(right, key)) {
if (!hasOwnProperty.call(left, key)) return false;
for (const key in right) {
if (hasOwnProperty.call(right, key)) {
if (!hasOwnProperty.call(left, key)) return false;
}
}
return true;
}
@@ -1106,12 +1119,18 @@ namespace ts {
export function extend<T1, T2>(first: T1, second: T2): T1 & T2 {
const result: T1 & T2 = <any>{};
for (const id in second) if (hasOwnProperty.call(second, id)) {
(result as any)[id] = (second as any)[id];
for (const id in second) {
if (hasOwnProperty.call(second, id)) {
(result as any)[id] = (second as any)[id];
}
}
for (const id in first) if (hasOwnProperty.call(first, id)) {
(result as any)[id] = (first as any)[id];
for (const id in first) {
if (hasOwnProperty.call(first, id)) {
(result as any)[id] = (first as any)[id];
}
}
return result;
}
@@ -2112,13 +2131,13 @@ namespace ts {
export function getScriptKindFromFileName(fileName: string): ScriptKind {
const ext = fileName.substr(fileName.lastIndexOf("."));
switch (ext.toLowerCase()) {
case ".js":
case Extension.Js:
return ScriptKind.JS;
case ".jsx":
case Extension.Jsx:
return ScriptKind.JSX;
case ".ts":
case Extension.Ts:
return ScriptKind.TS;
case ".tsx":
case Extension.Tsx:
return ScriptKind.TSX;
default:
return ScriptKind.Unknown;
@@ -2128,10 +2147,10 @@ namespace ts {
/**
* List of supported extensions in order of file resolution precedence.
*/
export const supportedTypeScriptExtensions = [".ts", ".tsx", ".d.ts"];
export const supportedTypeScriptExtensions = [Extension.Ts, Extension.Tsx, Extension.Dts];
/** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */
export const supportedTypescriptExtensionsForExtractExtension = [".d.ts", ".ts", ".tsx"];
export const supportedJavascriptExtensions = [".js", ".jsx"];
export const supportedTypescriptExtensionsForExtractExtension = [Extension.Dts, Extension.Ts, Extension.Tsx];
export const supportedJavascriptExtensions = [Extension.Js, Extension.Jsx];
const allSupportedExtensions = supportedTypeScriptExtensions.concat(supportedJavascriptExtensions);
export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: JsFileExtensionInfo[]): string[] {
@@ -2139,7 +2158,7 @@ namespace ts {
if (!extraFileExtensions || extraFileExtensions.length === 0 || !needAllExtensions) {
return needAllExtensions ? allSupportedExtensions : supportedTypeScriptExtensions;
}
const extensions = allSupportedExtensions.slice(0);
const extensions: string[] = allSupportedExtensions.slice(0);
for (const extInfo of extraFileExtensions) {
if (extensions.indexOf(extInfo.extension) === -1) {
extensions.push(extInfo.extension);
@@ -2218,7 +2237,7 @@ namespace ts {
}
}
const extensionsToRemove = [".d.ts", ".ts", ".js", ".tsx", ".jsx"];
const extensionsToRemove = [Extension.Dts, Extension.Ts, Extension.Js, Extension.Tsx, Extension.Jsx];
export function removeFileExtension(path: string): string {
for (const ext of extensionsToRemove) {
const extensionless = tryRemoveExtension(path, ext);
@@ -2249,6 +2268,7 @@ namespace ts {
getSymbolConstructor(): new (flags: SymbolFlags, name: string) => Symbol;
getTypeConstructor(): new (checker: TypeChecker, flags: TypeFlags) => Type;
getSignatureConstructor(): new (checker: TypeChecker) => Signature;
getSourceMapSourceConstructor(): new (fileName: string, text: string, skipTrivia?: (pos: number) => number) => SourceMapSource;
}
function Symbol(this: Symbol, flags: SymbolFlags, name: string) {
@@ -2279,6 +2299,12 @@ namespace ts {
this.original = undefined;
}
function SourceMapSource(this: SourceMapSource, fileName: string, text: string, skipTrivia?: (pos: number) => number) {
this.fileName = fileName;
this.text = text;
this.skipTrivia = skipTrivia || (pos => pos);
}
export let objectAllocator: ObjectAllocator = {
getNodeConstructor: () => <any>Node,
getTokenConstructor: () => <any>Node,
@@ -2286,7 +2312,8 @@ namespace ts {
getSourceFileConstructor: () => <any>Node,
getSymbolConstructor: () => <any>Symbol,
getTypeConstructor: () => <any>Type,
getSignatureConstructor: () => <any>Signature
getSignatureConstructor: () => <any>Signature,
getSourceMapSourceConstructor: () => <any>SourceMapSource,
};
export const enum AssertionLevel {
@@ -2464,7 +2491,7 @@ namespace ts {
/** True if an extension is one of the supported TypeScript extensions. */
export function extensionIsTypeScript(ext: Extension): boolean {
return ext <= Extension.LastTypeScriptExtension;
return ext === Extension.Ts || ext === Extension.Tsx || ext === Extension.Dts;
}
/**
@@ -2479,21 +2506,7 @@ namespace ts {
Debug.fail(`File ${path} has unknown extension.`);
}
export function tryGetExtensionFromPath(path: string): Extension | undefined {
if (fileExtensionIs(path, ".d.ts")) {
return Extension.Dts;
}
if (fileExtensionIs(path, ".ts")) {
return Extension.Ts;
}
if (fileExtensionIs(path, ".tsx")) {
return Extension.Tsx;
}
if (fileExtensionIs(path, ".js")) {
return Extension.Js;
}
if (fileExtensionIs(path, ".jsx")) {
return Extension.Jsx;
}
return find(supportedTypescriptExtensionsForExtractExtension, e => fileExtensionIs(path, e)) || find(supportedJavascriptExtensions, e => fileExtensionIs(path, e));
}
export function isCheckJsEnabledForFile(sourceFile: SourceFile, compilerOptions: CompilerOptions) {
+1 -1
View File
@@ -596,7 +596,7 @@ namespace ts {
currentIdentifiers = node.identifiers;
isCurrentFileExternalModule = isExternalModule(node);
enclosingDeclaration = node;
emitDetachedComments(currentText, currentLineMap, writer, writeCommentRange, node, newLine, /*removeComents*/ true);
emitDetachedComments(currentText, currentLineMap, writer, writeCommentRange, node, newLine, /*removeComments*/ true);
emitLines(node.statements);
}
+50 -8
View File
@@ -883,6 +883,23 @@
"category": "Error",
"code": 1322
},
"Dynamic import cannot be used when targeting ECMAScript 2015 modules.": {
"category": "Error",
"code": 1323
},
"Dynamic import must have one specifier as an argument.": {
"category": "Error",
"code": 1324
},
"Specifier of dynamic import cannot be spread element.": {
"category": "Error",
"code": 1325
},
"Dynamic import cannot have type arguments": {
"category": "Error",
"code": 1326
},
"Duplicate identifier '{0}'.": {
"category": "Error",
"code": 2300
@@ -1879,6 +1896,10 @@
"category": "Error",
"code": 2558
},
"Type '{0}' has no properties in common with type '{1}'.": {
"category": "Error",
"code": 2559
},
"JSX element attributes type '{0}' may not be a union type.": {
"category": "Error",
"code": 2600
@@ -1923,10 +1944,6 @@
"category": "Error",
"code": 2649
},
"Cannot emit namespaced JSX elements in React.": {
"category": "Error",
"code": 2650
},
"A member initializer in a enum declaration cannot reference members declared after it, including members defined in other enums.": {
"category": "Error",
"code": 2651
@@ -2159,6 +2176,14 @@
"category": "Error",
"code": 2710
},
"A dynamic import call returns a 'Promise'. Make sure you have a declaration for 'Promise' or include 'ES2015' in your `--lib` option.": {
"category": "Error",
"code": 2711
},
"A dynamic import call in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option.": {
"category": "Error",
"code": 2712
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
@@ -2625,7 +2650,7 @@
"category": "Message",
"code": 6015
},
"Specify module code generation: 'commonjs', 'amd', 'system', 'umd' or 'es2015'.": {
"Specify module code generation: 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.": {
"category": "Message",
"code": 6016
},
@@ -3253,6 +3278,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
@@ -3361,6 +3390,11 @@
"category": "Error",
"code": 7035
},
"Dynamic import's specifier must be of type 'string', but here has type '{0}'.": {
"category": "Error",
"code": 7036
},
"You cannot rename this element.": {
"category": "Error",
"code": 8000
@@ -3555,11 +3589,11 @@
"category": "Message",
"code": 90015
},
"Add declaration for missing property '{0}'.": {
"Declare property '{0}'.": {
"category": "Message",
"code": 90016
},
"Add index signature for missing property '{0}'.": {
"Add index signature for property '{0}'.": {
"category": "Message",
"code": 90017
},
@@ -3583,7 +3617,15 @@
"category": "Message",
"code": 90022
},
"Declare method '{0}'.": {
"category": "Message",
"code": 90023
},
"Declare static method '{0}'.": {
"category": "Message",
"code": 90024
},
"Convert function to an ES2015 class": {
"category": "Message",
"code": 95001
+21 -6
View File
@@ -676,6 +676,7 @@ namespace ts {
case SyntaxKind.SuperKeyword:
case SyntaxKind.TrueKeyword:
case SyntaxKind.ThisKeyword:
case SyntaxKind.ImportKeyword:
writeTokenNode(node);
return;
@@ -958,7 +959,7 @@ namespace ts {
function emitConstructorType(node: ConstructorTypeNode) {
write("new ");
emitTypeParameters(node, node.typeParameters);
emitParametersForArrow(node, node.parameters);
emitParameters(node, node.parameters);
write(" => ");
emit(node.type);
}
@@ -2282,11 +2283,25 @@ namespace ts {
emitList(parentNode, parameters, ListFormat.Parameters);
}
function emitParametersForArrow(parentNode: Node, parameters: NodeArray<ParameterDeclaration>) {
if (parameters &&
parameters.length === 1 &&
parameters[0].type === undefined &&
parameters[0].pos === parentNode.pos) {
function canEmitSimpleArrowHead(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray<ParameterDeclaration>) {
const parameter = singleOrUndefined(parameters);
return parameter
&& parameter.pos === parentNode.pos // may not have parsed tokens between parent and parameter
&& !(isArrowFunction(parentNode) && parentNode.type) // arrow function may not have return type annotation
&& !some(parentNode.decorators) // parent may not have decorators
&& !some(parentNode.modifiers) // parent may not have modifiers
&& !some(parentNode.typeParameters) // parent may not have type parameters
&& !some(parameter.decorators) // parameter may not have decorators
&& !some(parameter.modifiers) // parameter may not have modifiers
&& !parameter.dotDotDotToken // parameter may not be rest
&& !parameter.questionToken // parameter may not be optional
&& !parameter.type // parameter may not have a type annotation
&& !parameter.initializer // parameter may not have an initializer
&& isIdentifier(parameter.name); // parameter name must be identifier
}
function emitParametersForArrow(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray<ParameterDeclaration>) {
if (canEmitSimpleArrowHead(parentNode, parameters)) {
emit(parameters[0]);
}
else {
+45 -24
View File
@@ -228,7 +228,7 @@ namespace ts {
// Signature elements
export function createTypeParameterDeclaration(name: string | Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined) {
export function createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode) {
const node = createSynthesizedNode(SyntaxKind.TypeParameter) as TypeParameterDeclaration;
node.name = asName(name);
node.constraint = constraint;
@@ -2314,15 +2314,24 @@ namespace ts {
/**
* Sets a custom text range to use when emitting source maps.
*/
export function setSourceMapRange<T extends Node>(node: T, range: TextRange | undefined) {
export function setSourceMapRange<T extends Node>(node: T, range: SourceMapRange | undefined) {
getOrCreateEmitNode(node).sourceMapRange = range;
return node;
}
let SourceMapSource: new (fileName: string, text: string, skipTrivia?: (pos: number) => number) => SourceMapSource;
/**
* Create an external source map source file reference
*/
export function createSourceMapSource(fileName: string, text: string, skipTrivia?: (pos: number) => number): SourceMapSource {
return new (SourceMapSource || (SourceMapSource = objectAllocator.getSourceMapSourceConstructor()))(fileName, text, skipTrivia);
}
/**
* Gets the TextRange to use for source maps for a token of a node.
*/
export function getTokenSourceMapRange(node: Node, token: SyntaxKind): TextRange | undefined {
export function getTokenSourceMapRange(node: Node, token: SyntaxKind): SourceMapRange | undefined {
const emitNode = node.emitNode;
const tokenSourceMapRanges = emitNode && emitNode.tokenSourceMapRanges;
return tokenSourceMapRanges && tokenSourceMapRanges[token];
@@ -2331,7 +2340,7 @@ namespace ts {
/**
* Sets the TextRange to use for source maps for a token of a node.
*/
export function setTokenSourceMapRange<T extends Node>(node: T, token: SyntaxKind, range: TextRange | undefined) {
export function setTokenSourceMapRange<T extends Node>(node: T, token: SyntaxKind, range: SourceMapRange | undefined) {
const emitNode = getOrCreateEmitNode(node);
const tokenSourceMapRanges = emitNode.tokenSourceMapRanges || (emitNode.tokenSourceMapRanges = []);
tokenSourceMapRanges[token] = range;
@@ -2503,6 +2512,7 @@ namespace ts {
helpers
} = sourceEmitNode;
if (!destEmitNode) destEmitNode = {};
// We are using `.slice()` here in case `destEmitNode.leadingComments` is pushed to later.
if (leadingComments) destEmitNode.leadingComments = addRange(leadingComments.slice(), destEmitNode.leadingComments);
if (trailingComments) destEmitNode.trailingComments = addRange(trailingComments.slice(), destEmitNode.trailingComments);
if (flags) destEmitNode.flags = flags;
@@ -3840,23 +3850,34 @@ namespace ts {
return emitNode && emitNode.externalHelpersModuleName;
}
export function getOrCreateExternalHelpersModuleNameIfNeeded(node: SourceFile, compilerOptions: CompilerOptions) {
if (compilerOptions.importHelpers && (isExternalModule(node) || compilerOptions.isolatedModules)) {
export function getOrCreateExternalHelpersModuleNameIfNeeded(node: SourceFile, compilerOptions: CompilerOptions, hasExportStarsToExportValues?: boolean) {
if (compilerOptions.importHelpers && isEffectiveExternalModule(node, compilerOptions)) {
const externalHelpersModuleName = getExternalHelpersModuleName(node);
if (externalHelpersModuleName) {
return externalHelpersModuleName;
}
const helpers = getEmitHelpers(node);
if (helpers) {
for (const helper of helpers) {
if (!helper.scoped) {
const parseNode = getOriginalNode(node, isSourceFile);
const emitNode = getOrCreateEmitNode(parseNode);
return emitNode.externalHelpersModuleName || (emitNode.externalHelpersModuleName = createUniqueName(externalHelpersModuleNameText));
const moduleKind = getEmitModuleKind(compilerOptions);
let create = hasExportStarsToExportValues
&& moduleKind !== ModuleKind.System
&& moduleKind !== ModuleKind.ES2015;
if (!create) {
const helpers = getEmitHelpers(node);
if (helpers) {
for (const helper of helpers) {
if (!helper.scoped) {
create = true;
break;
}
}
}
}
if (create) {
const parseNode = getOriginalNode(node, isSourceFile);
const emitNode = getOrCreateEmitNode(parseNode);
return emitNode.externalHelpersModuleName || (emitNode.externalHelpersModuleName = createUniqueName(externalHelpersModuleNameText));
}
}
}
@@ -4239,17 +4260,6 @@ namespace ts {
let exportEquals: ExportAssignment = undefined;
let hasExportStarsToExportValues = false;
const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(sourceFile, compilerOptions);
const externalHelpersImportDeclaration = externalHelpersModuleName && createImportDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createImportClause(/*name*/ undefined, createNamespaceImport(externalHelpersModuleName)),
createLiteral(externalHelpersModuleNameText));
if (externalHelpersImportDeclaration) {
externalImports.push(externalHelpersImportDeclaration);
}
for (const node of sourceFile.statements) {
switch (node.kind) {
case SyntaxKind.ImportDeclaration:
@@ -4360,6 +4370,17 @@ namespace ts {
}
}
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 };
}
+5 -5
View File
@@ -815,15 +815,15 @@ 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 {
const path = tryFile(candidate + ext, failedLookupLocations, onlyRecordFailures, state);
function tryExtension(extension: Extension): Resolved | undefined {
const path = tryFile(candidate + extension, failedLookupLocations, onlyRecordFailures, state);
return path && { path, extension };
}
}
+80 -49
View File
@@ -15,7 +15,7 @@ namespace ts {
else if (kind === SyntaxKind.Identifier) {
return new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, pos, end);
}
else if (kind < SyntaxKind.FirstNode) {
else if (!isNodeKind(kind)) {
return new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, pos, end);
}
else {
@@ -46,10 +46,16 @@ namespace ts {
}
}
// Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes
// stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise,
// embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns
// a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned.
/**
* Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes
* stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise,
* embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns
* a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned.
*
* @param node a given node to visit its children
* @param cbNode a callback to be invoked for all child nodes
* @param cbNodeArray a callback to be invoked for embedded array
*/
export function forEachChild<T>(node: Node, cbNode: (node: Node) => T | undefined, cbNodeArray?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
if (!node) {
return;
@@ -475,7 +481,11 @@ namespace ts {
// becoming detached from any SourceFile). It is recommended that this SourceFile not
// be used once 'update' is called on it.
export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile {
return IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks);
const newSourceFile = IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks);
// Because new source file node is created, it may not have the flag PossiblyContainDynamicImport. This is the case if there is no new edit to add dynamic import.
// We will manually port the flag to the new source file.
newSourceFile.flags |= (sourceFile.flags & NodeFlags.PossiblyContainsDynamicImport);
return newSourceFile;
}
/* @internal */
@@ -754,7 +764,7 @@ namespace ts {
sourceFile.languageVersion = languageVersion;
sourceFile.fileName = normalizePath(fileName);
sourceFile.languageVariant = getLanguageVariant(scriptKind);
sourceFile.isDeclarationFile = fileExtensionIs(sourceFile.fileName, ".d.ts");
sourceFile.isDeclarationFile = fileExtensionIs(sourceFile.fileName, Extension.Dts);
sourceFile.scriptKind = scriptKind;
return sourceFile;
@@ -1093,7 +1103,7 @@ namespace ts {
pos = scanner.getStartPos();
}
return kind >= SyntaxKind.FirstNode ? new NodeConstructor(kind, pos, pos) :
return isNodeKind(kind) ? new NodeConstructor(kind, pos, pos) :
kind === SyntaxKind.Identifier ? new IdentifierConstructor(kind, pos, pos) :
new TokenConstructor(kind, pos, pos);
}
@@ -2409,7 +2419,7 @@ namespace ts {
if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
return parseSignatureMember(SyntaxKind.CallSignature);
}
if (token() === SyntaxKind.NewKeyword && lookAhead(isStartOfConstructSignature)) {
if (token() === SyntaxKind.NewKeyword && lookAhead(nextTokenIsOpenParenOrLessThan)) {
return parseSignatureMember(SyntaxKind.ConstructSignature);
}
const fullStart = getNodePos();
@@ -2420,7 +2430,7 @@ namespace ts {
return parsePropertyOrMethodSignature(fullStart, modifiers);
}
function isStartOfConstructSignature() {
function nextTokenIsOpenParenOrLessThan() {
nextToken();
return token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken;
}
@@ -2777,6 +2787,8 @@ namespace ts {
case SyntaxKind.SlashEqualsToken:
case SyntaxKind.Identifier:
return true;
case SyntaxKind.ImportKeyword:
return lookAhead(nextTokenIsOpenParenOrLessThan);
default:
return isIdentifier();
}
@@ -3509,10 +3521,10 @@ namespace ts {
* 5) --UnaryExpression[?Yield]
*/
if (isUpdateExpression()) {
const incrementExpression = parseIncrementExpression();
const updateExpression = parseUpdateExpression();
return token() === SyntaxKind.AsteriskAsteriskToken ?
<BinaryExpression>parseBinaryExpressionRest(getBinaryOperatorPrecedence(), incrementExpression) :
incrementExpression;
<BinaryExpression>parseBinaryExpressionRest(getBinaryOperatorPrecedence(), updateExpression) :
updateExpression;
}
/**
@@ -3578,7 +3590,7 @@ namespace ts {
}
// falls through
default:
return parseIncrementExpression();
return parseUpdateExpression();
}
}
@@ -3594,7 +3606,7 @@ namespace ts {
*/
function isUpdateExpression(): boolean {
// This function is called inside parseUnaryExpression to decide
// whether to call parseSimpleUnaryExpression or call parseIncrementExpression directly
// whether to call parseSimpleUnaryExpression or call parseUpdateExpression directly
switch (token()) {
case SyntaxKind.PlusToken:
case SyntaxKind.MinusToken:
@@ -3618,9 +3630,9 @@ namespace ts {
}
/**
* Parse ES7 IncrementExpression. IncrementExpression is used instead of ES6's PostFixExpression.
* Parse ES7 UpdateExpression. UpdateExpression is used instead of ES6's PostFixExpression.
*
* ES7 IncrementExpression[yield]:
* ES7 UpdateExpression[yield]:
* 1) LeftHandSideExpression[?yield]
* 2) LeftHandSideExpression[?yield] [[no LineTerminator here]]++
* 3) LeftHandSideExpression[?yield] [[no LineTerminator here]]--
@@ -3628,7 +3640,7 @@ namespace ts {
* 5) --LeftHandSideExpression[?yield]
* In TypeScript (2), (3) are parsed as PostfixUnaryExpression. (4), (5) are parsed as PrefixUnaryExpression
*/
function parseIncrementExpression(): IncrementExpression {
function parseUpdateExpression(): UpdateExpression {
if (token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) {
const node = <PrefixUnaryExpression>createNode(SyntaxKind.PrefixUnaryExpression);
node.operator = <PrefixUnaryOperator>token();
@@ -3678,17 +3690,27 @@ namespace ts {
// CallExpression Arguments
// CallExpression[Expression]
// CallExpression.IdentifierName
// super ( ArgumentListopt )
// import (AssignmentExpression)
// super Arguments
// super.IdentifierName
//
// Because of the recursion in these calls, we need to bottom out first. There are two
// bottom out states we can run into. Either we see 'super' which must start either of
// the last two CallExpression productions. Or we have a MemberExpression which either
// completes the LeftHandSideExpression, or starts the beginning of the first four
// CallExpression productions.
const expression = token() === SyntaxKind.SuperKeyword
? parseSuperExpression()
: parseMemberExpressionOrHigher();
// Because of the recursion in these calls, we need to bottom out first. There are three
// bottom out states we can run into: 1) We see 'super' which must start either of
// the last two CallExpression productions. 2) We see 'import' which must start import call.
// 3)we have a MemberExpression which either completes the LeftHandSideExpression,
// or starts the beginning of the first four CallExpression productions.
let expression: MemberExpression;
if (token() === SyntaxKind.ImportKeyword) {
// We don't want to eagerly consume all import keyword as import call expression so we look a head to find "("
// For example:
// var foo3 = require("subfolder
// import * as foo1 from "module-from-node -> we want this import to be a statement rather than import call expression
sourceFile.flags |= NodeFlags.PossiblyContainsDynamicImport;
expression = parseTokenNode<PrimaryExpression>();
}
else {
expression = token() === SyntaxKind.SuperKeyword ? parseSuperExpression() : parseMemberExpressionOrHigher();
}
// Now, we *may* be complete. However, we might have consumed the start of a
// CallExpression. As such, we need to consume the rest of it here to be complete.
@@ -3696,7 +3718,7 @@ namespace ts {
}
function parseMemberExpressionOrHigher(): MemberExpression {
// Note: to make our lives simpler, we decompose the the NewExpression productions and
// Note: to make our lives simpler, we decompose the NewExpression productions and
// place ObjectCreationExpression and FunctionExpression into PrimaryExpression.
// like so:
//
@@ -4792,9 +4814,11 @@ namespace ts {
case SyntaxKind.FinallyKeyword:
return true;
case SyntaxKind.ImportKeyword:
return isStartOfDeclaration() || lookAhead(nextTokenIsOpenParenOrLessThan);
case SyntaxKind.ConstKeyword:
case SyntaxKind.ExportKeyword:
case SyntaxKind.ImportKeyword:
return isStartOfDeclaration();
case SyntaxKind.AsyncKeyword:
@@ -6513,6 +6537,10 @@ namespace ts {
case "augments":
tag = parseAugmentsTag(atToken, tagName);
break;
case "class":
case "constructor":
tag = parseClassTag(atToken, tagName);
break;
case "arg":
case "argument":
case "param":
@@ -6639,14 +6667,12 @@ namespace ts {
});
}
function parseBracketNameInPropertyAndParamTag() {
let name: Identifier;
let isBracketed: boolean;
function parseBracketNameInPropertyAndParamTag(): { name: Identifier, isBracketed: boolean } {
// Looking for something like '[foo]' or 'foo'
if (parseOptionalToken(SyntaxKind.OpenBracketToken)) {
name = parseJSDocIdentifierName();
const isBracketed = parseOptional(SyntaxKind.OpenBracketToken);
const name = parseJSDocIdentifierName(/*createIfMissing*/ true);
if (isBracketed) {
skipWhitespace();
isBracketed = true;
// May have an optional default, e.g. '[foo = 42]'
if (parseOptionalToken(SyntaxKind.EqualsToken)) {
@@ -6655,9 +6681,7 @@ namespace ts {
parseExpected(SyntaxKind.CloseBracketToken);
}
else if (tokenIsIdentifierOrKeyword(token())) {
name = parseJSDocIdentifierName();
}
return { name, isBracketed };
}
@@ -6668,11 +6692,6 @@ namespace ts {
const { name, isBracketed } = parseBracketNameInPropertyAndParamTag();
skipWhitespace();
if (!name) {
parseErrorAtPosition(scanner.getStartPos(), 0, Diagnostics.Identifier_expected);
return undefined;
}
let preName: Identifier, postName: Identifier;
if (typeExpression) {
postName = name;
@@ -6732,6 +6751,13 @@ namespace ts {
return finishNode(result);
}
function parseClassTag(atToken: AtToken, tagName: Identifier): JSDocClassTag {
const tag = <JSDocClassTag>createNode(SyntaxKind.JSDocClassTag, atToken.pos);
tag.atToken = atToken;
tag.tagName = tagName;
return finishNode(tag);
}
function parseTypedefTag(atToken: AtToken, tagName: Identifier): JSDocTypedefTag {
const typeExpression = tryParseTypeExpression();
skipWhitespace();
@@ -6825,7 +6851,7 @@ namespace ts {
jsDocNamespaceNode.flags |= flags;
jsDocNamespaceNode.name = typeNameOrNamespaceName;
jsDocNamespaceNode.body = parseJSDocTypeNameWithNamespace(NodeFlags.NestedNamespace);
return jsDocNamespaceNode;
return finishNode(jsDocNamespaceNode);
}
if (typeNameOrNamespaceName && flags & NodeFlags.NestedNamespace) {
@@ -6916,14 +6942,19 @@ namespace ts {
return currentToken = scanner.scanJSDocToken();
}
function parseJSDocIdentifierName(): Identifier {
return createJSDocIdentifier(tokenIsIdentifierOrKeyword(token()));
function parseJSDocIdentifierName(createIfMissing = false): Identifier {
return createJSDocIdentifier(tokenIsIdentifierOrKeyword(token()), createIfMissing);
}
function createJSDocIdentifier(isIdentifier: boolean): Identifier {
function createJSDocIdentifier(isIdentifier: boolean, createIfMissing: boolean): Identifier {
if (!isIdentifier) {
parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
return undefined;
if (createIfMissing) {
return <Identifier>createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected);
}
else {
parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
return undefined;
}
}
const pos = scanner.getTokenPos();
+22 -23
View File
@@ -984,16 +984,12 @@ namespace ts {
if (sourceFile) {
return getDiagnostics(sourceFile, cancellationToken);
}
const allDiagnostics: Diagnostic[] = [];
forEach(program.getSourceFiles(), sourceFile => {
return sortAndDeduplicateDiagnostics(flatMap(program.getSourceFiles(), sourceFile => {
if (cancellationToken) {
cancellationToken.throwIfCancellationRequested();
}
addRange(allDiagnostics, getDiagnostics(sourceFile, cancellationToken));
});
return sortAndDeduplicateDiagnostics(allDiagnostics);
return getDiagnostics(sourceFile, cancellationToken);
}));
}
function getSyntacticDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
@@ -1069,10 +1065,10 @@ namespace ts {
const typeChecker = getDiagnosticsProducingTypeChecker();
Debug.assert(!!sourceFile.bindDiagnostics);
const bindDiagnostics = sourceFile.bindDiagnostics;
// For JavaScript files, we don't want to report semantic errors unless explicitly requested.
const includeCheckDiagnostics = !isSourceFileJavaScript(sourceFile) || isCheckJsEnabledForFile(sourceFile, options);
const checkDiagnostics = includeCheckDiagnostics ? typeChecker.getDiagnostics(sourceFile, cancellationToken) : [];
const includeBindAndCheckDiagnostics = !isSourceFileJavaScript(sourceFile) || isCheckJsEnabledForFile(sourceFile, options);
const bindDiagnostics = includeBindAndCheckDiagnostics ? sourceFile.bindDiagnostics : emptyArray;
const checkDiagnostics = includeBindAndCheckDiagnostics ? typeChecker.getDiagnostics(sourceFile, cancellationToken) : emptyArray;
const fileProcessingDiagnosticsInFile = fileProcessingDiagnostics.getDiagnostics(sourceFile.fileName);
const programDiagnosticsInFile = programDiagnostics.getDiagnostics(sourceFile.fileName);
@@ -1330,16 +1326,13 @@ namespace ts {
}
function getOptionsDiagnostics(): Diagnostic[] {
const allDiagnostics: Diagnostic[] = [];
addRange(allDiagnostics, fileProcessingDiagnostics.getGlobalDiagnostics());
addRange(allDiagnostics, programDiagnostics.getGlobalDiagnostics());
return sortAndDeduplicateDiagnostics(allDiagnostics);
return sortAndDeduplicateDiagnostics(concatenate(
fileProcessingDiagnostics.getGlobalDiagnostics(),
programDiagnostics.getGlobalDiagnostics()));
}
function getGlobalDiagnostics(): Diagnostic[] {
const allDiagnostics: Diagnostic[] = [];
addRange(allDiagnostics, getDiagnosticsProducingTypeChecker().getGlobalDiagnostics());
return sortAndDeduplicateDiagnostics(allDiagnostics);
return sortAndDeduplicateDiagnostics(getDiagnosticsProducingTypeChecker().getGlobalDiagnostics().slice());
}
function processRootFile(fileName: string, isDefaultLib: boolean) {
@@ -1366,6 +1359,7 @@ namespace ts {
const isJavaScriptFile = isSourceFileJavaScript(file);
const isExternalModuleFile = isExternalModule(file);
// file.imports may not be undefined if there exists dynamic import
let imports: LiteralExpression[];
let moduleAugmentations: LiteralExpression[];
let ambientModules: string[];
@@ -1385,8 +1379,8 @@ namespace ts {
for (const node of file.statements) {
collectModuleReferences(node, /*inAmbientModule*/ false);
if (isJavaScriptFile) {
collectRequireCalls(node);
if ((file.flags & NodeFlags.PossiblyContainsDynamicImport) || isJavaScriptFile) {
collectDynamicImportOrRequireCalls(node);
}
}
@@ -1449,12 +1443,16 @@ namespace ts {
}
}
function collectRequireCalls(node: Node): void {
function collectDynamicImportOrRequireCalls(node: Node): void {
if (isRequireCall(node, /*checkArgumentIsStringLiteral*/ true)) {
(imports || (imports = [])).push(<StringLiteral>(<CallExpression>node).arguments[0]);
}
// we have to check the argument list has length of 1. We will still have to process these even though we have parsing error.
else if (isImportCall(node) && node.arguments.length === 1 && node.arguments[0].kind === SyntaxKind.StringLiteral) {
(imports || (imports = [])).push(<StringLiteral>(<CallExpression>node).arguments[0]);
}
else {
forEachChild(node, collectRequireCalls);
forEachChild(node, collectDynamicImportOrRequireCalls);
}
}
}
@@ -1486,7 +1484,8 @@ namespace ts {
}
}
return sourceFile;
} else {
}
else {
const sourceFileNoExtension = options.allowNonTsExtensions && getSourceFile(fileName);
if (sourceFileNoExtension) return sourceFileNoExtension;
@@ -1496,7 +1495,7 @@ namespace ts {
}
const sourceFileWithAddedExtension = forEach(supportedExtensions, extension => getSourceFile(fileName + extension));
if (fail && !sourceFileWithAddedExtension) fail(Diagnostics.File_0_not_found, fileName + ".ts");
if (fail && !sourceFileWithAddedExtension) fail(Diagnostics.File_0_not_found, fileName + Extension.Ts);
return sourceFileWithAddedExtension;
}
}
+2 -2
View File
@@ -286,7 +286,7 @@ namespace ts {
const tokenStrings = makeReverseMap(textToToken);
export function tokenToString(t: SyntaxKind): string {
export function tokenToString(t: SyntaxKind): string | undefined {
return tokenStrings[t];
}
@@ -363,7 +363,7 @@ namespace ts {
};
}
export function getLineAndCharacterOfPosition(sourceFile: SourceFile, position: number): LineAndCharacter {
export function getLineAndCharacterOfPosition(sourceFile: SourceFileLike, position: number): LineAndCharacter {
return computeLineAndCharacterOfPosition(getLineStarts(sourceFile), position);
}
+33 -14
View File
@@ -22,7 +22,7 @@ namespace ts {
*
* @param sourceFile The source file.
*/
setSourceFile(sourceFile: SourceFile): void;
setSourceFile(sourceFile: SourceMapSource): void;
/**
* Emits a mapping.
@@ -81,7 +81,7 @@ namespace ts {
export function createSourceMapWriter(host: EmitHost, writer: EmitTextWriter): SourceMapWriter {
const compilerOptions = host.getCompilerOptions();
const extendedDiagnostics = compilerOptions.extendedDiagnostics;
let currentSourceFile: SourceFile;
let currentSource: SourceMapSource;
let currentSourceText: string;
let sourceMapDir: string; // The directory in which sourcemap will be
@@ -109,6 +109,13 @@ namespace ts {
getSourceMappingURL,
};
/**
* Skips trivia such as comments and white-space that can optionally overriden by the source map source
*/
function skipSourceTrivia(pos: number): number {
return currentSource.skipTrivia ? currentSource.skipTrivia(pos) : skipTrivia(currentSourceText, pos);
}
/**
* Initialize the SourceMapWriter for a new output file.
*
@@ -125,7 +132,7 @@ namespace ts {
reset();
}
currentSourceFile = undefined;
currentSource = undefined;
currentSourceText = undefined;
// Current source map file and its index in the sources list
@@ -192,7 +199,7 @@ namespace ts {
return;
}
currentSourceFile = undefined;
currentSource = undefined;
sourceMapDir = undefined;
sourceMapSourceIndex = undefined;
lastRecordedSourceMapSpan = undefined;
@@ -263,7 +270,7 @@ namespace ts {
performance.mark("beforeSourcemap");
}
const sourceLinePos = getLineAndCharacterOfPosition(currentSourceFile, pos);
const sourceLinePos = getLineAndCharacterOfPosition(currentSource, pos);
// Convert the location to be one-based.
sourceLinePos.line++;
@@ -320,14 +327,22 @@ namespace ts {
if (node) {
const emitNode = node.emitNode;
const emitFlags = emitNode && emitNode.flags;
const { pos, end } = emitNode && emitNode.sourceMapRange || node;
const range = emitNode && emitNode.sourceMapRange;
const { pos, end } = range || node;
let source = range && range.source;
const oldSource = currentSource;
if (source === oldSource) source = undefined;
if (source) setSourceFile(source);
if (node.kind !== SyntaxKind.NotEmittedStatement
&& (emitFlags & EmitFlags.NoLeadingSourceMap) === 0
&& pos >= 0) {
emitPos(skipTrivia(currentSourceText, pos));
emitPos(skipSourceTrivia(pos));
}
if (source) setSourceFile(oldSource);
if (emitFlags & EmitFlags.NoNestedSourceMaps) {
disabled = true;
emitCallback(hint, node);
@@ -337,11 +352,15 @@ namespace ts {
emitCallback(hint, node);
}
if (source) setSourceFile(source);
if (node.kind !== SyntaxKind.NotEmittedStatement
&& (emitFlags & EmitFlags.NoTrailingSourceMap) === 0
&& end >= 0) {
emitPos(end);
}
if (source) setSourceFile(oldSource);
}
}
@@ -362,7 +381,7 @@ namespace ts {
const emitFlags = emitNode && emitNode.flags;
const range = emitNode && emitNode.tokenSourceMapRanges && emitNode.tokenSourceMapRanges[token];
tokenPos = skipTrivia(currentSourceText, range ? range.pos : tokenPos);
tokenPos = skipSourceTrivia(range ? range.pos : tokenPos);
if ((emitFlags & EmitFlags.NoTokenLeadingSourceMaps) === 0 && tokenPos >= 0) {
emitPos(tokenPos);
}
@@ -382,13 +401,13 @@ namespace ts {
*
* @param sourceFile The source file.
*/
function setSourceFile(sourceFile: SourceFile) {
function setSourceFile(sourceFile: SourceMapSource) {
if (disabled) {
return;
}
currentSourceFile = sourceFile;
currentSourceText = currentSourceFile.text;
currentSource = sourceFile;
currentSourceText = currentSource.text;
// Add the file to tsFilePaths
// If sourceroot option: Use the relative path corresponding to the common directory path
@@ -396,7 +415,7 @@ namespace ts {
const sourcesDirectoryPath = compilerOptions.sourceRoot ? host.getCommonSourceDirectory() : sourceMapDir;
const source = getRelativePathToDirectoryOrUrl(sourcesDirectoryPath,
currentSourceFile.fileName,
currentSource.fileName,
host.getCurrentDirectory(),
host.getCanonicalFileName,
/*isAbsolutePathAnUrl*/ true);
@@ -407,10 +426,10 @@ namespace ts {
sourceMapData.sourceMapSources.push(source);
// The one that can be used from program to get the actual source file
sourceMapData.inputSourceFileNames.push(currentSourceFile.fileName);
sourceMapData.inputSourceFileNames.push(currentSource.fileName);
if (compilerOptions.inlineSources) {
sourceMapData.sourceMapSourcesContent.push(currentSourceFile.text);
sourceMapData.sourceMapSourcesContent.push(currentSource.text);
}
}
}
+4
View File
@@ -35,6 +35,10 @@ namespace ts {
getDirectories(path: string): string[];
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[];
getModifiedTime?(path: string): Date;
/**
* This should be cryptographically secure.
* A good implementation is node.js' `crypto.createHash`. (https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm)
*/
createHash?(data: string): string;
getMemoryUsage?(): number;
exit(exitCode?: number): void;
+2 -1
View File
@@ -15,6 +15,7 @@
namespace ts {
function getModuleTransformer(moduleKind: ModuleKind): TransformerFactory<SourceFile> {
switch (moduleKind) {
case ModuleKind.ESNext:
case ModuleKind.ES2015:
return transformES2015Module;
case ModuleKind.System:
@@ -238,7 +239,7 @@ namespace ts {
function hoistVariableDeclaration(name: Identifier): void {
Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization.");
Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed.");
const decl = createVariableDeclaration(name);
const decl = setEmitFlags(createVariableDeclaration(name), EmitFlags.NoNestedSourceMaps);
if (!lexicalEnvironmentVariableDeclarations) {
lexicalEnvironmentVariableDeclarations = [decl];
}
+2 -2
View File
@@ -2095,9 +2095,9 @@ namespace ts {
enableSubstitutionsForBlockScopedBindings();
}
const declarations = flatten(map(node.declarations, node.flags & NodeFlags.Let
const declarations = flatMap(node.declarations, node.flags & NodeFlags.Let
? visitVariableDeclarationInLetDeclarationList
: visitVariableDeclaration));
: visitVariableDeclaration);
const declarationList = createVariableDeclarationList(declarations);
setOriginalNode(declarationList, node);
+7 -5
View File
@@ -351,8 +351,10 @@ namespace ts {
);
}
function awaitAsYield(expression: Expression) {
return createYield(/*asteriskToken*/ undefined, enclosingFunctionFlags & FunctionFlags.Generator ? createAwaitHelper(context, expression) : expression);
function createDownlevelAwait(expression: Expression) {
return enclosingFunctionFlags & FunctionFlags.Generator
? createYield(/*asteriskToken*/ undefined, createAwaitHelper(context, expression))
: createAwait(expression);
}
function transformForAwaitOfStatement(node: ForOfStatement, outermostLabeledStatement: LabeledStatement) {
@@ -385,11 +387,11 @@ namespace ts {
EmitFlags.NoHoisting
),
/*condition*/ createComma(
createAssignment(result, awaitAsYield(callNext)),
createAssignment(result, createDownlevelAwait(callNext)),
createLogicalNot(getDone)
),
/*incrementor*/ undefined,
/*statement*/ convertForOfStatementHead(node, awaitAsYield(getValue))
/*statement*/ convertForOfStatementHead(node, createDownlevelAwait(getValue))
),
/*location*/ node
),
@@ -434,7 +436,7 @@ namespace ts {
createPropertyAccess(iterator, "return")
)
),
createStatement(awaitAsYield(callReturn))
createStatement(createDownlevelAwait(callReturn))
),
EmitFlags.SingleLine
)
+13 -7
View File
@@ -640,10 +640,13 @@ namespace ts {
return undefined;
}
return createStatement(
inlineExpressions(
map(variables, transformInitializedVariable)
)
return setSourceMapRange(
createStatement(
inlineExpressions(
map(variables, transformInitializedVariable)
)
),
node
);
}
}
@@ -1281,9 +1284,12 @@ namespace ts {
}
function transformInitializedVariable(node: VariableDeclaration) {
return createAssignment(
<Identifier>getSynthesizedClone(node.name),
visitNode(node.initializer, visitor, isExpression)
return setSourceMapRange(
createAssignment(
setSourceMapRange(<Identifier>getSynthesizedClone(node.name), node.name),
visitNode(node.initializer, visitor, isExpression)
),
node
);
}
+136 -25
View File
@@ -46,6 +46,7 @@ namespace ts {
let currentSourceFile: SourceFile; // The current file.
let currentModuleInfo: ExternalModuleInfo; // The ExternalModuleInfo for the current file.
let noSubstitution: boolean[]; // Set of nodes for which substitution rules should be ignored.
let needUMDDynamicImportHelper: boolean;
return transformSourceFile;
@@ -55,7 +56,7 @@ namespace ts {
* @param node The SourceFile node.
*/
function transformSourceFile(node: SourceFile) {
if (node.isDeclarationFile || !(isExternalModule(node) || compilerOptions.isolatedModules)) {
if (node.isDeclarationFile || !(isExternalModule(node) || compilerOptions.isolatedModules || node.transformFlags & TransformFlags.ContainsDynamicImport)) {
return node;
}
@@ -66,9 +67,9 @@ namespace ts {
// Perform the transformation.
const transformModule = getTransformModuleDelegate(moduleKind);
const updated = transformModule(node);
currentSourceFile = undefined;
currentModuleInfo = undefined;
needUMDDynamicImportHelper = false;
return aggregateTransformFlags(updated);
}
@@ -102,11 +103,12 @@ namespace ts {
addRange(statements, endLexicalEnvironment());
const updated = updateSourceFileNode(node, setTextRange(createNodeArray(statements), node.statements));
if (currentModuleInfo.hasExportStarsToExportValues) {
if (currentModuleInfo.hasExportStarsToExportValues && !compilerOptions.importHelpers) {
// If we have any `export * from ...` declarations
// we need to inform the emitter to add the __export helper.
addEmitHelper(updated, exportStarHelper);
}
addEmitHelpers(updated, context.readEmitHelpers());
return updated;
}
@@ -406,11 +408,14 @@ namespace ts {
addRange(statements, endLexicalEnvironment());
const body = createBlock(statements, /*multiLine*/ true);
if (currentModuleInfo.hasExportStarsToExportValues) {
if (currentModuleInfo.hasExportStarsToExportValues && !compilerOptions.importHelpers) {
// If we have any `export * from ...` declarations
// we need to inform the emitter to add the __export helper.
addEmitHelper(body, exportStarHelper);
}
if (needUMDDynamicImportHelper) {
addEmitHelper(body, dynamicImportUMDHelper);
}
return body;
}
@@ -488,12 +493,110 @@ namespace ts {
return visitEndOfDeclarationMarker(<EndOfDeclarationMarker>node);
default:
// This visitor does not descend into the tree, as export/import statements
// are only transformed at the top level of a file.
return node;
return visitEachChild(node, importCallExpressionVisitor, context);
}
}
function importCallExpressionVisitor(node: Node): VisitResult<Node> {
// 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)) {
return node;
}
if (isImportCall(node)) {
return visitImportCallExpression(<ImportCall>node);
}
else {
return visitEachChild(node, importCallExpressionVisitor, context);
}
}
function visitImportCallExpression(node: ImportCall): Expression {
switch (compilerOptions.module) {
case ModuleKind.AMD:
return transformImportCallExpressionAMD(node);
case ModuleKind.UMD:
return transformImportCallExpressionUMD(node);
case ModuleKind.CommonJS:
default:
return transformImportCallExpressionCommonJS(node);
}
}
function transformImportCallExpressionUMD(node: ImportCall): Expression {
// (function (factory) {
// ... (regular UMD)
// }
// })(function (require, exports, useSyncRequire) {
// "use strict";
// Object.defineProperty(exports, "__esModule", { value: true });
// var __syncRequire = typeof module === "object" && typeof module.exports === "object";
// var __resolved = new Promise(function (resolve) { resolve(); });
// .....
// __syncRequire
// ? __resolved.then(function () { return require(x); }) /*CommonJs Require*/
// : new Promise(function (_a, _b) { require([x], _a, _b); }); /*Amd Require*/
// });
needUMDDynamicImportHelper = true;
return createConditional(
/*condition*/ createIdentifier("__syncRequire"),
/*whenTrue*/ transformImportCallExpressionCommonJS(node),
/*whenFalse*/ transformImportCallExpressionAMD(node)
);
}
function transformImportCallExpressionAMD(node: ImportCall): Expression {
// improt("./blah")
// emit as
// define(["require", "exports", "blah"], function (require, exports) {
// ...
// new Promise(function (_a, _b) { require([x], _a, _b); }); /*Amd Require*/
// });
const resolve = createUniqueName("resolve");
const reject = createUniqueName("reject");
return createNew(
createIdentifier("Promise"),
/*typeArguments*/ undefined,
[createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
[createParameter(/*decorator*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ resolve),
createParameter(/*decorator*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ reject)],
/*type*/ undefined,
createBlock([createStatement(
createCall(
createIdentifier("require"),
/*typeArguments*/ undefined,
[createArrayLiteral([firstOrUndefined(node.arguments) || createOmittedExpression()]), resolve, reject]
))])
)]);
}
function transformImportCallExpressionCommonJS(node: ImportCall): Expression {
// import("./blah")
// emit as
// Promise.resolve().then(function () { return require(x); }) /*CommonJs Require*/
// We have to wrap require in then callback so that require is done in asynchronously
// if we simply do require in resolve callback in Promise constructor. We will execute the loading immediately
return createCall(
createPropertyAccess(
createCall(createPropertyAccess(createIdentifier("Promise"), "resolve"), /*typeArguments*/ undefined, /*argumentsArray*/ []),
"then"),
/*typeArguments*/ undefined,
[createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
/*parameters*/ undefined,
/*type*/ undefined,
createBlock([createReturn(createCall(createIdentifier("require"), /*typeArguments*/ undefined, node.arguments))])
)]);
}
/**
* Visits an ImportDeclaration node.
*
@@ -730,15 +833,7 @@ namespace ts {
// export * from "mod";
return setTextRange(
createStatement(
createCall(
createIdentifier("__export"),
/*typeArguments*/ undefined,
[
moduleKind !== ModuleKind.AMD
? createRequireCall(node)
: generatedName
]
)
createExportStarHelper(context, moduleKind !== ModuleKind.AMD ? createRequireCall(node) : generatedName)
),
node
);
@@ -786,9 +881,9 @@ namespace ts {
node.asteriskToken,
getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true),
/*typeParameters*/ undefined,
node.parameters,
visitNodes(node.parameters, importCallExpressionVisitor),
/*type*/ undefined,
node.body
visitEachChild(node.body, importCallExpressionVisitor, context)
),
/*location*/ node
),
@@ -797,7 +892,7 @@ namespace ts {
);
}
else {
statements = append(statements, node);
statements = append(statements, visitEachChild(node, importCallExpressionVisitor, context));
}
if (hasAssociatedEndOfDeclarationMarker(node)) {
@@ -828,7 +923,7 @@ namespace ts {
visitNodes(node.modifiers, modifierVisitor, isModifier),
getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true),
/*typeParameters*/ undefined,
node.heritageClauses,
visitNodes(node.heritageClauses, importCallExpressionVisitor),
node.members
),
node
@@ -838,7 +933,7 @@ namespace ts {
);
}
else {
statements = append(statements, node);
statements = append(statements, visitEachChild(node, importCallExpressionVisitor, context));
}
if (hasAssociatedEndOfDeclarationMarker(node)) {
@@ -890,7 +985,7 @@ namespace ts {
}
}
else {
statements = append(statements, node);
statements = append(statements, visitEachChild(node, importCallExpressionVisitor, context));
}
if (hasAssociatedEndOfDeclarationMarker(node)) {
@@ -913,7 +1008,7 @@ namespace ts {
function transformInitializedVariable(node: VariableDeclaration): Expression {
if (isBindingPattern(node.name)) {
return flattenDestructuringAssignment(
node,
visitNode(node, importCallExpressionVisitor),
/*visitor*/ undefined,
context,
FlattenLevel.All,
@@ -930,7 +1025,7 @@ namespace ts {
),
/*location*/ node.name
),
node.initializer
visitNode(node.initializer, importCallExpressionVisitor)
);
}
}
@@ -1495,6 +1590,22 @@ namespace ts {
text: `
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}`
}
`
};
function createExportStarHelper(context: TransformationContext, module: Expression) {
const compilerOptions = context.getCompilerOptions();
return compilerOptions.importHelpers
? createCall(getHelperName("__exportStar"), /*typeArguments*/ undefined, [module, createIdentifier("exports")])
: createCall(createIdentifier("__export"), /*typeArguments*/ undefined, [module]);
}
// emit helper for dynamic import
const dynamicImportUMDHelper: EmitHelper = {
name: "typescript:dynamicimport-sync-require",
scoped: true,
text: `
var __syncRequire = typeof module === "object" && typeof module.exports === "object";`
};
}
+49 -25
View File
@@ -50,7 +50,7 @@ namespace ts {
* @param node The SourceFile node.
*/
function transformSourceFile(node: SourceFile) {
if (node.isDeclarationFile || !(isExternalModule(node) || compilerOptions.isolatedModules)) {
if (node.isDeclarationFile || !(isEffectiveExternalModule(node, compilerOptions) || node.transformFlags & TransformFlags.ContainsDynamicImport)) {
return node;
}
@@ -646,7 +646,7 @@ namespace ts {
return undefined;
}
const expression = visitNode(node.expression, destructuringVisitor, isExpression);
const expression = visitNode(node.expression, destructuringAndImportCallVisitor, isExpression);
const original = node.original;
if (original && hasAssociatedEndOfDeclarationMarker(original)) {
// Defer exports until we encounter an EndOfDeclarationMarker node
@@ -673,12 +673,12 @@ namespace ts {
node.asteriskToken,
getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true),
/*typeParameters*/ undefined,
visitNodes(node.parameters, destructuringVisitor, isParameterDeclaration),
visitNodes(node.parameters, destructuringAndImportCallVisitor, isParameterDeclaration),
/*type*/ undefined,
visitNode(node.body, destructuringVisitor, isBlock)));
visitNode(node.body, destructuringAndImportCallVisitor, isBlock)));
}
else {
hoistedStatements = append(hoistedStatements, node);
hoistedStatements = append(hoistedStatements, visitEachChild(node, destructuringAndImportCallVisitor, context));
}
if (hasAssociatedEndOfDeclarationMarker(node)) {
@@ -716,8 +716,8 @@ namespace ts {
/*modifiers*/ undefined,
node.name,
/*typeParameters*/ undefined,
visitNodes(node.heritageClauses, destructuringVisitor, isHeritageClause),
visitNodes(node.members, destructuringVisitor, isClassElement)
visitNodes(node.heritageClauses, destructuringAndImportCallVisitor, isHeritageClause),
visitNodes(node.members, destructuringAndImportCallVisitor, isClassElement)
),
node
)
@@ -747,7 +747,7 @@ namespace ts {
*/
function visitVariableStatement(node: VariableStatement): VisitResult<Statement> {
if (!shouldHoistVariableDeclarationList(node.declarationList)) {
return visitNode(node, destructuringVisitor, isStatement);
return visitNode(node, destructuringAndImportCallVisitor, isStatement);
}
let expressions: Expression[];
@@ -820,13 +820,13 @@ namespace ts {
return isBindingPattern(node.name)
? flattenDestructuringAssignment(
node,
destructuringVisitor,
destructuringAndImportCallVisitor,
context,
FlattenLevel.All,
/*needsValue*/ false,
createAssignment
)
: createAssignment(node.name, visitNode(node.initializer, destructuringVisitor, isExpression));
: createAssignment(node.name, visitNode(node.initializer, destructuringAndImportCallVisitor, isExpression));
}
/**
@@ -1204,7 +1204,7 @@ namespace ts {
return visitEndOfDeclarationMarker(<EndOfDeclarationMarker>node);
default:
return destructuringVisitor(node);
return destructuringAndImportCallVisitor(node);
}
}
@@ -1220,8 +1220,8 @@ namespace ts {
node = updateFor(
node,
visitForInitializer(node.initializer),
visitNode(node.condition, destructuringVisitor, isExpression),
visitNode(node.incrementor, destructuringVisitor, isExpression),
visitNode(node.condition, destructuringAndImportCallVisitor, isExpression),
visitNode(node.incrementor, destructuringAndImportCallVisitor, isExpression),
visitNode(node.statement, nestedElementVisitor, isStatement)
);
@@ -1241,7 +1241,7 @@ namespace ts {
node = updateForIn(
node,
visitForInitializer(node.initializer),
visitNode(node.expression, destructuringVisitor, isExpression),
visitNode(node.expression, destructuringAndImportCallVisitor, isExpression),
visitNode(node.statement, nestedElementVisitor, isStatement, liftToBlock)
);
@@ -1262,7 +1262,7 @@ namespace ts {
node,
node.awaitModifier,
visitForInitializer(node.initializer),
visitNode(node.expression, destructuringVisitor, isExpression),
visitNode(node.expression, destructuringAndImportCallVisitor, isExpression),
visitNode(node.statement, nestedElementVisitor, isStatement, liftToBlock)
);
@@ -1313,7 +1313,7 @@ namespace ts {
return updateDo(
node,
visitNode(node.statement, nestedElementVisitor, isStatement, liftToBlock),
visitNode(node.expression, destructuringVisitor, isExpression)
visitNode(node.expression, destructuringAndImportCallVisitor, isExpression)
);
}
@@ -1325,7 +1325,7 @@ namespace ts {
function visitWhileStatement(node: WhileStatement): VisitResult<Statement> {
return updateWhile(
node,
visitNode(node.expression, destructuringVisitor, isExpression),
visitNode(node.expression, destructuringAndImportCallVisitor, isExpression),
visitNode(node.statement, nestedElementVisitor, isStatement, liftToBlock)
);
}
@@ -1351,7 +1351,7 @@ namespace ts {
function visitWithStatement(node: WithStatement): VisitResult<Statement> {
return updateWith(
node,
visitNode(node.expression, destructuringVisitor, isExpression),
visitNode(node.expression, destructuringAndImportCallVisitor, isExpression),
visitNode(node.statement, nestedElementVisitor, isStatement, liftToBlock)
);
}
@@ -1364,7 +1364,7 @@ namespace ts {
function visitSwitchStatement(node: SwitchStatement): VisitResult<Statement> {
return updateSwitch(
node,
visitNode(node.expression, destructuringVisitor, isExpression),
visitNode(node.expression, destructuringAndImportCallVisitor, isExpression),
visitNode(node.caseBlock, nestedElementVisitor, isCaseBlock)
);
}
@@ -1395,7 +1395,7 @@ namespace ts {
function visitCaseClause(node: CaseClause): VisitResult<CaseOrDefaultClause> {
return updateCaseClause(
node,
visitNode(node.expression, destructuringVisitor, isExpression),
visitNode(node.expression, destructuringAndImportCallVisitor, isExpression),
visitNodes(node.statements, nestedElementVisitor, isStatement)
);
}
@@ -1461,19 +1461,43 @@ namespace ts {
*
* @param node The node to visit.
*/
function destructuringVisitor(node: Node): VisitResult<Node> {
function destructuringAndImportCallVisitor(node: Node): VisitResult<Node> {
if (node.transformFlags & TransformFlags.DestructuringAssignment
&& node.kind === SyntaxKind.BinaryExpression) {
return visitDestructuringAssignment(<DestructuringAssignment>node);
}
else if (node.transformFlags & TransformFlags.ContainsDestructuringAssignment) {
return visitEachChild(node, destructuringVisitor, context);
else if (isImportCall(node)) {
return visitImportCallExpression(node);
}
else if ((node.transformFlags & TransformFlags.ContainsDestructuringAssignment) || (node.transformFlags & TransformFlags.ContainsDynamicImport)) {
return visitEachChild(node, destructuringAndImportCallVisitor, context);
}
else {
return node;
}
}
function visitImportCallExpression(node: ImportCall): Expression {
// import("./blah")
// emit as
// System.register([], function (_export, _context) {
// return {
// setters: [],
// execute: () => {
// _context.import('./blah');
// }
// };
// });
return createCall(
createPropertyAccess(
contextObject,
createIdentifier("import")
),
/*typeArguments*/ undefined,
node.arguments
);
}
/**
* Visits a DestructuringAssignment to flatten destructuring to exported symbols.
*
@@ -1483,14 +1507,14 @@ namespace ts {
if (hasExportedReferenceInDestructuringTarget(node.left)) {
return flattenDestructuringAssignment(
node,
destructuringVisitor,
destructuringAndImportCallVisitor,
context,
FlattenLevel.All,
/*needsValue*/ true
);
}
return visitEachChild(node, destructuringVisitor, context);
return visitEachChild(node, destructuringAndImportCallVisitor, context);
}
/**
+4
View File
@@ -662,6 +662,10 @@ namespace ts {
}
}
if (ts.Debug.isDebugging) {
ts.Debug.enableDebugInfo();
}
if (ts.sys.tryEnableSourceMapsForHost && /^development$/i.test(ts.sys.getEnvironmentVariable("NODE_ENV"))) {
ts.sys.tryEnableSourceMapsForHost();
}
+76 -31
View File
@@ -374,6 +374,7 @@ namespace ts {
JSDocComment,
JSDocTag,
JSDocAugmentsTag,
JSDocClassTag,
JSDocParameterTag,
JSDocReturnTag,
JSDocTypeTag,
@@ -395,6 +396,7 @@ namespace ts {
// Enum value count
Count,
// Markers
FirstAssignment = EqualsToken,
LastAssignment = CaretEqualsToken,
@@ -423,7 +425,7 @@ namespace ts {
FirstNode = QualifiedName,
FirstJSDocNode = JSDocTypeExpression,
LastJSDocNode = JSDocLiteralType,
FirstJSDocTagNode = JSDocComment,
FirstJSDocTagNode = JSDocTag,
LastJSDocTagNode = JSDocLiteralType
}
@@ -449,6 +451,17 @@ namespace ts {
ThisNodeOrAnySubNodesHasError = 1 << 17, // If this node or any of its children had an error
HasAggregatedChildData = 1 << 18, // If we've computed data from children and cached it in this node
// This flag will be set when the parser encounters a dynamic import expression so that module resolution
// will not have to walk the tree if the flag is not set. However, this flag is just a approximation because
// once it is set, the flag never gets cleared (hence why it's named "PossiblyContainsDynamicImport").
// During editing, if dynamic import is removed, incremental parsing will *NOT* update this flag. This means that the tree will always be traversed
// during module resolution. However, the removal operation should not occur often and in the case of the
// removal, it is likely that users will add the import anyway.
// The advantage of this approach is its simplicity. For the case of batch compilation,
// we guarantee that users won't have to pay the price of walking the tree if a dynamic import isn't used.
/* @internal */
PossiblyContainsDynamicImport = 1 << 19,
BlockScoped = Let | Const,
ReachabilityCheckFlags = HasImplicitReturn | HasExplicitReturn,
@@ -1001,8 +1014,10 @@ namespace ts {
_unaryExpressionBrand: any;
}
export interface IncrementExpression extends UnaryExpression {
_incrementExpressionBrand: any;
/** Deprecated, please use UpdateExpression */
export type IncrementExpression = UpdateExpression;
export interface UpdateExpression extends UnaryExpression {
_updateExpressionBrand: any;
}
// see: https://tc39.github.io/ecma262/#prod-UpdateExpression
@@ -1013,10 +1028,9 @@ namespace ts {
| SyntaxKind.PlusToken
| SyntaxKind.MinusToken
| SyntaxKind.TildeToken
| SyntaxKind.ExclamationToken
;
| SyntaxKind.ExclamationToken;
export interface PrefixUnaryExpression extends IncrementExpression {
export interface PrefixUnaryExpression extends UpdateExpression {
kind: SyntaxKind.PrefixUnaryExpression;
operator: PrefixUnaryOperator;
operand: UnaryExpression;
@@ -1028,13 +1042,13 @@ namespace ts {
| SyntaxKind.MinusMinusToken
;
export interface PostfixUnaryExpression extends IncrementExpression {
export interface PostfixUnaryExpression extends UpdateExpression {
kind: SyntaxKind.PostfixUnaryExpression;
operand: LeftHandSideExpression;
operator: PostfixUnaryOperator;
}
export interface LeftHandSideExpression extends IncrementExpression {
export interface LeftHandSideExpression extends UpdateExpression {
_leftHandSideExpressionBrand: any;
}
@@ -1062,6 +1076,10 @@ namespace ts {
kind: SyntaxKind.SuperKeyword;
}
export interface ImportExpression extends PrimaryExpression {
kind: SyntaxKind.ImportKeyword;
}
export interface DeleteExpression extends UnaryExpression {
kind: SyntaxKind.DeleteExpression;
expression: UnaryExpression;
@@ -1454,10 +1472,7 @@ namespace ts {
}
// see: https://tc39.github.io/ecma262/#prod-SuperProperty
export type SuperProperty
= SuperPropertyAccessExpression
| SuperElementAccessExpression
;
export type SuperProperty = SuperPropertyAccessExpression | SuperElementAccessExpression;
export interface CallExpression extends LeftHandSideExpression, Declaration {
kind: SyntaxKind.CallExpression;
@@ -1471,6 +1486,10 @@ namespace ts {
expression: SuperExpression;
}
export interface ImportCall extends CallExpression {
expression: ImportExpression;
}
export interface ExpressionWithTypeArguments extends TypeNode {
kind: SyntaxKind.ExpressionWithTypeArguments;
parent?: HeritageClause;
@@ -1689,6 +1708,8 @@ namespace ts {
incrementor?: Expression;
}
export type ForInOrOfStatement = ForInStatement | ForOfStatement;
export interface ForInStatement extends IterationStatement {
kind: SyntaxKind.ForInStatement;
initializer: ForInitializer;
@@ -1778,7 +1799,7 @@ namespace ts {
block: Block;
}
export type DeclarationWithTypeParameters = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration;
export type DeclarationWithTypeParameters = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag;
export interface ClassLikeDeclaration extends NamedDeclaration {
name?: Identifier;
@@ -2117,6 +2138,10 @@ namespace ts {
typeExpression: JSDocTypeExpression;
}
export interface JSDocClassTag extends JSDocTag {
kind: SyntaxKind.JSDocClassTag;
}
export interface JSDocTemplateTag extends JSDocTag {
kind: SyntaxKind.JSDocTemplateTag;
typeParameters: NodeArray<TypeParameterDeclaration>;
@@ -2535,7 +2560,6 @@ namespace ts {
getNonNullableType(type: Type): Type;
/** Note that the resulting nodes cannot be checked. */
typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeNode;
/** Note that the resulting nodes cannot be checked. */
signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration;
@@ -2605,6 +2629,9 @@ namespace ts {
* Does not include properties of primitive types.
*/
/* @internal */ getAllPossiblePropertiesOfType(type: Type): Symbol[];
/* @internal */ getJsxNamespace(): string;
/* @internal */ resolveNameAtLocation(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined;
}
export enum NodeBuilderFlags {
@@ -3497,6 +3524,7 @@ namespace ts {
noImplicitAny?: boolean; // Always combine with strict property
noImplicitReturns?: boolean;
noImplicitThis?: boolean; // Always combine with strict property
noStrictGenericChecks?: boolean;
noUnusedLocals?: boolean;
noUnusedParameters?: boolean;
noImplicitUseStrict?: boolean;
@@ -3564,6 +3592,7 @@ namespace ts {
UMD = 3,
System = 4,
ES2015 = 5,
ESNext = 6
}
export const enum JsxEmit {
@@ -3855,13 +3884,12 @@ namespace ts {
extension: Extension;
}
export enum Extension {
Ts,
Tsx,
Dts,
Js,
Jsx,
LastTypeScriptExtension = Dts
export const enum Extension {
Ts = ".ts",
Tsx = ".tsx",
Dts = ".d.ts",
Js = ".js",
Jsx = ".jsx"
}
export interface ResolvedModuleWithFailedLookupLocations {
@@ -3948,6 +3976,11 @@ namespace ts {
ContainsYield = 1 << 24,
ContainsHoistedDeclarationOrCompletion = 1 << 25,
ContainsDynamicImport = 1 << 26,
// Please leave this as 1 << 29.
// It is the maximum bit we can set before we outgrow the size of a v8 small integer (SMI) on an x86 system.
// It is a good reminder of how much room we have left
HasComputedFlags = 1 << 29, // Transform flags have been computed.
// Assertions
@@ -3985,18 +4018,29 @@ namespace ts {
ES2015FunctionSyntaxMask = ContainsCapturedLexicalThis | ContainsDefaultValueAssignments,
}
export interface SourceMapRange extends TextRange {
source?: SourceMapSource;
}
export interface SourceMapSource {
fileName: string;
text: string;
/* @internal */ lineMap: number[];
skipTrivia?: (pos: number) => number;
}
/* @internal */
export interface EmitNode {
annotatedNodes?: Node[]; // Tracks Parse-tree nodes with EmitNodes for eventual cleanup.
flags?: EmitFlags; // Flags that customize emit
leadingComments?: SynthesizedComment[]; // Synthesized leading comments
annotatedNodes?: Node[]; // Tracks Parse-tree nodes with EmitNodes for eventual cleanup.
flags?: EmitFlags; // Flags that customize emit
leadingComments?: SynthesizedComment[]; // Synthesized leading comments
trailingComments?: SynthesizedComment[]; // Synthesized trailing comments
commentRange?: TextRange; // The text range to use when emitting leading or trailing comments
sourceMapRange?: TextRange; // The text range to use when emitting leading or trailing source mappings
tokenSourceMapRanges?: TextRange[]; // The text range to use when emitting source mappings for tokens
constantValue?: string | number; // The constant value of an expression
externalHelpersModuleName?: Identifier; // The local name for an imported helpers module
helpers?: EmitHelper[]; // Emit helpers for the node
commentRange?: TextRange; // The text range to use when emitting leading or trailing comments
sourceMapRange?: SourceMapRange; // The text range to use when emitting leading or trailing source mappings
tokenSourceMapRanges?: SourceMapRange[]; // The text range to use when emitting source mappings for tokens
constantValue?: string | number; // The constant value of an expression
externalHelpersModuleName?: Identifier; // The local name for an imported helpers module
helpers?: EmitHelper[]; // Emit helpers for the node
}
export const enum EmitFlags {
@@ -4058,6 +4102,7 @@ namespace ts {
AsyncGenerator = 1 << 12, // __asyncGenerator (used by ES2017 async generator transformation)
AsyncDelegator = 1 << 13, // __asyncDelegator (used by ES2017 async generator yield* transformation)
AsyncValues = 1 << 14, // __asyncValues (used by ES2017 for..await..of transformation)
ExportStar = 1 << 15, // __exportStar (used by CommonJS/AMD/UMD module transformation)
// Helpers included by ES2015 for..of
ForOfIncludes = Values,
@@ -4075,7 +4120,7 @@ namespace ts {
SpreadIncludes = Read | Spread,
FirstEmitHelper = Extends,
LastEmitHelper = AsyncValues
LastEmitHelper = ExportStar
}
export const enum EmitHint {
+114 -31
View File
@@ -596,6 +596,10 @@ namespace ts {
return n.kind === SyntaxKind.CallExpression && (<CallExpression>n).expression.kind === SyntaxKind.SuperKeyword;
}
export function isImportCall(n: Node): n is ImportCall {
return n.kind === SyntaxKind.CallExpression && (<CallExpression>n).expression.kind === SyntaxKind.ImportKeyword;
}
export function isPrologueDirective(node: Node): node is PrologueDirective {
return node.kind === SyntaxKind.ExpressionStatement
&& (<ExpressionStatement>node).expression.kind === SyntaxKind.StringLiteral;
@@ -1434,31 +1438,17 @@ namespace ts {
}
function getJSDocTags(node: Node, kind: SyntaxKind): JSDocTag[] {
const docs = getJSDocs(node);
if (docs) {
const result: JSDocTag[] = [];
for (const doc of docs) {
if (doc.kind === SyntaxKind.JSDocParameterTag) {
if (doc.kind === kind) {
result.push(doc as JSDocTag);
}
}
else {
const tags = (doc as JSDoc).tags;
if (tags) {
result.push(...filter(tags, tag => tag.kind === kind));
}
}
}
return result;
}
return flatMap(getJSDocs(node), doc =>
doc.kind === SyntaxKind.JSDocComment
? filter((doc as JSDoc).tags, tag => tag.kind === kind)
: doc.kind === kind && doc);
}
function getFirstJSDocTag(node: Node, kind: SyntaxKind): JSDocTag {
return node && firstOrUndefined(getJSDocTags(node, kind));
}
export function getJSDocs(node: Node): (JSDoc | JSDocTag)[] {
export function getJSDocs(node: Node): (JSDoc | JSDocTag)[] {
if (isJSDocTypedefTag(node)) {
return [node.parent];
}
@@ -1556,6 +1546,12 @@ namespace ts {
p.name.kind === SyntaxKind.Identifier && p.name.text === name);
}
export function getTypeParameterFromJsDoc(node: TypeParameterDeclaration & { parent: JSDocTemplateTag }): TypeParameterDeclaration | undefined {
const name = node.name.text;
const { typeParameters } = (node.parent.parent.parent as ts.SignatureDeclaration | ts.InterfaceDeclaration | ts.ClassDeclaration);
return find(typeParameters, p => p.name.text === name);
}
export function getJSDocType(node: Node): JSDocType {
let tag: JSDocTypeTag | JSDocParameterTag = getFirstJSDocTag(node, SyntaxKind.JSDocTypeTag) as JSDocTypeTag;
if (!tag && node.kind === SyntaxKind.Parameter) {
@@ -1572,10 +1568,19 @@ namespace ts {
return getFirstJSDocTag(node, SyntaxKind.JSDocAugmentsTag) as JSDocAugmentsTag;
}
export function getJSDocClassTag(node: Node): JSDocClassTag {
return getFirstJSDocTag(node, SyntaxKind.JSDocClassTag) as JSDocClassTag;
}
export function getJSDocReturnTag(node: Node): JSDocReturnTag {
return getFirstJSDocTag(node, SyntaxKind.JSDocReturnTag) as JSDocReturnTag;
}
export function getJSDocReturnType(node: Node): JSDocType {
const returnTag = getJSDocReturnTag(node);
return returnTag && returnTag.typeExpression && returnTag.typeExpression.type;
}
export function getJSDocTemplateTag(node: Node): JSDocTemplateTag {
return getFirstJSDocTag(node, SyntaxKind.JSDocTemplateTag) as JSDocTemplateTag;
}
@@ -1622,7 +1627,7 @@ namespace ts {
return unaryOperator === SyntaxKind.PlusPlusToken || unaryOperator === SyntaxKind.MinusMinusToken ? AssignmentKind.Compound : AssignmentKind.None;
case SyntaxKind.ForInStatement:
case SyntaxKind.ForOfStatement:
return (<ForInStatement | ForOfStatement>parent).initializer === node ? AssignmentKind.Definite : AssignmentKind.None;
return (<ForInOrOfStatement>parent).initializer === node ? AssignmentKind.Definite : AssignmentKind.None;
case SyntaxKind.ParenthesizedExpression:
case SyntaxKind.ArrayLiteralExpression:
case SyntaxKind.SpreadElement:
@@ -2496,7 +2501,7 @@ namespace ts {
const path = outputDir
? getSourceFilePathInNewDir(sourceFile, host, outputDir)
: sourceFile.fileName;
return removeFileExtension(path) + ".d.ts";
return removeFileExtension(path) + Extension.Dts;
}
export interface EmitFileNames {
@@ -2555,7 +2560,7 @@ namespace ts {
if (sourceFiles.length) {
const jsFilePath = options.outFile || options.out;
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
const declarationFilePath = options.declaration ? removeFileExtension(jsFilePath) + ".d.ts" : "";
const declarationFilePath = options.declaration ? removeFileExtension(jsFilePath) + Extension.Dts : "";
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, createBundle(sourceFiles), emitOnlyDtsFiles);
}
}
@@ -2576,19 +2581,19 @@ namespace ts {
// 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): string {
function getOutputExtension(sourceFile: SourceFile, options: CompilerOptions): Extension {
if (options.jsx === JsxEmit.Preserve) {
if (isSourceFileJavaScript(sourceFile)) {
if (fileExtensionIs(sourceFile.fileName, ".jsx")) {
return ".jsx";
if (fileExtensionIs(sourceFile.fileName, Extension.Jsx)) {
return Extension.Jsx;
}
}
else if (sourceFile.languageVariant === LanguageVariant.JSX) {
// TypeScript source file preserving JSX syntax
return ".jsx";
return Extension.Jsx;
}
}
return ".js";
return Extension.Js;
}
export function getSourceFilePathInNewDir(sourceFile: SourceFile, host: EmitHost, newDirPath: string) {
@@ -2621,14 +2626,19 @@ namespace ts {
});
}
/** Get the type annotaion for the value parameter. */
export function getSetAccessorTypeAnnotationNode(accessor: SetAccessorDeclaration): TypeNode {
function getSetAccessorValueParameter(accessor: SetAccessorDeclaration): ParameterDeclaration | undefined {
if (accessor && accessor.parameters.length > 0) {
const hasThis = accessor.parameters.length === 2 && parameterIsThisKeyword(accessor.parameters[0]);
return accessor.parameters[hasThis ? 1 : 0].type;
return accessor.parameters[hasThis ? 1 : 0];
}
}
/** Get the type annotation for the value parameter. */
export function getSetAccessorTypeAnnotationNode(accessor: SetAccessorDeclaration): TypeNode {
const parameter = getSetAccessorValueParameter(accessor);
return parameter && parameter.type;
}
export function getThisParameter(signature: SignatureDeclaration): ParameterDeclaration | undefined {
if (signature.parameters.length) {
const thisParameter = signature.parameters[0];
@@ -2707,6 +2717,55 @@ namespace ts {
};
}
/**
* Gets the effective type annotation of a variable, parameter, or property. If the node was
* parsed in a JavaScript file, gets the type annotation from JSDoc.
*/
export function getEffectiveTypeAnnotationNode(node: VariableLikeDeclaration): TypeNode {
if (node.type) {
return node.type;
}
if (node.flags & NodeFlags.JavaScriptFile) {
return getJSDocType(node);
}
}
/**
* Gets the effective return type annotation of a signature. If the node was parsed in a
* JavaScript file, gets the return type annotation from JSDoc.
*/
export function getEffectiveReturnTypeNode(node: SignatureDeclaration): TypeNode {
if (node.type) {
return node.type;
}
if (node.flags & NodeFlags.JavaScriptFile) {
return getJSDocReturnType(node);
}
}
/**
* Gets the effective type parameters. If the node was parsed in a
* JavaScript file, gets the type parameters from the `@template` tag from JSDoc.
*/
export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): TypeParameterDeclaration[] {
if (node.typeParameters) {
return node.typeParameters;
}
if (node.flags & NodeFlags.JavaScriptFile) {
const templateTag = getJSDocTemplateTag(node);
return templateTag && templateTag.typeParameters;
}
}
/**
* Gets the effective type annotation of the value parameter of a set accessor. If the node
* was parsed in a JavaScript file, gets the type annotation from JSDoc.
*/
export function getEffectiveSetAccessorTypeAnnotationNode(node: SetAccessorDeclaration): TypeNode {
const parameter = getSetAccessorValueParameter(node);
return parameter && getEffectiveTypeAnnotationNode(parameter);
}
export function emitNewLineBeforeLeadingComments(lineMap: number[], writer: EmitTextWriter, node: TextRange, leadingComments: CommentRange[]) {
emitNewLineBeforeLeadingCommentsOfPosition(lineMap, writer, node.pos, leadingComments);
}
@@ -4053,7 +4112,7 @@ namespace ts {
// Signature elements
export function isTypeParameter(node: Node): node is TypeParameterDeclaration {
export function isTypeParameterDeclaration(node: Node): node is TypeParameterDeclaration {
return node.kind === SyntaxKind.TypeParameter;
}
@@ -4676,6 +4735,16 @@ namespace ts {
// All node tests in the following list should *not* reference parent pointers so that
// they may be used with transformations.
namespace ts {
/* @internal */
export function isNode(node: Node) {
return isNodeKind(node.kind);
}
/* @internal */
export function isNodeKind(kind: SyntaxKind) {
return kind >= SyntaxKind.FirstNode;
}
/**
* True if node is of some token syntax kind.
* For example, this is true for an IfKeyword but not for an IfStatement.
@@ -5097,6 +5166,11 @@ namespace ts {
return false;
}
/* @internal */
export function isForInOrOfStatement(node: Node): node is ForInOrOfStatement {
return node.kind === SyntaxKind.ForInStatement || node.kind === SyntaxKind.ForOfStatement;
}
// Element
/* @internal */
@@ -5225,6 +5299,10 @@ namespace ts {
/* @internal */
export function isDeclaration(node: Node): node is NamedDeclaration {
if (node.kind === SyntaxKind.TypeParameter) {
return node.parent.kind !== SyntaxKind.JSDocTemplateTag || isInJavaScriptFile(node);
}
return isDeclarationKind(node.kind);
}
@@ -5314,6 +5392,11 @@ namespace ts {
return node.kind >= SyntaxKind.FirstJSDocNode && node.kind <= SyntaxKind.LastJSDocNode;
}
/** True if node is of a kind that may contain comment text. */
export function isJSDocCommentContainingNode(node: Node): boolean {
return node.kind === SyntaxKind.JSDocComment || isJSDocTag(node);
}
// TODO: determine what this does before making it public.
/* @internal */
export function isJSDocTag(node: Node): boolean {
+64 -46
View File
@@ -275,7 +275,7 @@ namespace ts {
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 +288,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 +319,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 +350,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 +400,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 +476,7 @@ namespace ts {
nodesVisitor((<FunctionExpression>node).modifiers, visitor, isModifier),
visitNode((<FunctionExpression>node).asteriskToken, tokenVisitor, isToken),
visitNode((<FunctionExpression>node).name, visitor, isIdentifier),
nodesVisitor((<FunctionExpression>node).typeParameters, visitor, isTypeParameter),
nodesVisitor((<FunctionExpression>node).typeParameters, visitor, isTypeParameterDeclaration),
visitParameterList((<FunctionExpression>node).parameters, visitor, context, nodesVisitor),
visitNode((<FunctionExpression>node).type, visitor, isTypeNode),
visitFunctionBody((<FunctionExpression>node).body, visitor, context));
@@ -484,7 +484,7 @@ namespace ts {
case SyntaxKind.ArrowFunction:
return updateArrowFunction(<ArrowFunction>node,
nodesVisitor((<ArrowFunction>node).modifiers, visitor, isModifier),
nodesVisitor((<ArrowFunction>node).typeParameters, visitor, isTypeParameter),
nodesVisitor((<ArrowFunction>node).typeParameters, visitor, isTypeParameterDeclaration),
visitParameterList((<ArrowFunction>node).parameters, visitor, context, nodesVisitor),
visitNode((<ArrowFunction>node).type, visitor, isTypeNode),
visitFunctionBody((<ArrowFunction>node).body, visitor, context));
@@ -543,7 +543,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 +676,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 +686,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 +695,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 +704,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:
@@ -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:
@@ -1517,35 +1517,7 @@ namespace ts {
}
export namespace Debug {
if (isDebugging) {
// Add additional properties in debug mode to assist with debugging.
Object.defineProperties(objectAllocator.getSymbolConstructor().prototype, {
"__debugFlags": { get(this: Symbol) { return formatSymbolFlags(this.flags); } }
});
Object.defineProperties(objectAllocator.getTypeConstructor().prototype, {
"__debugFlags": { get(this: Type) { return formatTypeFlags(this.flags); } },
"__debugObjectFlags": { get(this: Type) { return this.flags & TypeFlags.Object ? formatObjectFlags((<ObjectType>this).objectFlags) : ""; } },
"__debugTypeToString": { value(this: Type) { return this.checker.typeToString(this); } },
});
for (const ctor of [objectAllocator.getNodeConstructor(), objectAllocator.getIdentifierConstructor(), objectAllocator.getTokenConstructor(), objectAllocator.getSourceFileConstructor()]) {
if (!ctor.prototype.hasOwnProperty("__debugKind")) {
Object.defineProperties(ctor.prototype, {
"__debugKind": { get(this: Node) { return formatSyntaxKind(this.kind); } },
"__debugModifierFlags": { get(this: Node) { return formatModifierFlags(getModifierFlagsNoCache(this)); } },
"__debugTransformFlags": { get(this: Node) { return formatTransformFlags(this.transformFlags); } },
"__debugEmitFlags": { get(this: Node) { return formatEmitFlags(getEmitFlags(this)); } },
"__debugGetText": { value(this: Node, includeTrivia?: boolean) {
if (nodeIsSynthesized(this)) return "";
const parseNode = getParseTreeNode(this);
const sourceFile = parseNode && getSourceFileOfNode(parseNode);
return sourceFile ? getSourceTextOfNodeFromSourceFile(sourceFile, parseNode, includeTrivia) : "";
} }
});
}
}
}
let isDebugInfoEnabled = false;
export const failBadSyntaxKind = shouldAssert(AssertionLevel.Normal)
? (node: Node, message?: string): void => fail(
@@ -1592,5 +1564,51 @@ namespace ts {
() => `Node ${formatSyntaxKind(node.kind)} was unexpected'.`,
assertMissingNode)
: noop;
/**
* Injects debug information into frequently used types.
*/
export function enableDebugInfo() {
if (isDebugInfoEnabled) return;
// Add additional properties in debug mode to assist with debugging.
Object.defineProperties(objectAllocator.getSymbolConstructor().prototype, {
"__debugFlags": { get(this: Symbol) { return formatSymbolFlags(this.flags); } }
});
Object.defineProperties(objectAllocator.getTypeConstructor().prototype, {
"__debugFlags": { get(this: Type) { return formatTypeFlags(this.flags); } },
"__debugObjectFlags": { get(this: Type) { return this.flags & TypeFlags.Object ? formatObjectFlags((<ObjectType>this).objectFlags) : ""; } },
"__debugTypeToString": { value(this: Type) { return this.checker.typeToString(this); } },
});
const nodeConstructors = [
objectAllocator.getNodeConstructor(),
objectAllocator.getIdentifierConstructor(),
objectAllocator.getTokenConstructor(),
objectAllocator.getSourceFileConstructor()
];
for (const ctor of nodeConstructors) {
if (!ctor.prototype.hasOwnProperty("__debugKind")) {
Object.defineProperties(ctor.prototype, {
"__debugKind": { get(this: Node) { return formatSyntaxKind(this.kind); } },
"__debugModifierFlags": { get(this: Node) { return formatModifierFlags(getModifierFlagsNoCache(this)); } },
"__debugTransformFlags": { get(this: Node) { return formatTransformFlags(this.transformFlags); } },
"__debugEmitFlags": { get(this: Node) { return formatEmitFlags(getEmitFlags(this)); } },
"__debugGetText": {
value(this: Node, includeTrivia?: boolean) {
if (nodeIsSynthesized(this)) return "";
const parseNode = getParseTreeNode(this);
const sourceFile = parseNode && getSourceFileOfNode(parseNode);
return sourceFile ? getSourceTextOfNodeFromSourceFile(sourceFile, parseNode, includeTrivia) : "";
}
}
});
}
}
isDebugInfoEnabled = true;
}
}
}
+1 -1
View File
@@ -90,7 +90,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.
+109 -73
View File
@@ -479,24 +479,11 @@ namespace FourSlash {
}
private getDiagnostics(fileName: string): ts.Diagnostic[] {
const syntacticErrors = this.languageService.getSyntacticDiagnostics(fileName);
const semanticErrors = this.languageService.getSemanticDiagnostics(fileName);
const diagnostics: ts.Diagnostic[] = [];
diagnostics.push.apply(diagnostics, syntacticErrors);
diagnostics.push.apply(diagnostics, semanticErrors);
return diagnostics;
return this.languageService.getSyntacticDiagnostics(fileName).concat(this.languageService.getSemanticDiagnostics(fileName));
}
private getAllDiagnostics(): ts.Diagnostic[] {
const diagnostics: ts.Diagnostic[] = [];
for (const fileName of this.languageServiceAdapterHost.getFilenames()) {
diagnostics.push.apply(this.getDiagnostics(fileName));
}
return diagnostics;
return ts.flatMap(this.languageServiceAdapterHost.getFilenames(), fileName => this.getDiagnostics(fileName));
}
public verifyErrorExistsAfterMarker(markerName: string, negative: boolean, after: boolean) {
@@ -549,11 +536,16 @@ namespace FourSlash {
Harness.IO.log("Unexpected error(s) found. Error list is:");
}
for (const { start, length, messageText } of errors) {
Harness.IO.log(" minChar: " + start +
", limChar: " + (start + length) +
for (const { start, length, messageText, file } of errors) {
Harness.IO.log(" from: " + showPosition(file, start) +
", to: " + showPosition(file, start + length) +
", message: " + ts.flattenDiagnosticMessageText(messageText, Harness.IO.newLine()) + "\n");
}
function showPosition(file: ts.SourceFile, pos: number) {
const { line, character } = ts.getLineAndCharacterOfPosition(file, pos);
return `${line}:${character}`;
}
}
public verifyNoErrors() {
@@ -1052,21 +1044,27 @@ namespace FourSlash {
fail(`Expected ${expected}, got ${actual}`);
}
for (const key in actual) if (ts.hasProperty(actual as any, key)) {
const ak = actual[key], ek = expected[key];
if (typeof ak === "object" && typeof ek === "object") {
recur(ak, ek, path ? path + "." + key : key);
}
else if (ak !== ek) {
fail(`Expected '${key}' to be '${ek}', got '${ak}'`);
for (const key in actual) {
if (ts.hasProperty(actual as any, key)) {
const ak = actual[key], ek = expected[key];
if (typeof ak === "object" && typeof ek === "object") {
recur(ak, ek, path ? path + "." + key : key);
}
else if (ak !== ek) {
fail(`Expected '${key}' to be '${ek}', got '${ak}'`);
}
}
}
for (const key in expected) if (ts.hasProperty(expected as any, key)) {
if (!ts.hasProperty(actual as any, key)) {
fail(`${msgPrefix}Missing property '${key}'`);
for (const key in expected) {
if (ts.hasProperty(expected as any, key)) {
if (!ts.hasProperty(actual as any, key)) {
fail(`${msgPrefix}Missing property '${key}'`);
}
}
}
};
if (fullActual === undefined || fullExpected === undefined) {
if (fullActual === fullExpected) {
return;
@@ -1148,15 +1146,17 @@ namespace FourSlash {
}
public verifyQuickInfos(namesAndTexts: { [name: string]: string | [string, string] }) {
for (const name in namesAndTexts) if (ts.hasProperty(namesAndTexts, name)) {
const text = namesAndTexts[name];
if (ts.isArray(text)) {
assert(text.length === 2);
const [expectedText, expectedDocumentation] = text;
this.verifyQuickInfoAt(name, expectedText, expectedDocumentation);
}
else {
this.verifyQuickInfoAt(name, text);
for (const name in namesAndTexts) {
if (ts.hasProperty(namesAndTexts, name)) {
const text = namesAndTexts[name];
if (ts.isArray(text)) {
assert(text.length === 2);
const [expectedText, expectedDocumentation] = text;
this.verifyQuickInfoAt(name, expectedText, expectedDocumentation);
}
else {
this.verifyQuickInfoAt(name, text);
}
}
}
}
@@ -1165,7 +1165,6 @@ namespace FourSlash {
if (expectedDocumentation === "") {
throw new Error("Use 'undefined' instead");
}
const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition);
const actualQuickInfoText = actualQuickInfo ? ts.displayPartsToString(actualQuickInfo.displayParts) : "";
const actualQuickInfoDocumentation = actualQuickInfo ? ts.displayPartsToString(actualQuickInfo.documentation) : "";
@@ -1468,7 +1467,7 @@ namespace FourSlash {
let baselineFile = this.testData.globalOptions[metadataOptionNames.baselineFile];
if (!baselineFile) {
baselineFile = this.activeFile.fileName.replace(this.basePath + "/breakpointValidation", "bpSpan");
baselineFile = baselineFile.replace(".ts", ".baseline");
baselineFile = baselineFile.replace(ts.Extension.Ts, ".baseline");
}
Harness.Baseline.runBaseline(
@@ -1538,7 +1537,7 @@ namespace FourSlash {
public baselineQuickInfo() {
let baselineFile = this.testData.globalOptions[metadataOptionNames.baselineFile];
if (!baselineFile) {
baselineFile = ts.getBaseFileName(this.activeFile.fileName).replace(".ts", ".baseline");
baselineFile = ts.getBaseFileName(this.activeFile.fileName).replace(ts.Extension.Ts, ".baseline");
}
Harness.Baseline.runBaseline(
@@ -1611,16 +1610,19 @@ namespace FourSlash {
}
private printMembersOrCompletions(info: ts.CompletionInfo) {
if (info === undefined) { return "No completion info."; }
const { entries } = info;
function pad(s: string, length: number) {
return s + new Array(length - s.length + 1).join(" ");
}
function max<T>(arr: T[], selector: (x: T) => number): number {
return arr.reduce((prev, x) => Math.max(prev, selector(x)), 0);
}
const longestNameLength = max(info.entries, m => m.name.length);
const longestKindLength = max(info.entries, m => m.kind.length);
info.entries.sort((m, n) => m.sortText > n.sortText ? 1 : m.sortText < n.sortText ? -1 : m.name > n.name ? 1 : m.name < n.name ? -1 : 0);
const membersString = info.entries.map(m => `${pad(m.name, longestNameLength)} ${pad(m.kind, longestKindLength)} ${m.kindModifiers}`).join("\n");
const longestNameLength = max(entries, m => m.name.length);
const longestKindLength = max(entries, m => m.kind.length);
entries.sort((m, n) => m.sortText > n.sortText ? 1 : m.sortText < n.sortText ? -1 : m.name > n.name ? 1 : m.name < n.name ? -1 : 0);
const membersString = entries.map(m => `${pad(m.name, longestNameLength)} ${pad(m.kind, longestKindLength)} ${m.kindModifiers}`).join("\n");
Harness.IO.log(membersString);
}
@@ -2172,7 +2174,7 @@ namespace FourSlash {
Harness.IO.log(this.spanInfoToString(this.getNameOrDottedNameSpan(pos), "**"));
}
private verifyClassifications(expected: { classificationType: string; text: string; textSpan?: TextSpan }[], actual: ts.ClassifiedSpan[]) {
private verifyClassifications(expected: { classificationType: string; text: string; textSpan?: TextSpan }[], actual: ts.ClassifiedSpan[], sourceFileText: string) {
if (actual.length !== expected.length) {
this.raiseError("verifyClassifications failed - expected total classifications to be " + expected.length +
", but was " + actual.length +
@@ -2212,9 +2214,11 @@ namespace FourSlash {
});
function jsonMismatchString() {
const showActual = actual.map(({ classificationType, textSpan }) =>
({ classificationType, text: sourceFileText.slice(textSpan.start, textSpan.start + textSpan.length) }));
return Harness.IO.newLine() +
"expected: '" + Harness.IO.newLine() + stringify(expected) + "'" + Harness.IO.newLine() +
"actual: '" + Harness.IO.newLine() + stringify(actual) + "'";
"actual: '" + Harness.IO.newLine() + stringify(showActual) + "'";
}
}
@@ -2237,14 +2241,14 @@ namespace FourSlash {
const actual = this.languageService.getSemanticClassifications(this.activeFile.fileName,
ts.createTextSpan(0, this.activeFile.content.length));
this.verifyClassifications(expected, actual);
this.verifyClassifications(expected, actual, this.activeFile.content);
}
public verifySyntacticClassifications(expected: { classificationType: string; text: string }[]) {
const actual = this.languageService.getSyntacticClassifications(this.activeFile.fileName,
ts.createTextSpan(0, this.activeFile.content.length));
this.verifyClassifications(expected, actual);
this.verifyClassifications(expected, actual, this.activeFile.content);
}
public verifyOutliningSpans(spans: TextSpan[]) {
@@ -2279,23 +2283,22 @@ namespace FourSlash {
}
/**
* Compares expected text to the text that would be in the sole range
* (ie: [|...|]) in the file after applying the codefix sole codefix
* in the source file.
*
* Because codefixes are only applied on the working file, it is unsafe
* to apply this more than once (consider a refactoring across files).
* Finds and applies a code action corresponding to the supplied parameters.
* If index is undefined, applies the unique code action available.
* @param errorCode The error code that generated the code action.
* @param index The nth (0-index-based) codeaction available generated by errorCode.
*/
public verifyRangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number) {
public getAndApplyCodeActions(errorCode?: number, index?: number) {
const fileName = this.activeFile.fileName;
this.applyCodeActions(this.getCodeFixActions(fileName, errorCode), index);
}
public verifyRangeIs(expectedText: string, includeWhiteSpace?: boolean) {
const ranges = this.getRanges();
if (ranges.length !== 1) {
this.raiseError("Exactly one range should be specified in the testfile.");
}
const fileName = this.activeFile.fileName;
this.applyCodeAction(fileName, this.getCodeFixActions(fileName, errorCode), index);
const actualText = this.rangeText(ranges[0]);
const result = includeWhiteSpace
@@ -2307,6 +2310,16 @@ namespace FourSlash {
}
}
/**
* Compares expected text to the text that would be in the sole range
* (ie: [|...|]) in the file after applying the codefix sole codefix
* in the source file.
*/
public verifyRangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number) {
this.getAndApplyCodeActions(errorCode, index);
this.verifyRangeIs(expectedText, includeWhiteSpace);
}
/**
* Applies fixes for the errors in fileName and compares the results to
* expectedContents after all fixes have been applied.
@@ -2319,7 +2332,7 @@ namespace FourSlash {
public verifyFileAfterCodeFix(expectedContents: string, fileName?: string) {
fileName = fileName ? fileName : this.activeFile.fileName;
this.applyCodeAction(fileName, this.getCodeFixActions(fileName));
this.applyCodeActions(this.getCodeFixActions(fileName));
const actualContents: string = this.getFileContent(fileName);
if (this.removeWhitespace(actualContents) !== this.removeWhitespace(expectedContents)) {
@@ -2357,11 +2370,10 @@ namespace FourSlash {
return actions;
}
private applyCodeAction(fileName: string, actions: ts.CodeAction[], index?: number): void {
private applyCodeActions(actions: ts.CodeAction[], index?: number): void {
if (index === undefined) {
if (!(actions && actions.length === 1)) {
const actionText = (actions && actions.length) ? JSON.stringify(actions) : "none";
this.raiseError(`Should find exactly one codefix, but found ${actionText}`);
this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found.`);
}
index = 0;
}
@@ -2371,12 +2383,11 @@ namespace FourSlash {
}
}
const fileChanges = ts.find(actions[index].changes, change => change.fileName === fileName);
if (!fileChanges) {
this.raiseError("The CodeFix found doesn't provide any changes in this file.");
}
const changes = actions[index].changes;
this.applyEdits(fileChanges.fileName, fileChanges.textChanges, /*isFormattingEdit*/ false);
for (const change of changes) {
this.applyEdits(change.fileName, change.textChanges, /*isFormattingEdit*/ false);
}
}
public verifyImportFixAtPosition(expectedTextArray: string[], errorCode?: number) {
@@ -2388,7 +2399,10 @@ namespace FourSlash {
const codeFixes = this.getCodeFixActions(this.activeFile.fileName, errorCode);
if (!codeFixes || codeFixes.length === 0) {
this.raiseError("No codefixes returned.");
if (expectedTextArray.length !== 0) {
this.raiseError("No codefixes returned.");
}
return;
}
const actualTextArray: string[] = [];
@@ -2665,6 +2679,13 @@ namespace FourSlash {
this.rangesByText().forEach(ranges => this.verifyRangesAreDocumentHighlights(ranges));
}
public verifyDocumentHighlightsOf(startRange: Range, ranges: Range[]) {
ts.Debug.assert(ts.contains(ranges, startRange));
const fileNames = unique(ranges, range => range.fileName);
this.goToRangeStart(startRange);
this.verifyDocumentHighlights(ranges, fileNames);
}
public verifyRangesAreDocumentHighlights(ranges?: Range[]) {
ranges = ranges || this.getRanges();
const fileNames = unique(ranges, range => range.fileName);
@@ -2747,6 +2768,7 @@ namespace FourSlash {
markerName: string,
expectedContent: string,
refactorNameToApply: string,
actionName: string,
formattingOptions?: ts.FormatCodeSettings) {
formattingOptions = formattingOptions || this.formatCodeSettings;
@@ -2759,9 +2781,11 @@ namespace FourSlash {
this.raiseError(`The expected refactor: ${refactorNameToApply} is not available at the marker location.`);
}
const codeActions = this.languageService.getRefactorCodeActions(this.activeFile.fileName, formattingOptions, markerPos, refactorNameToApply);
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, formattingOptions, markerPos, refactorNameToApply, actionName);
this.applyCodeAction(this.activeFile.fileName, codeActions);
for (const edit of editInfo.edits) {
this.applyEdits(edit.fileName, edit.textChanges);
}
const actualContent = this.getFileContent(this.activeFile.fileName);
if (this.normalizeNewlines(actualContent) !== this.normalizeNewlines(expectedContent)) {
@@ -3804,8 +3828,16 @@ namespace FourSlashInterface {
this.state.verifyRangeAfterCodeFix(expectedText, includeWhiteSpace, errorCode, index);
}
public fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, formattingOptions?: ts.FormatCodeSettings): void {
this.state.verifyFileAfterApplyingRefactorAtMarker(markerName, expectedContent, refactorNameToApply, formattingOptions);
public fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, actionName: string, formattingOptions?: ts.FormatCodeSettings): void {
this.state.verifyFileAfterApplyingRefactorAtMarker(markerName, expectedContent, refactorNameToApply, actionName, formattingOptions);
}
public rangeIs(expectedText: string, includeWhiteSpace?: boolean): void {
this.state.verifyRangeIs(expectedText, includeWhiteSpace);
}
public getAndApplyCodeFix(errorCode?: number, index?: number): void {
this.state.getAndApplyCodeActions(errorCode, index);
}
public importFixAtPosition(expectedTextArray: string[], errorCode?: number): void {
@@ -3868,6 +3900,10 @@ namespace FourSlashInterface {
this.state.verifyRangesWithSameTextAreDocumentHighlights();
}
public documentHighlightsOf(startRange: FourSlash.Range, ranges: FourSlash.Range[]) {
this.state.verifyDocumentHighlightsOf(startRange, ranges);
}
public completionEntryDetailIs(entryName: string, text: string, documentation?: string, kind?: string, tags?: ts.JSDocTagInfo[]) {
this.state.verifyCompletionEntryDetails(entryName, text, documentation, kind, tags);
}
+13 -11
View File
@@ -259,8 +259,9 @@ namespace Utils {
return true;
}
else if ((f & v) > 0) {
if (result.length)
if (result.length) {
result += " | ";
}
result += flags[v];
return false;
}
@@ -857,6 +858,7 @@ namespace Harness {
export function getDefaultLibFileName(options: ts.CompilerOptions): string {
switch (options.target) {
case ts.ScriptTarget.ESNext:
case ts.ScriptTarget.ES2017:
return "lib.es2017.d.ts";
case ts.ScriptTarget.ES2016:
@@ -1051,7 +1053,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);
@@ -1247,7 +1249,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);
}
@@ -1463,7 +1465,7 @@ namespace Harness {
// When calling this function from rwc-runner, the baselinePath will have no extension.
// As rwc test- file is stored in json which ".json" will get stripped off.
// When calling this function from compiler-runner, the baselinePath will then has either ".ts" or ".tsx" extension
const outputFileName = ts.endsWith(baselinePath, ".ts") || ts.endsWith(baselinePath, ".tsx") ?
const outputFileName = ts.endsWith(baselinePath, ts.Extension.Ts) || ts.endsWith(baselinePath, ts.Extension.Tsx) ?
baselinePath.replace(/\.tsx?/, fullExtension) : baselinePath.concat(fullExtension);
Harness.Baseline.runBaseline(outputFileName, () => fullBaseLine, opts);
}
@@ -1561,7 +1563,7 @@ namespace Harness {
}
// 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) {
@@ -1649,22 +1651,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) {
@@ -1971,7 +1973,7 @@ namespace Harness {
export function isDefaultLibraryFile(filePath: string): boolean {
// We need to make sure that the filePath is prefixed with "lib." not just containing "lib." and end with ".d.ts"
const fileName = ts.getBaseFileName(ts.normalizeSlashes(filePath));
return ts.startsWith(fileName, "lib.") && ts.endsWith(fileName, ".d.ts");
return ts.startsWith(fileName, "lib.") && ts.endsWith(fileName, ts.Extension.Dts);
}
export function isBuiltFile(filePath: string): boolean {
+6 -2
View File
@@ -492,7 +492,7 @@ namespace Harness.LanguageService {
getCodeFixDiagnostics(): ts.Diagnostic[] {
throw new Error("Not supported on the shim.");
}
getRefactorCodeActions(): ts.CodeAction[] {
getEditsForRefactor(): ts.RefactorEditInfo {
throw new Error("Not supported on the shim.");
}
getApplicableRefactors(): ts.ApplicableRefactorInfo[] {
@@ -731,7 +731,7 @@ namespace Harness.LanguageService {
}
createHash(s: string) {
return s;
return mockHash(s);
}
require(_initialDir: string, _moduleName: string): ts.server.RequireResult {
@@ -856,4 +856,8 @@ namespace Harness.LanguageService {
getClassifier(): ts.Classifier { throw new Error("getClassifier is not available using the server interface."); }
getPreProcessedFileInfo(): ts.PreProcessedFileInfo { throw new Error("getPreProcessedFileInfo is not available using the server interface."); }
}
export function mockHash(s: string): string {
return `hash-${s}`;
}
}
+3 -6
View File
@@ -232,14 +232,11 @@ namespace Playback {
// different entry).
// TODO (yuisu): We can certainly remove these once we recapture the RWC using new API
const normalizedPath = ts.normalizePath(path).toLowerCase();
const result: string[] = [];
for (const directory of replayLog.directoriesRead) {
return ts.flatMap(replayLog.directoriesRead, directory => {
if (ts.normalizeSlashes(directory.path).toLowerCase() === normalizedPath) {
result.push(...directory.result);
return directory.result;
}
}
return result;
});
});
wrapper.writeFile = recordReplay(wrapper.writeFile, underlying)(
+4 -4
View File
@@ -325,8 +325,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++;
}
@@ -386,14 +386,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);
+4
View File
@@ -222,6 +222,10 @@ if (taskConfigsFolder) {
}
}
else {
if (ts.Debug.isDebugging) {
ts.Debug.enableDebugInfo();
}
runTests(runners);
}
if (!runUnitTests) {
@@ -47,7 +47,7 @@ namespace ts {
clearTimeout,
setImmediate: typeof setImmediate !== "undefined" ? setImmediate : action => setTimeout(action, 0),
clearImmediate: typeof clearImmediate !== "undefined" ? clearImmediate : clearTimeout,
createHash: s => s
createHash: Harness.LanguageService.mockHash,
};
}
+1 -1
View File
@@ -113,7 +113,7 @@ namespace ts {
start: undefined,
length: undefined,
}, {
messageText: "Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015'.",
messageText: "Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'esnext'.",
category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
+2 -2
View File
@@ -513,7 +513,7 @@ namespace ts.projectSystem {
const lines = ["var x = 1;", "var y = 2;"];
const path = "/a/app";
const f = {
path: path + ".ts",
path: path + ts.Extension.Ts,
content: lines.join(newLine)
};
const host = createServerHost([f], { newLine });
@@ -530,7 +530,7 @@ namespace ts.projectSystem {
command: "compileOnSaveEmitFile",
arguments: { file: f.path }
});
const emitOutput = host.readFile(path + ".js");
const emitOutput = host.readFile(path + ts.Extension.Js);
assert.equal(emitOutput, f.content + newLine, "content of emit output should be identical with the input + newline");
}
});
@@ -122,7 +122,7 @@ namespace ts {
file: undefined,
start: 0,
length: 0,
messageText: "Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015'.",
messageText: "Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'esnext'.",
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
}]
+1 -1
View File
@@ -5,7 +5,7 @@ namespace ts {
if (!expected === !actual) {
if (expected) {
assert.isTrue(expected.resolvedFileName === actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
assert.isTrue(expected.extension === actual.extension, `'ext': expected '${Extension[expected.extension]}' to be equal to '${Extension[actual.extension]}'`);
assert.isTrue(expected.extension === actual.extension, `'ext': expected '${expected.extension}' to be equal to '${actual.extension}'`);
assert.isTrue(expected.isExternalLibraryImport === actual.isExternalLibraryImport, `'isExternalLibraryImport': expected '${expected.isExternalLibraryImport}' to be equal to '${actual.isExternalLibraryImport}'`);
}
return true;
+124 -51
View File
@@ -81,63 +81,136 @@ namespace ts {
describe("printNode", () => {
const printsCorrectly = makePrintsCorrectly("printsNodeCorrectly");
let sourceFile: SourceFile;
before(() => sourceFile = createSourceFile("source.ts", "", ScriptTarget.ES2015));
// tslint:disable boolean-trivia
const syntheticNode = createClassDeclaration(
undefined,
undefined,
/*name*/ createIdentifier("C"),
undefined,
undefined,
createNodeArray([
createProperty(
undefined,
printsCorrectly("class", {}, printer => printer.printNode(
EmitHint.Unspecified,
createClassDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*name*/ createIdentifier("C"),
/*typeParameters*/ undefined,
/*heritageClauses*/ undefined,
[createProperty(
/*decorators*/ undefined,
createNodeArray([createToken(SyntaxKind.PublicKeyword)]),
createIdentifier("prop"),
undefined,
undefined,
undefined
)
])
);
/*questionToken*/ undefined,
/*type*/ undefined,
/*initializer*/ undefined
)]
),
createSourceFile("source.ts", "", ScriptTarget.ES2015)
));
printsCorrectly("namespaceExportDeclaration", {}, printer => printer.printNode(
EmitHint.Unspecified,
createNamespaceExportDeclaration("B"),
createSourceFile("source.ts", "", ScriptTarget.ES2015)
));
// https://github.com/Microsoft/TypeScript/issues/15971
const classWithOptionalMethodAndProperty = createClassDeclaration(
undefined,
/* modifiers */ createNodeArray([createToken(SyntaxKind.DeclareKeyword)]),
/* name */ createIdentifier("X"),
undefined,
undefined,
createNodeArray([
createMethod(
undefined,
undefined,
undefined,
/* name */ createIdentifier("method"),
/* questionToken */ createToken(SyntaxKind.QuestionToken),
undefined,
undefined,
/* type */ createKeywordTypeNode(SyntaxKind.VoidKeyword),
undefined
printsCorrectly("classWithOptionalMethodAndProperty", {}, printer => printer.printNode(
EmitHint.Unspecified,
createClassDeclaration(
/*decorators*/ undefined,
/*modifiers*/ [createToken(SyntaxKind.DeclareKeyword)],
/*name*/ createIdentifier("X"),
/*typeParameters*/ undefined,
/*heritageClauses*/ undefined,
[
createMethod(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ createIdentifier("method"),
/*questionToken*/ createToken(SyntaxKind.QuestionToken),
/*typeParameters*/ undefined,
[],
/*type*/ createKeywordTypeNode(SyntaxKind.VoidKeyword),
/*body*/ undefined
),
createProperty(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*name*/ createIdentifier("property"),
/*questionToken*/ createToken(SyntaxKind.QuestionToken),
/*type*/ createKeywordTypeNode(SyntaxKind.StringKeyword),
/*initializer*/ undefined
),
]
),
createSourceFile("source.ts", "", ScriptTarget.ES2015)
));
// https://github.com/Microsoft/TypeScript/issues/15651
printsCorrectly("functionTypes", {}, printer => printer.printNode(
EmitHint.Unspecified,
createTupleTypeNode([
createFunctionTypeNode(
/*typeArguments*/ undefined,
[createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
createIdentifier("args")
)],
createKeywordTypeNode(SyntaxKind.AnyKeyword)
),
createProperty(
undefined,
undefined,
/* name */ createIdentifier("property"),
/* questionToken */ createToken(SyntaxKind.QuestionToken),
/* type */ createKeywordTypeNode(SyntaxKind.StringKeyword),
undefined
createFunctionTypeNode(
[createTypeParameterDeclaration("T")],
[createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
createIdentifier("args")
)],
createKeywordTypeNode(SyntaxKind.AnyKeyword)
),
])
);
// tslint:enable boolean-trivia
printsCorrectly("class", {}, printer => printer.printNode(EmitHint.Unspecified, syntheticNode, sourceFile));
printsCorrectly("namespaceExportDeclaration", {}, printer => printer.printNode(EmitHint.Unspecified, createNamespaceExportDeclaration("B"), sourceFile));
printsCorrectly("classWithOptionalMethodAndProperty", {}, printer => printer.printNode(EmitHint.Unspecified, classWithOptionalMethodAndProperty, sourceFile));
createFunctionTypeNode(
/*typeArguments*/ undefined,
[createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createToken(SyntaxKind.DotDotDotToken),
createIdentifier("args")
)],
createKeywordTypeNode(SyntaxKind.AnyKeyword)
),
createFunctionTypeNode(
/*typeArguments*/ undefined,
[createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
createIdentifier("args"),
createToken(SyntaxKind.QuestionToken)
)],
createKeywordTypeNode(SyntaxKind.AnyKeyword)
),
createFunctionTypeNode(
/*typeArguments*/ undefined,
[createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
createIdentifier("args"),
/*questionToken*/ undefined,
createKeywordTypeNode(SyntaxKind.AnyKeyword)
)],
createKeywordTypeNode(SyntaxKind.AnyKeyword)
),
createFunctionTypeNode(
/*typeArguments*/ undefined,
[createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
createObjectBindingPattern([])
)],
createKeywordTypeNode(SyntaxKind.AnyKeyword)
),
]),
createSourceFile("source.ts", "", ScriptTarget.ES2015)
));
});
});
}
+3 -3
View File
@@ -25,7 +25,7 @@ namespace ts.server {
clearTimeout: noop,
setImmediate: () => 0,
clearImmediate: noop,
createHash: s => s
createHash: Harness.LanguageService.mockHash,
};
const mockLogger: Logger = {
@@ -240,8 +240,8 @@ namespace ts.server {
CommandNames.GetCodeFixesFull,
CommandNames.GetSupportedCodeFixes,
CommandNames.GetApplicableRefactors,
CommandNames.GetRefactorCodeActions,
CommandNames.GetRefactorCodeActionsFull,
CommandNames.GetEditsForRefactor,
CommandNames.GetEditsForRefactorFull,
];
it("should not throw when commands are executed with invalid arguments", () => {
+27 -25
View File
@@ -9,6 +9,7 @@ namespace ts.projectSystem {
et.service.openClientFile(file.path);
assert.equal(et.getEvents().length, 0);
});
it("only sends an event once", () => {
const file = makeFile("/a.ts");
const tsconfig = makeFile("/tsconfig.json", {});
@@ -46,12 +47,13 @@ namespace ts.projectSystem {
const et = new EventTracker([file1]);
const compilerOptions: ts.CompilerOptions = { strict: true };
const projectFileName = "foo.csproj";
const projectFileName = "/hunter2/foo.csproj";
open();
// TODO: Apparently compilerOptions is mutated, so have to repeat it here!
et.assertProjectInfoTelemetryEvent({
projectId: Harness.LanguageService.mockHash("/hunter2/foo.csproj"),
compilerOptions: { strict: true },
compileOnSave: true,
// These properties can't be present for an external project, so they are undefined instead of false.
@@ -195,6 +197,7 @@ namespace ts.projectSystem {
const et = new EventTracker([jsconfig, file]);
et.service.openClientFile(file.path);
et.assertProjectInfoTelemetryEvent({
projectId: Harness.LanguageService.mockHash("/jsconfig.json"),
fileStats: fileStats({ js: 1 }),
compilerOptions: autoJsCompilerOptions,
typeAcquisition: {
@@ -214,6 +217,7 @@ namespace ts.projectSystem {
et.service.openClientFile(file.path);
et.getEvent<server.ProjectLanguageServiceStateEvent>(server.ProjectLanguageServiceStateEvent, /*mayBeMore*/ true);
et.assertProjectInfoTelemetryEvent({
projectId: Harness.LanguageService.mockHash("/jsconfig.json"),
fileStats: fileStats({ js: 1 }),
compilerOptions: autoJsCompilerOptions,
configFileName: "jsconfig.json",
@@ -248,39 +252,37 @@ namespace ts.projectSystem {
}
assertProjectInfoTelemetryEvent(partial: Partial<server.ProjectInfoTelemetryEventData>): void {
assert.deepEqual(this.getEvent<server.ProjectInfoTelemetryEvent>(ts.server.ProjectInfoTelemetryEvent), makePayload(partial));
assert.deepEqual(this.getEvent<server.ProjectInfoTelemetryEvent>(ts.server.ProjectInfoTelemetryEvent), {
projectId: Harness.LanguageService.mockHash("/tsconfig.json"),
fileStats: fileStats({ ts: 1 }),
compilerOptions: {},
extends: false,
files: false,
include: false,
exclude: false,
compileOnSave: false,
typeAcquisition: {
enable: false,
exclude: false,
include: false,
},
configFileName: "tsconfig.json",
projectType: "configured",
languageServiceEnabled: true,
version: ts.version,
...partial,
});
}
getEvent<T extends server.ProjectServiceEvent>(eventName: T["eventName"], mayBeMore = false): T["data"] {
if (mayBeMore) assert(this.events.length !== 0); else assert.equal(this.events.length, 1);
if (mayBeMore) { assert(this.events.length !== 0); }
else { assert.equal(this.events.length, 1); }
const event = this.events.shift();
assert.equal(event.eventName, eventName);
return event.data;
}
}
function makePayload(partial: Partial<server.ProjectInfoTelemetryEventData>): server.ProjectInfoTelemetryEventData {
return {
fileStats: fileStats({ ts: 1 }),
compilerOptions: {},
extends: false,
files: false,
include: false,
exclude: false,
compileOnSave: false,
typeAcquisition: {
enable: false,
exclude: false,
include: false,
},
configFileName: "tsconfig.json",
projectType: "configured",
languageServiceEnabled: true,
version: ts.version,
...partial
};
}
function makeFile(path: string, content: {} = ""): projectSystem.FileOrFolder {
return { path, content: typeof content === "string" ? "" : JSON.stringify(content) };
}
+2 -2
View File
@@ -36,7 +36,7 @@ namespace ts {
transpileOptions.reportDiagnostics = true;
justName = "transpile/" + name.replace(/[^a-z0-9\-. ]/ig, "") + (transpileOptions.compilerOptions.jsx ? ".tsx" : ".ts");
justName = "transpile/" + name.replace(/[^a-z0-9\-. ]/ig, "") + (transpileOptions.compilerOptions.jsx ? Extension.Tsx : Extension.Ts);
toBeCompiled = [{
unitName: transpileOptions.fileName,
content: input
@@ -88,7 +88,7 @@ namespace ts {
}
it("Correct output for " + justName, () => {
Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".js"), () => {
Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ts.Extension.Js), () => {
if (transpileResult.outputText) {
return transpileResult.outputText;
}
@@ -13,7 +13,8 @@ namespace ts.projectSystem {
express: "express",
jquery: "jquery",
lodash: "lodash",
moment: "moment"
moment: "moment",
chroma: "chroma-js"
})
};
@@ -61,7 +62,6 @@ namespace ts.projectSystem {
super(installTypingHost, globalTypingsCacheLocation, safeList.path, throttleLimit, log);
}
safeFileList = safeList.path;
protected postExecActions: PostExecAction[] = [];
executePendingCommands() {
@@ -472,7 +472,7 @@ namespace ts.projectSystem {
}
createHash(s: string): string {
return s;
return Harness.LanguageService.mockHash(s);
}
triggerDirectoryWatcherCallback(directoryName: string, fileName: string): void {
+24 -3
View File
@@ -1009,6 +1009,26 @@ namespace ts.projectSystem {
});
describe("discover typings", () => {
it("should use mappings from safe list", () => {
const app = {
path: "/a/b/app.js",
content: ""
};
const jquery = {
path: "/a/b/jquery.js",
content: ""
};
const chroma = {
path: "/a/b/chroma.min.js",
content: ""
};
const cache = createMap<string>();
const host = createServerHost([app, jquery, chroma]);
const result = JsTyping.discoverTypings(host, [app.path, jquery.path, chroma.path], getDirectoryPath(<Path>app.path), /*safeListPath*/ undefined, cache, { enable: true }, []);
assert.deepEqual(result.newTypingNames, ["jquery", "chroma-js"]);
});
it("should return node for core modules", () => {
const f = {
path: "/a/b/app.js",
@@ -1016,6 +1036,7 @@ namespace ts.projectSystem {
};
const host = createServerHost([f]);
const cache = createMap<string>();
for (const name of JsTyping.nodeCoreModuleList) {
const result = JsTyping.discoverTypings(host, [f.path], getDirectoryPath(<Path>f.path), /*safeListPath*/ undefined, cache, { enable: true }, [name, "somename"]);
assert.deepEqual(result.newTypingNames.sort(), ["node", "somename"]);
@@ -1040,7 +1061,7 @@ namespace ts.projectSystem {
});
describe("telemetry events", () => {
it ("should be received", () => {
it("should be received", () => {
const f1 = {
path: "/a/app.js",
content: ""
@@ -1089,7 +1110,7 @@ namespace ts.projectSystem {
});
describe("progress notifications", () => {
it ("should be sent for success", () => {
it("should be sent for success", () => {
const f1 = {
path: "/a/app.js",
content: ""
@@ -1140,7 +1161,7 @@ namespace ts.projectSystem {
checkProjectActualFiles(projectService.inferredProjects[0], [f1.path, commander.path]);
});
it ("should be sent for error", () => {
it("should be sent for error", () => {
const f1 = {
path: "/a/app.js",
content: ""
+2 -1
View File
@@ -3483,7 +3483,7 @@ interface DragEvent extends MouseEvent {
declare var DragEvent: {
prototype: DragEvent;
new(): DragEvent;
new(type: "drag" | "dragend" | "dragenter" | "dragexit" | "dragleave" | "dragover" | "dragstart" | "drop", dragEventInit?: { dataTransfer?: DataTransfer }): DragEvent;
};
interface DynamicsCompressorNode extends AudioNode {
@@ -8224,6 +8224,7 @@ interface Navigator extends Object, NavigatorID, NavigatorOnLine, NavigatorConte
readonly serviceWorker: ServiceWorkerContainer;
readonly webdriver: boolean;
readonly hardwareConcurrency: number;
readonly languages: string[];
getGamepads(): Gamepad[];
javaEnabled(): boolean;
msLaunchUri(uri: string, successCallback?: MSLaunchUriCallback, noHandlerCallback?: MSLaunchUriCallback): void;
+146 -351
View File
File diff suppressed because it is too large Load Diff
+37 -8
View File
@@ -719,20 +719,49 @@ namespace ts.server {
return response.body;
}
getRefactorCodeActions(
getEditsForRefactor(
fileName: string,
_formatOptions: FormatCodeSettings,
positionOrRange: number | TextRange,
refactorName: string) {
refactorName: string,
actionName: string): RefactorEditInfo {
const args = this.createFileLocationOrRangeRequestArgs(positionOrRange, fileName) as protocol.GetRefactorCodeActionsRequestArgs;
args.refactorName = refactorName;
const args = this.createFileLocationOrRangeRequestArgs(positionOrRange, fileName) as protocol.GetEditsForRefactorRequestArgs;
args.refactor = refactorName;
args.action = actionName;
const request = this.processRequest<protocol.GetRefactorCodeActionsRequest>(CommandNames.GetRefactorCodeActions, args);
const response = this.processResponse<protocol.GetRefactorCodeActionsResponse>(request);
const codeActions = response.body.actions;
const request = this.processRequest<protocol.GetEditsForRefactorRequest>(CommandNames.GetEditsForRefactor, args);
const response = this.processResponse<protocol.GetEditsForRefactorResponse>(request);
return map(codeActions, codeAction => this.convertCodeActions(codeAction, fileName));
if (!response.body) {
return {
edits: []
};
}
const edits: FileTextChanges[] = this.convertCodeEditsToTextChanges(response.body.edits);
const renameFilename: string | undefined = response.body.renameFilename;
let renameLocation: number | undefined = undefined;
if (renameFilename !== undefined) {
renameLocation = this.lineOffsetToPosition(renameFilename, response.body.renameLocation);
}
return {
edits,
renameFilename,
renameLocation
};
}
private convertCodeEditsToTextChanges(edits: ts.server.protocol.FileCodeEdits[]): FileTextChanges[] {
return edits.map(edit => {
const fileName = edit.fileName;
return {
fileName,
textChanges: edit.textChanges.map(t => this.convertTextChangeToCodeEdit(t, fileName))
};
});
}
convertCodeActions(entry: protocol.CodeAction, fileName: string): CodeAction {
+3
View File
@@ -37,6 +37,8 @@ namespace ts.server {
}
export interface ProjectInfoTelemetryEventData {
/** Cryptographically secure hash of project file location. */
readonly projectId: string;
/** Count of file extensions seen in the project. */
readonly fileStats: FileStats;
/**
@@ -1049,6 +1051,7 @@ namespace ts.server {
if (!this.eventHandler) return;
const data: ProjectInfoTelemetryEventData = {
projectId: this.host.createHash(projectKey),
fileStats: countEachFileTypes(project.getScriptInfos()),
compilerOptions: convertCompilerOptionsForTelemetry(project.getCompilerOptions()),
typeAcquisition: convertTypeAcquisition(project.getTypeAcquisition()),
+32 -16
View File
@@ -25,7 +25,7 @@ namespace ts.server {
result.jsx += 1;
break;
case ScriptKind.TS:
fileExtensionIs(info.fileName, ".d.ts")
fileExtensionIs(info.fileName, Extension.Dts)
? result.dts += 1
: result.ts += 1;
break;
@@ -106,6 +106,7 @@ namespace ts.server {
private rootFiles: ScriptInfo[] = [];
private rootFilesMap: FileMap<ScriptInfo> = createFileMap<ScriptInfo>();
private program: ts.Program;
private externalFiles: SortedReadonlyArray<string>;
private cachedUnresolvedImportsPerFile = new UnresolvedImportsMap();
private lastCachedUnresolvedImportsList: SortedReadonlyArray<string>;
@@ -261,8 +262,8 @@ namespace ts.server {
abstract getProjectRootPath(): string | undefined;
abstract getTypeAcquisition(): TypeAcquisition;
getExternalFiles(): string[] {
return [];
getExternalFiles(): SortedReadonlyArray<string> {
return emptyArray as SortedReadonlyArray<string>;
}
getSourceFile(path: Path) {
@@ -561,6 +562,24 @@ namespace ts.server {
}
}
}
const oldExternalFiles = this.externalFiles || emptyArray as SortedReadonlyArray<string>;
this.externalFiles = this.getExternalFiles();
enumerateInsertsAndDeletes(this.externalFiles, oldExternalFiles,
// Ensure a ScriptInfo is created for new external files. This is performed indirectly
// by the LSHost for files in the program when the program is retrieved above but
// the program doesn't contain external files so this must be done explicitly.
inserted => {
const scriptInfo = this.projectService.getOrCreateScriptInfo(inserted, /*openedByClient*/ false);
scriptInfo.attachToProject(this);
},
removed => {
const scriptInfoToDetach = this.projectService.getScriptInfo(removed);
if (scriptInfoToDetach) {
scriptInfoToDetach.detachFromProject(this);
}
});
return hasChanges;
}
@@ -646,7 +665,7 @@ namespace ts.server {
const added: string[] = [];
const removed: string[] = [];
const updated: string[] = arrayFrom(updatedFileNames.keys());
const updated: string[] = updatedFileNames ? arrayFrom(updatedFileNames.keys()) : [];
forEachKey(currentFiles, id => {
if (!lastReportedFileNames.has(id)) {
@@ -956,19 +975,16 @@ namespace ts.server {
return this.typeAcquisition;
}
getExternalFiles(): string[] {
const items: string[] = [];
for (const plugin of this.plugins) {
if (typeof plugin.getExternalFiles === "function") {
try {
items.push(...plugin.getExternalFiles(this));
}
catch (e) {
this.projectService.logger.info(`A plugin threw an exception in getExternalFiles: ${e}`);
}
getExternalFiles(): SortedReadonlyArray<string> {
return toSortedReadonlyArray(flatMap(this.plugins, plugin => {
if (typeof plugin.getExternalFiles !== "function") return;
try {
return plugin.getExternalFiles(this);
}
}
return items;
catch (e) {
this.projectService.logger.info(`A plugin threw an exception in getExternalFiles: ${e}`);
}
}));
}
watchConfigFile(callback: (project: ConfiguredProject) => void) {
+79 -30
View File
@@ -98,8 +98,11 @@ namespace ts.server.protocol {
GetSupportedCodeFixes = "getSupportedCodeFixes",
GetApplicableRefactors = "getApplicableRefactors",
GetRefactorCodeActions = "getRefactorCodeActions",
GetRefactorCodeActionsFull = "getRefactorCodeActions-full",
GetEditsForRefactor = "getEditsForRefactor",
/* @internal */
GetEditsForRefactorFull = "getEditsForRefactor-full",
// NOTE: If updating this, be sure to also update `allCommandNames` in `harness/unittests/session.ts`.
}
/**
@@ -401,52 +404,98 @@ namespace ts.server.protocol {
export type FileLocationOrRangeRequestArgs = FileLocationRequestArgs | FileRangeRequestArgs;
/**
* Request refactorings at a given position or selection area.
*/
export interface GetApplicableRefactorsRequest extends Request {
command: CommandTypes.GetApplicableRefactors;
arguments: GetApplicableRefactorsRequestArgs;
}
export type GetApplicableRefactorsRequestArgs = FileLocationOrRangeRequestArgs;
export interface ApplicableRefactorInfo {
name: string;
description: string;
}
/**
* Response is a list of available refactorings.
* Each refactoring exposes one or more "Actions"; a user selects one action to invoke a refactoring
*/
export interface GetApplicableRefactorsResponse extends Response {
body?: ApplicableRefactorInfo[];
}
export interface GetRefactorCodeActionsRequest extends Request {
command: CommandTypes.GetRefactorCodeActions;
arguments: GetRefactorCodeActionsRequestArgs;
/**
* A set of one or more available refactoring actions, grouped under a parent refactoring.
*/
export 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[];
}
export type GetRefactorCodeActionsRequestArgs = FileLocationOrRangeRequestArgs & {
/* The kind of the applicable refactor */
refactorName: string;
/**
* 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.
*/
export 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;
};
export type RefactorCodeActions = {
actions: protocol.CodeAction[];
renameLocation?: number
};
/* @internal */
export type RefactorCodeActionsFull = {
actions: ts.CodeAction[];
renameLocation?: number
};
export interface GetRefactorCodeActionsResponse extends Response {
body: RefactorCodeActions;
export interface GetEditsForRefactorRequest extends Request {
command: CommandTypes.GetEditsForRefactor;
arguments: GetEditsForRefactorRequestArgs;
}
/* @internal */
export interface GetRefactorCodeActionsFullResponse extends Response {
body: RefactorCodeActionsFull;
/**
* Request the edits that a particular refactoring action produces.
* Callers must specify the name of the refactor and the name of the action.
*/
export type GetEditsForRefactorRequestArgs = FileLocationOrRangeRequestArgs & {
/* The 'name' property from the refactoring that offered this action */
refactor: string;
/* The 'name' property from the refactoring action */
action: string;
};
export interface GetEditsForRefactorResponse extends Response {
body?: RefactorEditInfo;
}
export 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.
*/
+6 -3
View File
@@ -35,6 +35,7 @@ namespace ts.server {
} = require("os");
function getGlobalTypingsCacheLocation() {
const versionMajorMinor = ts.version.match(/\d+\.\d+/)[0];
switch (process.platform) {
case "win32": {
const basePath = process.env.LOCALAPPDATA ||
@@ -43,13 +44,15 @@ namespace ts.server {
process.env.USERPROFILE ||
(process.env.HOMEDRIVE && process.env.HOMEPATH && normalizeSlashes(process.env.HOMEDRIVE + process.env.HOMEPATH)) ||
os.tmpdir();
return combinePaths(normalizeSlashes(basePath), "Microsoft/TypeScript");
return combinePaths(combinePaths(normalizeSlashes(basePath), "Microsoft/TypeScript"), versionMajorMinor);
}
case "openbsd":
case "freebsd":
case "darwin":
case "linux":
case "android": {
const cacheLocation = getNonWindowsCacheLocation(process.platform === "darwin");
return combinePaths(cacheLocation, "typescript");
return combinePaths(combinePaths(cacheLocation, "typescript"), versionMajorMinor);
}
default:
Debug.fail(`unsupported platform '${process.platform}'`);
@@ -524,7 +527,7 @@ namespace ts.server {
watchedFile.callback(watchedFile.fileName);
}
else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) {
watchedFile.mtime = getModifiedTime(watchedFile.fileName);
watchedFile.mtime = stats.mtime;
watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0);
}
});
+48 -19
View File
@@ -112,7 +112,13 @@ namespace ts.server {
return true;
}
export import CommandNames = protocol.CommandTypes;
// CommandNames used to be exposed before TS 2.4 as a namespace
// In TS 2.4 we switched to an enum, keep this for backward compatibility
// The var assignment ensures that even though CommandTypes are a const enum
// we want to ensure the value is maintained in the out since the file is
// built using --preseveConstEnum.
export type CommandNames = protocol.CommandTypes;
export const CommandNames = (<any>protocol).CommandTypes;
export function formatMessage<T extends protocol.Message>(msg: T, logger: server.Logger, byteLength: (s: string, encoding: string) => number, newLine: string): string {
const verboseLogging = logger.hasLevel(LogLevel.verbose);
@@ -1425,29 +1431,40 @@ namespace ts.server {
return project.getLanguageService().getApplicableRefactors(file, position || textRange);
}
private getRefactorCodeActions(args: protocol.GetRefactorCodeActionsRequestArgs, simplifiedResult: boolean): protocol.RefactorCodeActions | protocol.RefactorCodeActionsFull {
private getEditsForRefactor(args: protocol.GetEditsForRefactorRequestArgs, simplifiedResult: boolean): ts.RefactorEditInfo | protocol.RefactorEditInfo {
const { file, project } = this.getFileAndProjectWithoutRefreshingInferredProjects(args);
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
const { position, textRange } = this.extractPositionAndRange(args, scriptInfo);
const result: ts.CodeAction[] = project.getLanguageService().getRefactorCodeActions(
const result = project.getLanguageService().getEditsForRefactor(
file,
this.projectService.getFormatCodeOptions(),
position || textRange,
args.refactorName
args.refactor,
args.action
);
if (simplifiedResult) {
// Not full
if (result === undefined) {
return {
actions: result.map(action => this.mapCodeAction(action, scriptInfo))
edits: []
};
}
if (simplifiedResult) {
const file = result.renameFilename;
let location: ILineInfo | undefined = undefined;
if (file !== undefined && result.renameLocation !== undefined) {
const renameScriptInfo = project.getScriptInfoForNormalizedPath(toNormalizedPath(file));
location = renameScriptInfo.positionToLineOffset(result.renameLocation);
}
return {
renameLocation: location,
renameFilename: file,
edits: result.edits.map(change => this.mapTextChangesToCodeEdits(project, change))
};
}
else {
// Full
return {
actions: result
};
return result;
}
}
@@ -1505,6 +1522,14 @@ namespace ts.server {
};
}
private mapTextChangesToCodeEdits(project: Project, textChanges: FileTextChanges): protocol.FileCodeEdits {
const scriptInfo = project.getScriptInfoForNormalizedPath(toNormalizedPath(textChanges.fileName));
return {
fileName: textChanges.fileName,
textChanges: textChanges.textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, scriptInfo))
};
}
private convertTextChangeToCodeEdit(change: ts.TextChange, scriptInfo: ScriptInfo): protocol.CodeEdit {
return {
start: scriptInfo.positionToLineOffset(change.span.start),
@@ -1544,18 +1569,22 @@ namespace ts.server {
const normalizedFileName = toNormalizedPath(fileName);
const project = this.projectService.getDefaultProjectForFile(normalizedFileName, /*refreshInferredProjects*/ true);
for (const fileNameInProject of fileNamesInProject) {
if (this.getCanonicalFileName(fileNameInProject) === this.getCanonicalFileName(fileName))
if (this.getCanonicalFileName(fileNameInProject) === this.getCanonicalFileName(fileName)) {
highPriorityFiles.push(fileNameInProject);
}
else {
const info = this.projectService.getScriptInfo(fileNameInProject);
if (!info.isScriptOpen()) {
if (fileNameInProject.indexOf(".d.ts") > 0)
if (fileNameInProject.indexOf(Extension.Dts) > 0) {
veryLowPriorityFiles.push(fileNameInProject);
else
}
else {
lowPriorityFiles.push(fileNameInProject);
}
}
else
else {
mediumPriorityFiles.push(fileNameInProject);
}
}
}
@@ -1833,11 +1862,11 @@ namespace ts.server {
[CommandNames.GetApplicableRefactors]: (request: protocol.GetApplicableRefactorsRequest) => {
return this.requiredResponse(this.getApplicableRefactors(request.arguments));
},
[CommandNames.GetRefactorCodeActions]: (request: protocol.GetRefactorCodeActionsRequest) => {
return this.requiredResponse(this.getRefactorCodeActions(request.arguments, /*simplifiedResult*/ true));
[CommandNames.GetEditsForRefactor]: (request: protocol.GetEditsForRefactorRequest) => {
return this.requiredResponse(this.getEditsForRefactor(request.arguments, /*simplifiedResult*/ true));
},
[CommandNames.GetRefactorCodeActionsFull]: (request: protocol.GetRefactorCodeActionsRequest) => {
return this.requiredResponse(this.getRefactorCodeActions(request.arguments, /*simplifiedResult*/ false));
[CommandNames.GetEditsForRefactorFull]: (request: protocol.GetEditsForRefactorRequest) => {
return this.requiredResponse(this.getEditsForRefactor(request.arguments, /*simplifiedResult*/ false));
}
});
+31
View File
@@ -195,6 +195,37 @@ namespace ts.server {
return <any>arr;
}
export function enumerateInsertsAndDeletes<T>(a: SortedReadonlyArray<T>, b: SortedReadonlyArray<T>, inserted: (item: T) => void, deleted: (item: T) => void, compare?: (a: T, b: T) => Comparison) {
compare = compare || ts.compareValues;
let aIndex = 0;
let bIndex = 0;
const aLen = a.length;
const bLen = b.length;
while (aIndex < aLen && bIndex < bLen) {
const aItem = a[aIndex];
const bItem = b[bIndex];
const compareResult = compare(aItem, bItem);
if (compareResult === Comparison.LessThan) {
inserted(aItem);
aIndex++;
}
else if (compareResult === Comparison.GreaterThan) {
deleted(bItem);
bIndex++;
}
else {
aIndex++;
bIndex++;
}
}
while (aIndex < aLen) {
inserted(a[aIndex++]);
}
while (bIndex < bLen) {
deleted(b[bIndex++]);
}
}
export class ThrottledOperations {
private pendingTimeouts: Map<any> = createMap<any>();
constructor(private readonly host: ServerHost) {
+1 -1
View File
@@ -146,7 +146,7 @@ namespace ts.BreakpointResolver {
case SyntaxKind.ForOfStatement:
// span in initializer
return spanInInitializerOfForLike(<ForOfStatement | ForInStatement>node);
return spanInInitializerOfForLike(<ForOfStatement>node);
case SyntaxKind.SwitchStatement:
// span on switch(...)
+3 -3
View File
@@ -724,8 +724,8 @@ namespace ts {
pushCommentRange(pos, tag.pos - pos);
}
pushClassification(tag.atToken.pos, tag.atToken.end - tag.atToken.pos, ClassificationType.punctuation);
pushClassification(tag.tagName.pos, tag.tagName.end - tag.tagName.pos, ClassificationType.docCommentTagName);
pushClassification(tag.atToken.pos, tag.atToken.end - tag.atToken.pos, ClassificationType.punctuation); // "@"
pushClassification(tag.tagName.pos, tag.tagName.end - tag.tagName.pos, ClassificationType.docCommentTagName); // e.g. "param"
pos = tag.tagName.end;
@@ -814,7 +814,7 @@ namespace ts {
* False will mean that node is not classified and traverse routine should recurse into node contents.
*/
function tryClassifyNode(node: Node): boolean {
if (isJSDocTag(node)) {
if (isJSDoc(node)) {
return true;
}
+125 -54
View File
@@ -8,107 +8,161 @@ namespace ts.codefix {
function getActionsForAddMissingMember(context: CodeFixContext): CodeAction[] | undefined {
const sourceFile = context.sourceFile;
const tokenSourceFile = context.sourceFile;
const start = context.span.start;
// This is the identifier of the missing property. eg:
// The identifier of the missing property. eg:
// this.missing = 1;
// ^^^^^^^
const token = getTokenAtPosition(sourceFile, start, /*includeJsDocComment*/ false);
const token = getTokenAtPosition(tokenSourceFile, start, /*includeJsDocComment*/ false);
if (token.kind !== SyntaxKind.Identifier) {
return undefined;
}
if (!isPropertyAccessExpression(token.parent) || token.parent.expression.kind !== SyntaxKind.ThisKeyword) {
if (!isPropertyAccessExpression(token.parent)) {
return undefined;
}
const classMemberDeclaration = getThisContainer(token, /*includeArrowFunctions*/ false);
if (!isClassElement(classMemberDeclaration)) {
return undefined;
const tokenName = token.getText(tokenSourceFile);
let makeStatic = false;
let classDeclaration: ClassLikeDeclaration;
if (token.parent.expression.kind === SyntaxKind.ThisKeyword) {
const containingClassMemberDeclaration = getThisContainer(token, /*includeArrowFunctions*/ false);
if (!isClassElement(containingClassMemberDeclaration)) {
return undefined;
}
classDeclaration = <ClassLikeDeclaration>containingClassMemberDeclaration.parent;
// Property accesses on `this` in a static method are accesses of a static member.
makeStatic = classDeclaration && hasModifier(containingClassMemberDeclaration, ModifierFlags.Static);
}
else {
const checker = context.program.getTypeChecker();
const leftExpression = token.parent.expression;
const leftExpressionType = checker.getTypeAtLocation(leftExpression);
if (leftExpressionType.flags & TypeFlags.Object) {
const symbol = leftExpressionType.symbol;
if (symbol.flags & SymbolFlags.Class) {
classDeclaration = symbol.declarations && <ClassLikeDeclaration>symbol.declarations[0];
if (leftExpressionType !== checker.getDeclaredTypeOfSymbol(symbol)) {
// The expression is a class symbol but the type is not the instance-side.
makeStatic = true;
}
}
}
}
const classDeclaration = <ClassLikeDeclaration>classMemberDeclaration.parent;
if (!classDeclaration || !isClassLike(classDeclaration)) {
return undefined;
}
const isStatic = hasModifier(classMemberDeclaration, ModifierFlags.Static);
const classDeclarationSourceFile = getSourceFileOfNode(classDeclaration);
const classOpenBrace = getOpenBraceOfClassLike(classDeclaration, classDeclarationSourceFile);
return isInJavaScriptFile(sourceFile) ? getActionsForAddMissingMemberInJavaScriptFile() : getActionsForAddMissingMemberInTypeScriptFile();
return isInJavaScriptFile(classDeclarationSourceFile) ?
getActionsForAddMissingMemberInJavaScriptFile(classDeclaration, makeStatic) :
getActionsForAddMissingMemberInTypeScriptFile(classDeclaration, makeStatic);
function getActionsForAddMissingMemberInJavaScriptFile(): CodeAction[] | undefined {
const memberName = token.getText();
function getActionsForAddMissingMemberInJavaScriptFile(classDeclaration: ClassLikeDeclaration, makeStatic: boolean): CodeAction[] | undefined {
let actions: CodeAction[];
if (isStatic) {
const methodCodeAction = getActionForMethodDeclaration(/*includeTypeScriptSyntax*/ false);
if (methodCodeAction) {
actions = [methodCodeAction];
}
if (makeStatic) {
if (classDeclaration.kind === SyntaxKind.ClassExpression) {
return undefined;
return actions;
}
const className = classDeclaration.name.getText();
return [{
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Initialize_static_property_0), [memberName]),
changes: [{
fileName: sourceFile.fileName,
textChanges: [{
span: { start: classDeclaration.getEnd(), length: 0 },
newText: `${context.newLineCharacter}${className}.${memberName} = undefined;${context.newLineCharacter}`
}]
}]
}];
const staticInitialization = createStatement(createAssignment(
createPropertyAccess(createIdentifier(className), tokenName),
createIdentifier("undefined")));
const staticInitializationChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
staticInitializationChangeTracker.insertNodeAfter(
classDeclarationSourceFile,
classDeclaration,
staticInitialization,
{ suffix: context.newLineCharacter });
const initializeStaticAction = {
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Initialize_static_property_0), [tokenName]),
changes: staticInitializationChangeTracker.getChanges()
};
(actions || (actions = [])).push(initializeStaticAction);
return actions;
}
else {
const classConstructor = getFirstConstructorWithBody(classDeclaration);
if (!classConstructor) {
return undefined;
return actions;
}
return [{
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Initialize_property_0_in_the_constructor), [memberName]),
changes: [{
fileName: sourceFile.fileName,
textChanges: [{
span: { start: classConstructor.body.getEnd() - 1, length: 0 },
newText: `this.${memberName} = undefined;${context.newLineCharacter}`
}]
}]
}];
const propertyInitialization = createStatement(createAssignment(
createPropertyAccess(createThis(), tokenName),
createIdentifier("undefined")));
const propertyInitializationChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
propertyInitializationChangeTracker.insertNodeAt(
classDeclarationSourceFile,
classConstructor.body.getEnd() - 1,
propertyInitialization,
{ prefix: context.newLineCharacter, suffix: context.newLineCharacter });
const initializeAction = {
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Initialize_property_0_in_the_constructor), [tokenName]),
changes: propertyInitializationChangeTracker.getChanges()
};
(actions || (actions = [])).push(initializeAction);
return actions;
}
}
function getActionsForAddMissingMemberInTypeScriptFile(): CodeAction[] | undefined {
let typeNode: TypeNode;
function getActionsForAddMissingMemberInTypeScriptFile(classDeclaration: ClassLikeDeclaration, makeStatic: boolean): CodeAction[] | undefined {
let actions: CodeAction[];
if (token.parent.parent.kind === SyntaxKind.BinaryExpression) {
const binaryExpression = token.parent.parent as BinaryExpression;
const checker = context.program.getTypeChecker();
const widenedType = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(binaryExpression.right)));
typeNode = checker.typeToTypeNode(widenedType, classDeclaration);
const methodCodeAction = getActionForMethodDeclaration(/*includeTypeScriptSyntax*/ true);
if (methodCodeAction) {
actions = [methodCodeAction];
}
let typeNode: TypeNode;
if (token.parent.parent.kind === SyntaxKind.BinaryExpression) {
const binaryExpression = token.parent.parent as BinaryExpression;
const otherExpression = token.parent === binaryExpression.left ? binaryExpression.right : binaryExpression.left;
const checker = context.program.getTypeChecker();
const widenedType = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(otherExpression)));
typeNode = checker.typeToTypeNode(widenedType, classDeclaration);
}
typeNode = typeNode || createKeywordTypeNode(SyntaxKind.AnyKeyword);
const openBrace = getOpenBraceOfClassLike(classDeclaration, sourceFile);
const property = createProperty(
/*decorators*/undefined,
/*modifiers*/ isStatic ? [createToken(SyntaxKind.StaticKeyword)] : undefined,
token.getText(sourceFile),
/*modifiers*/ makeStatic ? [createToken(SyntaxKind.StaticKeyword)] : undefined,
tokenName,
/*questionToken*/ undefined,
typeNode,
/*initializer*/ undefined);
const propertyChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
propertyChangeTracker.insertNodeAfter(sourceFile, openBrace, property, { suffix: context.newLineCharacter });
propertyChangeTracker.insertNodeAfter(classDeclarationSourceFile, classOpenBrace, property, { suffix: context.newLineCharacter });
const actions = [{
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_property_0), [token.getText()]),
(actions || (actions = [])).push({
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Declare_property_0), [tokenName]),
changes: propertyChangeTracker.getChanges()
}];
});
if (!isStatic) {
if (!makeStatic) {
// Index signatures cannot have the static modifier.
const stringTypeNode = createKeywordTypeNode(SyntaxKind.StringKeyword);
const indexingParameter = createParameter(
/*decorators*/ undefined,
@@ -125,15 +179,32 @@ namespace ts.codefix {
typeNode);
const indexSignatureChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
indexSignatureChangeTracker.insertNodeAfter(sourceFile, openBrace, indexSignature, { suffix: context.newLineCharacter });
indexSignatureChangeTracker.insertNodeAfter(classDeclarationSourceFile, classOpenBrace, indexSignature, { suffix: context.newLineCharacter });
actions.push({
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_missing_property_0), [token.getText()]),
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_property_0), [tokenName]),
changes: indexSignatureChangeTracker.getChanges()
});
}
return actions;
}
function getActionForMethodDeclaration(includeTypeScriptSyntax: boolean): CodeAction | undefined {
if (token.parent.parent.kind === SyntaxKind.CallExpression) {
const callExpression = <CallExpression>token.parent.parent;
const methodDeclaration = createMethodFromCallExpression(callExpression, tokenName, includeTypeScriptSyntax, makeStatic);
const methodDeclarationChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
methodDeclarationChangeTracker.insertNodeAfter(classDeclarationSourceFile, classOpenBrace, methodDeclaration, { suffix: context.newLineCharacter });
return {
description: formatStringFromArgs(getLocaleSpecificMessage(makeStatic ?
Diagnostics.Declare_method_0 :
Diagnostics.Declare_static_method_0),
[tokenName]),
changes: methodDeclarationChangeTracker.getChanges()
};
}
}
}
}
+45 -13
View File
@@ -142,6 +142,50 @@ namespace ts.codefix {
}
}
export function createMethodFromCallExpression(callExpression: CallExpression, methodName: string, includeTypeScriptSyntax: boolean, makeStatic: boolean): MethodDeclaration {
const parameters = createDummyParameters(callExpression.arguments.length, /*names*/ undefined, /*minArgumentCount*/ undefined, includeTypeScriptSyntax);
let typeParameters: TypeParameterDeclaration[];
if (includeTypeScriptSyntax) {
const typeArgCount = length(callExpression.typeArguments);
for (let i = 0; i < typeArgCount; i++) {
const name = typeArgCount < 8 ? String.fromCharCode(CharacterCodes.T + i) : `T${i}`;
const typeParameter = createTypeParameterDeclaration(name, /*constraint*/ undefined, /*defaultType*/ undefined);
(typeParameters ? typeParameters : typeParameters = []).push(typeParameter);
}
}
const newMethod = createMethod(
/*decorators*/ undefined,
/*modifiers*/ makeStatic ? [createToken(SyntaxKind.StaticKeyword)] : undefined,
/*asteriskToken*/ undefined,
methodName,
/*questionToken*/ undefined,
typeParameters,
parameters,
/*type*/ includeTypeScriptSyntax ? createKeywordTypeNode(SyntaxKind.AnyKeyword) : undefined,
createStubbedMethodBody()
);
return newMethod;
}
function createDummyParameters(argCount: number, names: string[] | undefined, minArgumentCount: number | undefined, addAnyType: boolean) {
const parameters: ParameterDeclaration[] = [];
for (let i = 0; i < argCount; i++) {
const newParameter = createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
/*name*/ names && names[i] || `arg${i}`,
/*questionToken*/ minArgumentCount !== undefined && i >= minArgumentCount ? createToken(SyntaxKind.QuestionToken) : undefined,
/*type*/ addAnyType ? createKeywordTypeNode(SyntaxKind.AnyKeyword) : undefined,
/*initializer*/ undefined);
parameters.push(newParameter);
}
return parameters;
}
function createMethodImplementingSignatures(signatures: Signature[], name: PropertyName, optional: boolean, modifiers: Modifier[] | undefined): MethodDeclaration {
/** This is *a* signature with the maximal number of arguments,
* such that if there is a "maximal" signature without rest arguments,
@@ -163,19 +207,7 @@ namespace ts.codefix {
const maxNonRestArgs = maxArgsSignature.parameters.length - (maxArgsSignature.hasRestParameter ? 1 : 0);
const maxArgsParameterSymbolNames = maxArgsSignature.parameters.map(symbol => symbol.getName());
const parameters: ParameterDeclaration[] = [];
for (let i = 0; i < maxNonRestArgs; i++) {
const anyType = createKeywordTypeNode(SyntaxKind.AnyKeyword);
const newParameter = createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
maxArgsParameterSymbolNames[i],
/*questionToken*/ i >= minArgumentCount ? createToken(SyntaxKind.QuestionToken) : undefined,
anyType,
/*initializer*/ undefined);
parameters.push(newParameter);
}
const parameters = createDummyParameters(maxNonRestArgs, maxArgsParameterSymbolNames, minArgumentCount, /*addAnyType*/ true);
if (someSigHasRestParameter) {
const anyArrayType = createArrayTypeNode(createKeywordTypeNode(SyntaxKind.AnyKeyword));
+27 -11
View File
@@ -138,8 +138,23 @@ namespace ts.codefix {
const currentTokenMeaning = getMeaningFromLocation(token);
if (context.errorCode === Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead.code) {
const symbol = checker.getAliasedSymbol(checker.getSymbolAtLocation(token));
return getCodeActionForImport(symbol, /*isDefault*/ false, /*isNamespaceImport*/ true);
const umdSymbol = checker.getSymbolAtLocation(token);
let symbol: ts.Symbol;
let symbolName: string;
if (umdSymbol.flags & ts.SymbolFlags.Alias) {
symbol = checker.getAliasedSymbol(umdSymbol);
symbolName = name;
}
else if (isJsxOpeningLikeElement(token.parent) && token.parent.tagName === token) {
// The error wasn't for the symbolAtLocation, it was for the JSX tag itself, which needs access to e.g. `React`.
symbol = checker.getAliasedSymbol(checker.resolveNameAtLocation(token, checker.getJsxNamespace(), SymbolFlags.Value));
symbolName = symbol.name;
}
else {
Debug.fail("Either the symbol or the JSX namespace should be a UMD global if we got here");
}
return getCodeActionForImport(symbol, symbolName, /*isDefault*/ false, /*isNamespaceImport*/ true);
}
const candidateModules = checker.getAmbientModules();
@@ -159,7 +174,7 @@ namespace ts.codefix {
if (localSymbol && localSymbol.name === name && checkSymbolHasMeaning(localSymbol, currentTokenMeaning)) {
// check if this symbol is already used
const symbolId = getUniqueSymbolId(localSymbol);
symbolIdActionMap.addActions(symbolId, getCodeActionForImport(moduleSymbol, /*isDefault*/ true));
symbolIdActionMap.addActions(symbolId, getCodeActionForImport(moduleSymbol, name, /*isDefault*/ true));
}
}
@@ -167,7 +182,7 @@ namespace ts.codefix {
const exportSymbolWithIdenticalName = checker.tryGetMemberInModuleExports(name, moduleSymbol);
if (exportSymbolWithIdenticalName && checkSymbolHasMeaning(exportSymbolWithIdenticalName, currentTokenMeaning)) {
const symbolId = getUniqueSymbolId(exportSymbolWithIdenticalName);
symbolIdActionMap.addActions(symbolId, getCodeActionForImport(moduleSymbol));
symbolIdActionMap.addActions(symbolId, getCodeActionForImport(moduleSymbol, name));
}
}
@@ -218,7 +233,7 @@ namespace ts.codefix {
return declarations ? some(symbol.declarations, decl => !!(getMeaningFromDeclaration(decl) & meaning)) : false;
}
function getCodeActionForImport(moduleSymbol: Symbol, isDefault?: boolean, isNamespaceImport?: boolean): ImportCodeAction[] {
function getCodeActionForImport(moduleSymbol: Symbol, symbolName: string, isDefault?: boolean, isNamespaceImport?: boolean): ImportCodeAction[] {
const existingDeclarations = getImportDeclarations(moduleSymbol);
if (existingDeclarations.length > 0) {
// With an existing import statement, there are more than one actions the user can do.
@@ -375,10 +390,10 @@ namespace ts.codefix {
const moduleSpecifierWithoutQuotes = stripQuotes(moduleSpecifier || getModuleSpecifierForNewImport());
const changeTracker = createChangeTracker();
const importClause = isDefault
? createImportClause(createIdentifier(name), /*namedBindings*/ undefined)
? createImportClause(createIdentifier(symbolName), /*namedBindings*/ undefined)
: isNamespaceImport
? createImportClause(/*name*/ undefined, createNamespaceImport(createIdentifier(name)))
: createImportClause(/*name*/ undefined, createNamedImports([createImportSpecifier(/*propertyName*/ undefined, createIdentifier(name))]));
? createImportClause(/*name*/ undefined, createNamespaceImport(createIdentifier(symbolName)))
: createImportClause(/*name*/ undefined, createNamedImports([createImportSpecifier(/*propertyName*/ undefined, createIdentifier(symbolName))]));
const importDecl = createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, importClause, createLiteral(moduleSpecifierWithoutQuotes));
if (!lastImportDeclaration) {
changeTracker.insertNodeAt(sourceFile, sourceFile.getStart(), importDecl, { suffix: `${context.newLineCharacter}${context.newLineCharacter}` });
@@ -392,7 +407,7 @@ namespace ts.codefix {
// are there are already a new line seperating code and import statements.
return createCodeAction(
Diagnostics.Import_0_from_1,
[name, `"${moduleSpecifierWithoutQuotes}"`],
[symbolName, `"${moduleSpecifierWithoutQuotes}"`],
changeTracker.getChanges(),
"NewImport",
moduleSpecifierWithoutQuotes
@@ -412,8 +427,9 @@ namespace ts.codefix {
removeFileExtension(getRelativePath(moduleFileName, sourceDirectory));
function tryGetModuleNameFromAmbientModule(): string {
if (moduleSymbol.valueDeclaration.kind !== SyntaxKind.SourceFile) {
return moduleSymbol.name;
const decl = moduleSymbol.valueDeclaration;
if (isModuleDeclaration(decl) && isStringLiteral(decl.name)) {
return decl.name.text;
}
}
+114 -70
View File
@@ -18,16 +18,33 @@ namespace ts.Completions {
return undefined;
}
const { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, requestJsDocTagName, requestJsDocTag, hasFilteredClassMemberKeywords } = completionData;
const { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, request, hasFilteredClassMemberKeywords } = completionData;
if (requestJsDocTagName) {
// If the current position is a jsDoc tag name, only tag names should be provided for completion
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getJSDocTagNameCompletions() };
if (sourceFile.languageVariant === LanguageVariant.JSX &&
location && location.parent && location.parent.kind === SyntaxKind.JsxClosingElement) {
// In the TypeScript JSX element, if such element is not defined. When users query for completion at closing tag,
// instead of simply giving unknown value, the completion will return the tag-name of an associated opening-element.
// For example:
// var x = <div> </ /*1*/> completion list at "1" will contain "div" with type any
const tagName = (<JsxElement>location.parent.parent).openingElement.tagName;
return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: false,
entries: [{
name: (<JsxTagNameExpression>tagName).getFullText(),
kind: ScriptElementKind.classElement,
kindModifiers: undefined,
sortText: "0",
}]};
}
if (requestJsDocTag) {
// If the current position is a jsDoc tag, only tags should be provided for completion
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getJSDocTagCompletions() };
if (request) {
const entries = request.kind === "JsDocTagName"
// If the current position is a jsDoc tag name, only tag names should be provided for completion
? JsDoc.getJSDocTagNameCompletions()
: request.kind === "JsDocTag"
// If the current position is a jsDoc tag, only tags should be provided for completion
? JsDoc.getJSDocTagCompletions()
: JsDoc.getJSDocParameterNameCompletions(request.tag);
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries };
}
const entries: CompletionEntry[] = [];
@@ -38,21 +55,7 @@ namespace ts.Completions {
}
else {
if (!symbols || symbols.length === 0) {
if (sourceFile.languageVariant === LanguageVariant.JSX &&
location.parent && location.parent.kind === SyntaxKind.JsxClosingElement) {
// In the TypeScript JSX element, if such element is not defined. When users query for completion at closing tag,
// instead of simply giving unknown value, the completion will return the tag-name of an associated opening-element.
// For example:
// var x = <div> </ /*1*/> completion list at "1" will contain "div" with type any
const tagName = (<JsxElement>location.parent.parent).openingElement.tagName;
entries.push({
name: (<Identifier>tagName).text,
kind: undefined,
kindModifiers: undefined,
sortText: "0",
});
}
else if (!hasFilteredClassMemberKeywords) {
if (!hasFilteredClassMemberKeywords) {
return undefined;
}
}
@@ -64,7 +67,7 @@ namespace ts.Completions {
addRange(entries, classMemberKeywordCompletions);
}
// Add keywords if this is not a member completion list
else if (!isMemberCompletion && !requestJsDocTag && !requestJsDocTagName) {
else if (!isMemberCompletion) {
addRange(entries, keywordCompletions);
}
@@ -345,16 +348,27 @@ namespace ts.Completions {
return undefined;
}
function getCompletionData(typeChecker: TypeChecker, log: (message: string) => void, sourceFile: SourceFile, position: number) {
interface CompletionData {
symbols: Symbol[];
isGlobalCompletion: boolean;
isMemberCompletion: boolean;
isNewIdentifierLocation: boolean;
location: Node;
isRightOfDot: boolean;
request?: Request;
hasFilteredClassMemberKeywords: boolean;
}
type Request = { kind: "JsDocTagName" } | { kind: "JsDocTag" } | { kind: "JsDocParameterName", tag: JSDocParameterTag };
function getCompletionData(typeChecker: TypeChecker, log: (message: string) => void, sourceFile: SourceFile, position: number): CompletionData {
const isJavaScriptFile = isSourceFileJavaScript(sourceFile);
// JsDoc tag-name is just the name of the JSDoc tagname (exclude "@")
let requestJsDocTagName = false;
// JsDoc tag includes both "@" and tag-name
let requestJsDocTag = false;
let request: Request | undefined;
let start = timestamp();
let currentToken = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false); // TODO: GH#15853
// We will check for jsdoc comments with insideComment and getJsDocTagAtPosition. (TODO: that seems rather inefficient to check the same thing so many times.)
log("getCompletionData: Get current token: " + (timestamp() - start));
start = timestamp();
@@ -365,10 +379,10 @@ namespace ts.Completions {
let insideJsDocTagTypeExpression = false;
if (insideComment) {
if (hasDocComment(sourceFile, position)) {
// The current position is next to the '@' sign, when no tag name being provided yet.
// Provide a full list of tag names
if (sourceFile.text.charCodeAt(position - 1) === CharacterCodes.at) {
requestJsDocTagName = true;
// The current position is next to the '@' sign, when no tag name being provided yet.
// Provide a full list of tag names
request = { kind: "JsDocTagName" };
}
else {
// When completion is requested without "@", we will have check to make sure that
@@ -388,17 +402,19 @@ namespace ts.Completions {
// * |c|
// */
const lineStart = getLineStartPositionForPosition(position, sourceFile);
requestJsDocTag = !(sourceFile.text.substring(lineStart, position).match(/[^\*|\s|(/\*\*)]/));
if (!(sourceFile.text.substring(lineStart, position).match(/[^\*|\s|(/\*\*)]/))) {
request = { kind: "JsDocTag" };
}
}
}
// Completion should work inside certain JsDoc tags. For example:
// /** @type {number | string} */
// Completion should work in the brackets
const tag = getJsDocTagAtPosition(sourceFile, position);
const tag = getJsDocTagAtPosition(currentToken, position);
if (tag) {
if (tag.tagName.pos <= position && position <= tag.tagName.end) {
requestJsDocTagName = true;
request = { kind: "JsDocTagName" };
}
if (isTagWithTypeExpression(tag) && tag.typeExpression) {
currentToken = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ true);
@@ -410,10 +426,13 @@ namespace ts.Completions {
insideJsDocTagTypeExpression = isCurrentlyEditingNode(tag.typeExpression);
}
}
if (isJSDocParameterTag(tag) && (nodeIsMissing(tag.name) || tag.name.pos <= position && position <= tag.name.end)) {
request = { kind: "JsDocParameterName", tag };
}
}
if (requestJsDocTagName || requestJsDocTag) {
return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, requestJsDocTagName, requestJsDocTag, hasFilteredClassMemberKeywords: false };
if (request) {
return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, request, hasFilteredClassMemberKeywords: false };
}
if (!insideJsDocTagTypeExpression) {
@@ -494,7 +513,7 @@ namespace ts.Completions {
// It has a left-hand side, so we're not in an opening JSX tag.
break;
}
// falls through
// falls through
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.JsxElement:
@@ -550,7 +569,7 @@ namespace ts.Completions {
log("getCompletionData: Semantic work: " + (timestamp() - semanticStart));
return { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), requestJsDocTagName, requestJsDocTag, hasFilteredClassMemberKeywords };
return { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), request, hasFilteredClassMemberKeywords };
type JSDocTagWithTypeExpression = JSDocAugmentsTag | JSDocParameterTag | JSDocPropertyTag | JSDocReturnTag | JSDocTypeTag | JSDocTypedefTag;
@@ -923,7 +942,7 @@ namespace ts.Completions {
*
* @returns true if 'symbols' was successfully populated; false otherwise.
*/
function tryGetObjectLikeCompletionSymbols(objectLikeContainer: ObjectLiteralExpression | BindingPattern): boolean {
function tryGetObjectLikeCompletionSymbols(objectLikeContainer: ObjectLiteralExpression | ObjectBindingPattern): boolean {
// We're looking up possible property names from contextual/inferred/declared type.
isMemberCompletion = true;
@@ -939,41 +958,36 @@ namespace ts.Completions {
typeMembers = typeChecker.getAllPossiblePropertiesOfType(typeForObject);
existingMembers = (<ObjectLiteralExpression>objectLikeContainer).properties;
}
else if (objectLikeContainer.kind === SyntaxKind.ObjectBindingPattern) {
else {
Debug.assert(objectLikeContainer.kind === SyntaxKind.ObjectBindingPattern);
// We are *only* completing on properties from the type being destructured.
isNewIdentifierLocation = false;
const rootDeclaration = getRootDeclaration(objectLikeContainer.parent);
if (isVariableLike(rootDeclaration)) {
// We don't want to complete using the type acquired by the shape
// of the binding pattern; we are only interested in types acquired
// through type declaration or inference.
// Also proceed if rootDeclaration is a parameter and if its containing function expression/arrow function is contextually typed -
// type of parameter will flow in from the contextual type of the function
let canGetType = !!(rootDeclaration.initializer || rootDeclaration.type);
if (!canGetType && rootDeclaration.kind === SyntaxKind.Parameter) {
if (isExpression(rootDeclaration.parent)) {
canGetType = !!typeChecker.getContextualType(<Expression>rootDeclaration.parent);
}
else if (rootDeclaration.parent.kind === SyntaxKind.MethodDeclaration || rootDeclaration.parent.kind === SyntaxKind.SetAccessor) {
canGetType = isExpression(rootDeclaration.parent.parent) && !!typeChecker.getContextualType(<Expression>rootDeclaration.parent.parent);
}
if (!isVariableLike(rootDeclaration)) throw Debug.fail("Root declaration is not variable-like.");
// We don't want to complete using the type acquired by the shape
// of the binding pattern; we are only interested in types acquired
// through type declaration or inference.
// Also proceed if rootDeclaration is a parameter and if its containing function expression/arrow function is contextually typed -
// type of parameter will flow in from the contextual type of the function
let canGetType = rootDeclaration.initializer || rootDeclaration.type || rootDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement;
if (!canGetType && rootDeclaration.kind === SyntaxKind.Parameter) {
if (isExpression(rootDeclaration.parent)) {
canGetType = !!typeChecker.getContextualType(<Expression>rootDeclaration.parent);
}
if (canGetType) {
const typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer);
if (!typeForObject) return false;
// In a binding pattern, get only known properties. Everywhere else we will get all possible properties.
typeMembers = typeChecker.getPropertiesOfType(typeForObject);
existingMembers = (<ObjectBindingPattern>objectLikeContainer).elements;
else if (rootDeclaration.parent.kind === SyntaxKind.MethodDeclaration || rootDeclaration.parent.kind === SyntaxKind.SetAccessor) {
canGetType = isExpression(rootDeclaration.parent.parent) && !!typeChecker.getContextualType(<Expression>rootDeclaration.parent.parent);
}
}
else {
Debug.fail("Root declaration is not variable-like.");
if (canGetType) {
const typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer);
if (!typeForObject) return false;
// In a binding pattern, get only known properties. Everywhere else we will get all possible properties.
typeMembers = typeChecker.getPropertiesOfType(typeForObject);
existingMembers = (<ObjectBindingPattern>objectLikeContainer).elements;
}
}
else {
Debug.fail("Expected object literal or binding pattern, got " + objectLikeContainer.kind);
}
if (typeMembers && typeMembers.length > 0) {
// Add filtered items to the completion list
@@ -1082,14 +1096,14 @@ namespace ts.Completions {
* Returns the immediate owning object literal or binding pattern of a context token,
* on the condition that one exists and that the context implies completion should be given.
*/
function tryGetObjectLikeCompletionContainer(contextToken: Node): ObjectLiteralExpression | BindingPattern {
function tryGetObjectLikeCompletionContainer(contextToken: Node): ObjectLiteralExpression | ObjectBindingPattern {
if (contextToken) {
switch (contextToken.kind) {
case SyntaxKind.OpenBraceToken: // const x = { |
case SyntaxKind.CommaToken: // const x = { a: 0, |
const parent = contextToken.parent;
if (parent && (parent.kind === SyntaxKind.ObjectLiteralExpression || parent.kind === SyntaxKind.ObjectBindingPattern)) {
return <ObjectLiteralExpression | BindingPattern>parent;
if (isObjectLiteralExpression(parent) || isObjectBindingPattern(parent)) {
return parent;
}
break;
}
@@ -1148,7 +1162,7 @@ namespace ts.Completions {
default:
if (isFromClassElementDeclaration(contextToken) &&
(isClassMemberCompletionKeyword(contextToken.kind) ||
isClassMemberCompletionKeywordText(contextToken.getText()))) {
isClassMemberCompletionKeywordText(contextToken.getText()))) {
return contextToken.parent.parent as ClassLikeDeclaration;
}
}
@@ -1296,7 +1310,7 @@ namespace ts.Completions {
if (isFromClassElementDeclaration(contextToken)) {
return false;
}
// falls through
// falls through
case SyntaxKind.ClassKeyword:
case SyntaxKind.EnumKeyword:
case SyntaxKind.InterfaceKeyword:
@@ -1603,4 +1617,34 @@ namespace ts.Completions {
kind === SyntaxKind.EqualsEqualsEqualsToken ||
kind === SyntaxKind.ExclamationEqualsEqualsToken;
}
/** Get the corresponding JSDocTag node if the position is in a jsDoc comment */
function getJsDocTagAtPosition(node: Node, position: number): JSDocTag | undefined {
const { jsDoc } = getJsDocHavingNode(node);
if (!jsDoc) return undefined;
for (const { pos, end, tags } of jsDoc) {
if (!tags || position < pos || position > end) continue;
for (let i = tags.length - 1; i >= 0; i--) {
const tag = tags[i];
if (position >= tag.pos) {
return tag;
}
}
}
}
function getJsDocHavingNode(node: Node): Node {
if (!isToken(node)) return node;
switch (node.kind) {
case SyntaxKind.VarKeyword:
case SyntaxKind.LetKeyword:
case SyntaxKind.ConstKeyword:
// if the current token is var, let or const, skip the VariableDeclarationList
return node.parent.parent;
default:
return node.parent;
}
}
}
+12 -6
View File
@@ -1,17 +1,23 @@
/* @internal */
namespace ts.DocumentHighlights {
export function getDocumentHighlights(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, position: number, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] {
export function getDocumentHighlights(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, position: number, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] | undefined {
const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ true);
return node && (getSemanticDocumentHighlights(node, program, cancellationToken, sourceFilesToSearch) || getSyntacticDocumentHighlights(node, sourceFile));
if (!node) return undefined;
if (isJsxOpeningElement(node.parent) && node.parent.tagName === node || isJsxClosingElement(node.parent)) {
// For a JSX element, just highlight the matching tag, not all references.
const { openingElement, closingElement } = node.parent.parent;
const highlightSpans = [openingElement, closingElement].map(({ tagName }) => getHighlightSpanForNode(tagName, sourceFile));
return [{ fileName: sourceFile.fileName, highlightSpans }];
}
return getSemanticDocumentHighlights(node, program, cancellationToken, sourceFilesToSearch) || getSyntacticDocumentHighlights(node, sourceFile);
}
function getHighlightSpanForNode(node: Node, sourceFile: SourceFile): HighlightSpan {
const start = node.getStart(sourceFile);
const end = node.getEnd();
return {
fileName: sourceFile.fileName,
textSpan: createTextSpanFromBounds(start, end),
textSpan: createTextSpanFromNode(node, sourceFile),
kind: HighlightSpanKind.none
};
}
+11 -15
View File
@@ -185,7 +185,8 @@ namespace ts.FindAllReferences {
if (entry.type === "node") {
const { node } = entry;
return { textSpan: getTextSpan(node), fileName: node.getSourceFile().fileName, ...implementationKindDisplayParts(node, checker) };
} else {
}
else {
const { textSpan, fileName } = entry;
return { textSpan, fileName, kind: ScriptElementKind.unknown, displayParts: [] };
}
@@ -495,11 +496,10 @@ namespace ts.FindAllReferences.Core {
const { text = stripQuotes(getDeclaredName(this.checker, symbol, location)), allSearchSymbols = undefined } = searchOptions;
const escapedText = escapeIdentifier(text);
const parents = this.options.implementations && getParentSymbolsOfPropertyAccess(location, symbol, this.checker);
return { location, symbol, comingFrom, text, escapedText, parents, includes };
function includes(referenceSymbol: Symbol): boolean {
return allSearchSymbols ? contains(allSearchSymbols, referenceSymbol) : referenceSymbol === symbol;
}
return {
location, symbol, comingFrom, text, escapedText, parents,
includes: referenceSymbol => allSearchSymbols ? contains(allSearchSymbols, referenceSymbol) : referenceSymbol === symbol,
};
}
private readonly symbolIdToReferences: Entry[][] = [];
@@ -678,9 +678,7 @@ namespace ts.FindAllReferences.Core {
return parent ? scope.getSourceFile() : scope;
}
function getPossibleSymbolReferencePositions(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile, fullStart = false): number[] {
const start = fullStart ? container.getFullStart() : container.getStart(sourceFile);
const end = container.getEnd();
function getPossibleSymbolReferencePositions(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile): number[] {
const positions: number[] = [];
/// TODO: Cache symbol existence for files to save text search
@@ -695,10 +693,10 @@ namespace ts.FindAllReferences.Core {
const sourceLength = text.length;
const symbolNameLength = symbolName.length;
let position = text.indexOf(symbolName, start);
let position = text.indexOf(symbolName, container.pos);
while (position >= 0) {
// If we are past the end, stop looking
if (position > end) break;
if (position > container.end) break;
// We found a match. Make sure it's not part of a larger word (i.e. the char
// before and after it have to be a non-identifier char).
@@ -759,8 +757,7 @@ namespace ts.FindAllReferences.Core {
}
function addReferencesForKeywordInFile(sourceFile: SourceFile, kind: SyntaxKind, searchText: string, references: Push<NodeEntry>): void {
// Want fullStart so we can find the symbol in JSDoc comments
const possiblePositions = getPossibleSymbolReferencePositions(sourceFile, searchText, sourceFile, /*fullStart*/ true);
const possiblePositions = getPossibleSymbolReferencePositions(sourceFile, searchText, sourceFile);
for (const position of possiblePositions) {
const referenceLocation = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
if (referenceLocation.kind === kind) {
@@ -784,8 +781,7 @@ namespace ts.FindAllReferences.Core {
return;
}
const fullStart = state.options.findInComments || container.jsDoc !== undefined || forEach(search.symbol.declarations, d => d.kind === ts.SyntaxKind.JSDocTypedefTag);
for (const position of getPossibleSymbolReferencePositions(sourceFile, search.text, container, fullStart)) {
for (const position of getPossibleSymbolReferencePositions(sourceFile, search.text, container)) {
getReferencesAtLocation(sourceFile, position, search, state);
}
}
+127 -91
View File
@@ -73,54 +73,56 @@ namespace ts.FindAllReferences {
function handleDirectImports(exportingModuleSymbol: Symbol): void {
const theseDirectImports = getDirectImports(exportingModuleSymbol);
if (theseDirectImports) for (const direct of theseDirectImports) {
if (!markSeenDirectImport(direct)) {
continue;
}
if (theseDirectImports) {
for (const direct of theseDirectImports) {
if (!markSeenDirectImport(direct)) {
continue;
}
cancellationToken.throwIfCancellationRequested();
cancellationToken.throwIfCancellationRequested();
switch (direct.kind) {
case SyntaxKind.CallExpression:
if (!isAvailableThroughGlobal) {
const parent = direct.parent!;
if (exportKind === ExportKind.ExportEquals && parent.kind === SyntaxKind.VariableDeclaration) {
const { name } = parent as ts.VariableDeclaration;
if (name.kind === SyntaxKind.Identifier) {
directImports.push(name);
break;
switch (direct.kind) {
case SyntaxKind.CallExpression:
if (!isAvailableThroughGlobal) {
const parent = direct.parent!;
if (exportKind === ExportKind.ExportEquals && parent.kind === SyntaxKind.VariableDeclaration) {
const { name } = parent as ts.VariableDeclaration;
if (name.kind === SyntaxKind.Identifier) {
directImports.push(name);
break;
}
}
// Don't support re-exporting 'require()' calls, so just add a single indirect user.
addIndirectUser(direct.getSourceFile());
}
break;
// Don't support re-exporting 'require()' calls, so just add a single indirect user.
addIndirectUser(direct.getSourceFile());
}
break;
case SyntaxKind.ImportEqualsDeclaration:
handleNamespaceImport(direct, direct.name, hasModifier(direct, ModifierFlags.Export));
break;
case SyntaxKind.ImportEqualsDeclaration:
handleNamespaceImport(direct, direct.name, hasModifier(direct, ModifierFlags.Export));
break;
case SyntaxKind.ImportDeclaration:
const namedBindings = direct.importClause && direct.importClause.namedBindings;
if (namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport) {
handleNamespaceImport(direct, namedBindings.name);
}
else {
directImports.push(direct);
}
break;
case SyntaxKind.ImportDeclaration:
const namedBindings = direct.importClause && direct.importClause.namedBindings;
if (namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport) {
handleNamespaceImport(direct, namedBindings.name);
}
else {
directImports.push(direct);
}
break;
case SyntaxKind.ExportDeclaration:
if (!direct.exportClause) {
// This is `export * from "foo"`, so imports of this module may import the export too.
handleDirectImports(getContainingModuleSymbol(direct, checker));
}
else {
// This is `export { foo } from "foo"` and creates an alias symbol, so recursive search will get handle re-exports.
directImports.push(direct);
}
break;
case SyntaxKind.ExportDeclaration:
if (!direct.exportClause) {
// This is `export * from "foo"`, so imports of this module may import the export too.
handleDirectImports(getContainingModuleSymbol(direct, checker));
}
else {
// This is `export { foo } from "foo"` and creates an alias symbol, so recursive search will get handle re-exports.
directImports.push(direct);
}
break;
}
}
}
}
@@ -160,8 +162,10 @@ namespace ts.FindAllReferences {
const moduleSymbol = checker.getMergedSymbol(sourceFileLike.symbol);
Debug.assert(!!(moduleSymbol.flags & SymbolFlags.Module));
const directImports = getDirectImports(moduleSymbol);
if (directImports) for (const directImport of directImports) {
addIndirectUsers(getSourceFileLikeForImportDeclaration(directImport));
if (directImports) {
for (const directImport of directImports) {
addIndirectUsers(getSourceFileLikeForImportDeclaration(directImport));
}
}
}
@@ -183,8 +187,10 @@ namespace ts.FindAllReferences {
importSearches.push([location, symbol]);
}
if (directImports) for (const decl of directImports) {
handleImport(decl);
if (directImports) {
for (const decl of directImports) {
handleImport(decl);
}
}
return { importSearches, singleReferences };
@@ -258,25 +264,27 @@ namespace ts.FindAllReferences {
}
function searchForNamedImport(namedBindings: NamedImportsOrExports | undefined): void {
if (namedBindings) for (const element of namedBindings.elements) {
const { name, propertyName } = element;
if ((propertyName || name).text !== exportName) {
continue;
}
if (namedBindings) {
for (const element of namedBindings.elements) {
const { name, propertyName } = element;
if ((propertyName || name).text !== exportName) {
continue;
}
if (propertyName) {
// This is `import { foo as bar } from "./a"` or `export { foo as bar } from "./a"`. `foo` isn't a local in the file, so just add it as a single reference.
singleReferences.push(propertyName);
if (!isForRename) { // If renaming `foo`, don't touch `bar`, just `foo`.
// Search locally for `bar`.
addSearch(name, checker.getSymbolAtLocation(name));
if (propertyName) {
// This is `import { foo as bar } from "./a"` or `export { foo as bar } from "./a"`. `foo` isn't a local in the file, so just add it as a single reference.
singleReferences.push(propertyName);
if (!isForRename) { // If renaming `foo`, don't touch `bar`, just `foo`.
// Search locally for `bar`.
addSearch(name, checker.getSymbolAtLocation(name));
}
}
else {
const localSymbol = element.kind === SyntaxKind.ExportSpecifier && element.propertyName
? checker.getExportSpecifierLocalTargetSymbol(element) // For re-exporting under a different name, we want to get the re-exported symbol.
: checker.getSymbolAtLocation(name);
addSearch(name, localSymbol);
}
}
else {
const localSymbol = element.kind === SyntaxKind.ExportSpecifier && element.propertyName
? checker.getExportSpecifierLocalTargetSymbol(element) // For re-exporting under a different name, we want to get the re-exported symbol.
: checker.getSymbolAtLocation(name);
addSearch(name, localSymbol);
}
}
}
@@ -436,8 +444,8 @@ namespace ts.FindAllReferences {
if (parent.kind === SyntaxKind.PropertyAccessExpression) {
// When accessing an export of a JS module, there's no alias. The symbol will still be flagged as an export even though we're at the use.
// So check that we are at the declaration.
return symbol.declarations.some(d => d === parent) && parent.parent.kind === ts.SyntaxKind.BinaryExpression
? getSpecialPropertyExport(parent.parent as ts.BinaryExpression, /*useLhsSymbol*/ false)
return symbol.declarations.some(d => d === parent) && isBinaryExpression(parent.parent)
? getSpecialPropertyExport(parent.parent, /*useLhsSymbol*/ false)
: undefined;
}
else {
@@ -449,31 +457,41 @@ namespace ts.FindAllReferences {
else {
const exportNode = getExportNode(parent);
if (exportNode && hasModifier(exportNode, ModifierFlags.Export)) {
if (exportNode.kind === SyntaxKind.ImportEqualsDeclaration && (exportNode as ImportEqualsDeclaration).moduleReference === node) {
if (isImportEqualsDeclaration(exportNode) && exportNode.moduleReference === node) {
// We're at `Y` in `export import X = Y`. This is not the exported symbol, the left-hand-side is. So treat this as an import statement.
if (comingFromExport) {
return undefined;
}
const lhsSymbol = checker.getSymbolAtLocation((exportNode as ImportEqualsDeclaration).name);
const lhsSymbol = checker.getSymbolAtLocation(exportNode.name);
return { kind: ImportExport.Import, symbol: lhsSymbol, isNamedImport: false };
}
else {
return exportInfo(symbol, getExportKindForDeclaration(exportNode));
}
}
else if (parent.kind === SyntaxKind.ExportAssignment) {
// Get the symbol for the `export =` node; its parent is the module it's the export of.
const exportingModuleSymbol = parent.symbol.parent;
Debug.assert(!!exportingModuleSymbol);
return { kind: ImportExport.Export, symbol, exportInfo: { exportingModuleSymbol, exportKind: ExportKind.ExportEquals } };
// If we are in `export = a;`, `parent` is the export assignment.
else if (isExportAssignment(parent)) {
return getExportAssignmentExport(parent);
}
else if (parent.kind === ts.SyntaxKind.BinaryExpression) {
return getSpecialPropertyExport(parent as ts.BinaryExpression, /*useLhsSymbol*/ true);
// If we are in `export = class A {};` at `A`, `parent.parent` is the export assignment.
else if (isExportAssignment(parent.parent)) {
return getExportAssignmentExport(parent.parent);
}
else if (parent.parent.kind === SyntaxKind.BinaryExpression) {
return getSpecialPropertyExport(parent.parent as ts.BinaryExpression, /*useLhsSymbol*/ true);
// Similar for `module.exports =` and `exports.A =`.
else if (isBinaryExpression(parent)) {
return getSpecialPropertyExport(parent, /*useLhsSymbol*/ true);
}
else if (isBinaryExpression(parent.parent)) {
return getSpecialPropertyExport(parent.parent, /*useLhsSymbol*/ true);
}
}
function getExportAssignmentExport(ex: ExportAssignment): ExportedSymbol {
// Get the symbol for the `export =` node; its parent is the module it's the export of.
const exportingModuleSymbol = ex.symbol.parent;
Debug.assert(!!exportingModuleSymbol);
return { kind: ImportExport.Export, symbol, exportInfo: { exportingModuleSymbol, exportKind: ExportKind.ExportEquals } };
}
function getSpecialPropertyExport(node: ts.BinaryExpression, useLhsSymbol: boolean): ExportedSymbol | undefined {
@@ -496,21 +514,21 @@ namespace ts.FindAllReferences {
function getImport(): ImportedSymbol | undefined {
const isImport = isNodeImport(node);
if (!isImport) return;
if (!isImport) return undefined;
// A symbol being imported is always an alias. So get what that aliases to find the local symbol.
let importedSymbol = checker.getImmediateAliasedSymbol(symbol);
if (importedSymbol) {
// Search on the local symbol in the exporting module, not the exported symbol.
importedSymbol = skipExportSpecifierSymbol(importedSymbol, checker);
// Similarly, skip past the symbol for 'export ='
if (importedSymbol.name === "export=") {
importedSymbol = checker.getImmediateAliasedSymbol(importedSymbol);
}
if (!importedSymbol) return undefined;
if (symbolName(importedSymbol) === symbol.name) { // If this is a rename import, do not continue searching.
return { kind: ImportExport.Import, symbol: importedSymbol, ...isImport };
}
// Search on the local symbol in the exporting module, not the exported symbol.
importedSymbol = skipExportSpecifierSymbol(importedSymbol, checker);
// Similarly, skip past the symbol for 'export ='
if (importedSymbol.name === "export=") {
importedSymbol = getExportEqualsLocalSymbol(importedSymbol, checker);
}
if (symbolName(importedSymbol) === symbol.name) { // If this is a rename import, do not continue searching.
return { kind: ImportExport.Import, symbol: importedSymbol, ...isImport };
}
}
@@ -525,12 +543,29 @@ namespace ts.FindAllReferences {
}
}
function getExportEqualsLocalSymbol(importedSymbol: Symbol, checker: TypeChecker): Symbol {
if (importedSymbol.flags & SymbolFlags.Alias) {
return checker.getImmediateAliasedSymbol(importedSymbol);
}
const decl = importedSymbol.valueDeclaration;
if (isExportAssignment(decl)) { // `export = class {}`
return decl.expression.symbol;
}
else if (isBinaryExpression(decl)) { // `module.exports = class {}`
return decl.right.symbol;
}
Debug.fail();
}
// If a reference is a class expression, the exported node would be its parent.
// If a reference is a variable declaration, the exported node would be the variable statement.
function getExportNode(parent: Node): Node | undefined {
if (parent.kind === SyntaxKind.VariableDeclaration) {
const p = parent as ts.VariableDeclaration;
return p.parent.kind === ts.SyntaxKind.CatchClause ? undefined : p.parent.parent.kind === SyntaxKind.VariableStatement ? p.parent.parent : undefined;
} else {
}
else {
return parent;
}
}
@@ -577,12 +612,13 @@ namespace ts.FindAllReferences {
/** If at an export specifier, go to the symbol it refers to. */
function skipExportSpecifierSymbol(symbol: Symbol, checker: TypeChecker): Symbol {
// For `export { foo } from './bar", there's nothing to skip, because it does not create a new alias. But `export { foo } does.
if (symbol.declarations) for (const declaration of symbol.declarations) {
if (isExportSpecifier(declaration) && !(declaration as ExportSpecifier).propertyName && !(declaration as ExportSpecifier).parent.parent.moduleSpecifier) {
return checker.getExportSpecifierLocalTargetSymbol(declaration);
if (symbol.declarations) {
for (const declaration of symbol.declarations) {
if (isExportSpecifier(declaration) && !(declaration as ExportSpecifier).propertyName && !(declaration as ExportSpecifier).parent.parent.moduleSpecifier) {
return checker.getExportSpecifierLocalTargetSymbol(declaration);
}
}
}
return symbol;
}
+19
View File
@@ -132,6 +132,25 @@ namespace ts.JsDoc {
}));
}
export function getJSDocParameterNameCompletions(tag: JSDocParameterTag): CompletionEntry[] {
const nameThusFar = tag.name.text;
const jsdoc = tag.parent;
const fn = jsdoc.parent;
if (!ts.isFunctionLike(fn)) return [];
return mapDefined(fn.parameters, param => {
if (!isIdentifier(param.name)) return undefined;
const name = param.name.text;
if (jsdoc.tags.some(t => t !== tag && isJSDocParameterTag(t) && t.name.text === name)
|| nameThusFar !== undefined && !startsWith(name, nameThusFar)) {
return undefined;
}
return { name, kind: ScriptElementKind.parameterElement, kindModifiers: "", sortText: "0" };
});
}
/**
* Checks if position points to a valid position to add JSDoc comments, and if so,
* returns the appropriate template. Otherwise returns an empty string.
+2 -2
View File
@@ -143,7 +143,7 @@ namespace ts.JsTyping {
/**
* Merge a given list of typingNames to the inferredTypings map
*/
function mergeTypings(typingNames: string[]) {
function mergeTypings(typingNames: ReadonlyArray<string>) {
if (!typingNames) {
return;
}
@@ -192,7 +192,7 @@ namespace ts.JsTyping {
const cleanedTypingNames = map(inferredTypingNames, f => f.replace(/((?:\.|-)min(?=\.|$))|((?:-|\.)\d+)/g, ""));
if (safeList !== EmptySafeList) {
mergeTypings(filter(cleanedTypingNames, f => safeList.has(f)));
mergeTypings(ts.mapDefined(cleanedTypingNames, f => safeList.get(f)));
}
const hasJsxFile = forEach(fileNames, f => ensureScriptKind(f, getScriptKindFromFileName(f)) === ScriptKind.JSX);
+1 -1
View File
@@ -10,7 +10,7 @@ namespace ts.NavigateTo {
for (const sourceFile of sourceFiles) {
cancellationToken.throwIfCancellationRequested();
if (excludeDtsFiles && fileExtensionIs(sourceFile.fileName, ".d.ts")) {
if (excludeDtsFiles && fileExtensionIs(sourceFile.fileName, Extension.Dts)) {
continue;
}
+11 -3
View File
@@ -95,9 +95,16 @@ namespace ts {
function tryConsumeImport(): boolean {
let token = scanner.getToken();
if (token === SyntaxKind.ImportKeyword) {
token = nextToken();
if (token === SyntaxKind.StringLiteral) {
if (token === SyntaxKind.OpenParenToken) {
token = nextToken();
if (token === SyntaxKind.StringLiteral) {
// import("mod");
recordModuleName();
return true;
}
}
else if (token === SyntaxKind.StringLiteral) {
// import "mod";
recordModuleName();
return true;
@@ -297,7 +304,8 @@ namespace ts {
// import * as NS from "mod"
// import d, {a, b as B} from "mod"
// import i = require("mod");
//
// import("mod");
// export * from "mod"
// export {a as b} from "mod"
// export import i = require("mod")
+8 -18
View File
@@ -8,10 +8,10 @@ namespace ts {
description: string;
/** Compute the associated code actions */
getCodeActions(context: RefactorContext): CodeAction[];
getEditsForAction(context: RefactorContext, actionName: string): RefactorEditInfo | undefined;
/** A fast syntactic check to see if the refactor is applicable at given position. */
isApplicable(context: RefactorContext): boolean;
/** Compute (quickly) which actions are available here */
getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined;
}
export interface RefactorContext {
@@ -34,7 +34,6 @@ namespace ts {
}
export function getApplicableRefactors(context: RefactorContext): ApplicableRefactorInfo[] | undefined {
let results: ApplicableRefactorInfo[];
const refactorList: Refactor[] = [];
refactors.forEach(refactor => {
@@ -44,26 +43,17 @@ namespace ts {
if (context.cancellationToken && context.cancellationToken.isCancellationRequested()) {
return results;
}
if (refactor.isApplicable(context)) {
(results || (results = [])).push({ name: refactor.name, description: refactor.description });
const infos = refactor.getAvailableActions(context);
if (infos && infos.length) {
(results || (results = [])).push(...infos);
}
}
return results;
}
export function getRefactorCodeActions(context: RefactorContext, refactorName: string): CodeAction[] | undefined {
let result: CodeAction[];
export function getEditsForRefactor(context: RefactorContext, refactorName: string, actionName: string): RefactorEditInfo | undefined {
const refactor = refactors.get(refactorName);
if (!refactor) {
return undefined;
}
const codeActions = refactor.getCodeActions(context);
if (codeActions) {
addRange((result || (result = [])), codeActions);
}
return result;
return refactor && refactor.getEditsForAction(context, actionName);
}
}
}
@@ -1,16 +1,18 @@
/* @internal */
namespace ts.refactor {
const actionName = "convert";
const convertFunctionToES6Class: Refactor = {
name: "Convert to ES2015 class",
description: Diagnostics.Convert_function_to_an_ES2015_class.message,
getCodeActions,
isApplicable
getEditsForAction,
getAvailableActions
};
registerRefactor(convertFunctionToES6Class);
function isApplicable(context: RefactorContext): boolean {
function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] {
const start = context.startPosition;
const node = getTokenAtPosition(context.file, start, /*includeJsDocComment*/ false);
const checker = context.program.getTypeChecker();
@@ -20,10 +22,28 @@ namespace ts.refactor {
symbol = (symbol.valueDeclaration as VariableDeclaration).initializer.symbol;
}
return symbol && symbol.flags & SymbolFlags.Function && symbol.members && symbol.members.size > 0;
if (symbol && (symbol.flags & SymbolFlags.Function) && symbol.members && (symbol.members.size > 0)) {
return [
{
name: convertFunctionToES6Class.name,
description: convertFunctionToES6Class.description,
actions: [
{
description: convertFunctionToES6Class.description,
name: actionName
}
]
}
];
}
}
function getCodeActions(context: RefactorContext): CodeAction[] | undefined {
function getEditsForAction(context: RefactorContext, action: string): RefactorEditInfo | undefined {
// Somehow wrong action got invoked?
if (actionName !== action) {
return undefined;
}
const start = context.startPosition;
const sourceFile = context.file;
const checker = context.program.getTypeChecker();
@@ -35,7 +55,7 @@ namespace ts.refactor {
const deletes: (() => any)[] = [];
if (!(ctorSymbol.flags & (SymbolFlags.Function | SymbolFlags.Variable))) {
return [];
return undefined;
}
const ctorDeclaration = ctorSymbol.valueDeclaration;
@@ -63,7 +83,7 @@ namespace ts.refactor {
}
if (!newClassDeclaration) {
return [];
return undefined;
}
// Because the preceding node could be touched, we need to insert nodes before delete nodes.
@@ -72,10 +92,9 @@ namespace ts.refactor {
deleteCallback();
}
return [{
description: formatStringFromArgs(Diagnostics.Convert_function_0_to_class.message, [ctorSymbol.name]),
changes: changeTracker.getChanges()
}];
return {
edits: changeTracker.getChanges()
};
function deleteNode(node: Node, inList = false) {
if (deletedNodes.some(n => isNodeDescendantOf(node, n))) {
+59 -50
View File
@@ -37,7 +37,7 @@ namespace ts {
let ruleProvider: formatting.RulesProvider;
function createNode<TKind extends SyntaxKind>(kind: TKind, pos: number, end: number, parent?: Node): NodeObject | TokenObject<TKind> | IdentifierObject {
const node = kind >= SyntaxKind.FirstNode ? new NodeObject(kind, pos, end) :
const node = isNodeKind(kind) ? new NodeObject(kind, pos, end) :
kind === SyntaxKind.Identifier ? new IdentifierObject(SyntaxKind.Identifier, pos, end) :
new TokenObject(kind, pos, end);
node.parent = parent;
@@ -103,10 +103,10 @@ namespace ts {
return sourceFile.text.substring(this.getStart(sourceFile), this.getEnd());
}
private addSyntheticNodes(nodes: Node[], pos: number, end: number, useJSDocScanner?: boolean): number {
private addSyntheticNodes(nodes: Node[], pos: number, end: number): number {
scanner.setTextPos(pos);
while (pos < end) {
const token = useJSDocScanner ? scanner.scanJSDocToken() : scanner.scan();
const token = scanner.scan();
Debug.assert(token !== SyntaxKind.EndOfFileToken); // Else it would infinitely loop
const textPos = scanner.getTextPos();
if (textPos <= end) {
@@ -136,54 +136,50 @@ namespace ts {
}
private createChildren(sourceFile?: SourceFileLike) {
if (isJSDocTag(this)) {
if (!isNodeKind(this.kind)) {
this._children = emptyArray;
return;
}
if (isJSDocCommentContainingNode(this)) {
/** Don't add trivia for "tokens" since this is in a comment. */
const children: Node[] = [];
this.forEachChild(child => { children.push(child); });
this._children = children;
return;
}
else if (this.kind >= SyntaxKind.FirstNode) {
const children: Node[] = [];
scanner.setText((sourceFile || this.getSourceFile()).text);
let pos = this.pos;
const useJSDocScanner = this.kind >= SyntaxKind.FirstJSDocTagNode && this.kind <= SyntaxKind.LastJSDocTagNode;
const processNode = (node: Node) => {
const isJSDocTagNode = isJSDocTag(node);
if (!isJSDocTagNode && pos < node.pos) {
pos = this.addSyntheticNodes(children, pos, node.pos, useJSDocScanner);
}
children.push(node);
if (!isJSDocTagNode) {
pos = node.end;
}
};
const processNodes = (nodes: NodeArray<Node>) => {
if (pos < nodes.pos) {
pos = this.addSyntheticNodes(children, pos, nodes.pos, useJSDocScanner);
}
children.push(this.createSyntaxList(nodes));
pos = nodes.end;
};
// jsDocComments need to be the first children
if (this.jsDoc) {
for (const jsDocComment of this.jsDoc) {
processNode(jsDocComment);
}
const children: Node[] = [];
scanner.setText((sourceFile || this.getSourceFile()).text);
let pos = this.pos;
const processNode = (node: Node) => {
pos = this.addSyntheticNodes(children, pos, node.pos);
children.push(node);
pos = node.end;
};
const processNodes = (nodes: NodeArray<Node>) => {
if (pos < nodes.pos) {
pos = this.addSyntheticNodes(children, pos, nodes.pos);
}
// For syntactic classifications, all trivia are classcified together, including jsdoc comments.
// For that to work, the jsdoc comments should still be the leading trivia of the first child.
// Restoring the scanner position ensures that.
pos = this.pos;
forEachChild(this, processNode, processNodes);
if (pos < this.end) {
this.addSyntheticNodes(children, pos, this.end);
children.push(this.createSyntaxList(nodes));
pos = nodes.end;
};
// jsDocComments need to be the first children
if (this.jsDoc) {
for (const jsDocComment of this.jsDoc) {
processNode(jsDocComment);
}
scanner.setText(undefined);
this._children = children;
}
else {
this._children = emptyArray;
// For syntactic classifications, all trivia are classcified together, including jsdoc comments.
// For that to work, the jsdoc comments should still be the leading trivia of the first child.
// Restoring the scanner position ensures that.
pos = this.pos;
forEachChild(this, processNode, processNodes);
if (pos < this.end) {
this.addSyntheticNodes(children, pos, this.end);
}
scanner.setText(undefined);
this._children = children;
}
public getChildCount(sourceFile?: SourceFile): number {
@@ -368,7 +364,7 @@ namespace ts {
_primaryExpressionBrand: any;
_memberExpressionBrand: any;
_leftHandSideExpressionBrand: any;
_incrementExpressionBrand: any;
_updateExpressionBrand: any;
_unaryExpressionBrand: any;
_expressionBrand: any;
/*@internal*/typeArguments: NodeArray<TypeNode>;
@@ -521,6 +517,7 @@ namespace ts {
private namedDeclarations: Map<Declaration[]>;
public ambientModuleNames: string[];
public checkJsDirective: CheckJsDirective | undefined;
public possiblyContainDynamicImport: boolean;
constructor(kind: SyntaxKind, pos: number, end: number) {
super(kind, pos, end);
@@ -683,8 +680,9 @@ namespace ts {
forEachChild(decl.name, visit);
break;
}
if (decl.initializer)
if (decl.initializer) {
visit(decl.initializer);
}
}
// falls through
case SyntaxKind.EnumMember:
@@ -731,6 +729,15 @@ namespace ts {
}
}
class SourceMapSourceObject implements SourceMapSource {
lineMap: number[];
constructor (public fileName: string, public text: string, public skipTrivia?: (pos: number) => number) {}
public getLineAndCharacterOfPosition(pos: number): LineAndCharacter {
return ts.getLineAndCharacterOfPosition(this, pos);
}
}
function getServicesObjectAllocator(): ObjectAllocator {
return {
getNodeConstructor: () => NodeObject,
@@ -741,6 +748,7 @@ namespace ts {
getSymbolConstructor: () => SymbolObject,
getTypeConstructor: () => TypeObject,
getSignatureConstructor: () => SignatureObject,
getSourceMapSourceConstructor: () => SourceMapSourceObject,
};
}
@@ -1988,15 +1996,16 @@ namespace ts {
return refactor.getApplicableRefactors(getRefactorContext(file, positionOrRange));
}
function getRefactorCodeActions(
function getEditsForRefactor(
fileName: string,
formatOptions: FormatCodeSettings,
positionOrRange: number | TextRange,
refactorName: string): CodeAction[] | undefined {
refactorName: string,
actionName: string): RefactorEditInfo {
synchronizeHostData();
const file = getValidSourceFile(fileName);
return refactor.getRefactorCodeActions(getRefactorContext(file, positionOrRange, formatOptions), refactorName);
return refactor.getEditsForRefactor(getRefactorContext(file, positionOrRange, formatOptions), refactorName, actionName);
}
return {
@@ -2004,8 +2013,6 @@ namespace ts {
cleanupSemanticCache,
getSyntacticDiagnostics,
getSemanticDiagnostics,
getApplicableRefactors,
getRefactorCodeActions,
getCompilerOptionsDiagnostics,
getSyntacticClassifications,
getSemanticClassifications,
@@ -2043,7 +2050,9 @@ namespace ts {
getEmitOutput,
getNonBoundSourceFile,
getSourceFile,
getProgram
getProgram,
getApplicableRefactors,
getEditsForRefactor,
};
}
+3 -1
View File
@@ -4,8 +4,10 @@ namespace ts.SymbolDisplay {
export function getSymbolKind(typeChecker: TypeChecker, symbol: Symbol, location: Node): ScriptElementKind {
const { flags } = symbol;
if (flags & SymbolFlags.Class) return getDeclarationOfKind(symbol, SyntaxKind.ClassExpression) ?
if (flags & SymbolFlags.Class) {
return getDeclarationOfKind(symbol, SyntaxKind.ClassExpression) ?
ScriptElementKind.localClassElement : ScriptElementKind.classElement;
}
if (flags & SymbolFlags.Enum) return ScriptElementKind.enumElement;
if (flags & SymbolFlags.TypeAlias) return ScriptElementKind.typeElement;
if (flags & SymbolFlags.Interface) return ScriptElementKind.interfaceElement;
+55 -1
View File
@@ -71,6 +71,10 @@ namespace ts {
getLineAndCharacterOfPosition(pos: number): LineAndCharacter;
}
export interface SourceMapSource {
getLineAndCharacterOfPosition(pos: number): LineAndCharacter;
}
/**
* Represents an immutable snapshot of a script at a specified time.Once acquired, the
* snapshot is observably immutable. i.e. the same calls with the same parameters will return
@@ -261,8 +265,9 @@ namespace ts {
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: FormatCodeSettings): CodeAction[];
getApplicableRefactors(fileName: string, positionOrRaneg: number | TextRange): ApplicableRefactorInfo[];
getRefactorCodeActions(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string): CodeAction[] | undefined;
getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string): RefactorEditInfo | undefined;
getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean): EmitOutput;
@@ -353,11 +358,60 @@ namespace ts {
changes: FileTextChanges[];
}
/**
* A set of one or more available refactoring actions, grouped under a parent refactoring.
*/
export 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.
*/
export 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;
};
/**
* A set of edits to make in response to a refactor action, plus an optional
* location where renaming should be invoked from
*/
export type RefactorEditInfo = {
edits: FileTextChanges[];
renameFilename?: string;
renameLocation?: number;
};
export interface TextInsertion {
newText: string;
/** The position in newText the caret should point to after the insertion. */
+20 -49
View File
@@ -94,6 +94,10 @@ namespace ts {
else if (isNamespaceReference(node)) {
return SemanticMeaning.Namespace;
}
else if (isTypeParameterDeclaration(node.parent)) {
Debug.assert(isJSDocTemplateTag(node.parent.parent)); // Else would be handled by isDeclarationName
return SemanticMeaning.Type;
}
else {
return SemanticMeaning.Value;
}
@@ -615,18 +619,21 @@ namespace ts {
return getTouchingToken(sourceFile, position, includeJsDocComment, n => isPropertyName(n.kind));
}
/** Returns the token if position is in [start, end) or if position === end and includeItemAtEndPosition(token) === true */
export function getTouchingToken(sourceFile: SourceFile, position: number, includeJsDocComment: boolean, includeItemAtEndPosition?: (n: Node) => boolean): Node {
return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ false, includeItemAtEndPosition, includeJsDocComment);
/**
* Returns the token if position is in [start, end).
* If position === end, returns the preceding token if includeItemAtEndPosition(previousToken) === true
*/
export function getTouchingToken(sourceFile: SourceFile, position: number, includeJsDocComment: boolean, includePrecedingTokenAtEndPosition?: (n: Node) => boolean): Node {
return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ false, includePrecedingTokenAtEndPosition, /*includeEndPosition*/ false, includeJsDocComment);
}
/** Returns a token if position is in [start-of-leading-trivia, end) */
export function getTokenAtPosition(sourceFile: SourceFile, position: number, includeJsDocComment: boolean): Node {
return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includeItemAtEndPosition*/ undefined, includeJsDocComment);
export function getTokenAtPosition(sourceFile: SourceFile, position: number, includeJsDocComment: boolean, includeEndPosition?: boolean): Node {
return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includePrecedingTokenAtEndPosition*/ undefined, includeEndPosition, includeJsDocComment);
}
/** Get the token whose text contains the position */
function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includeItemAtEndPosition: (n: Node) => boolean, includeJsDocComment: boolean): Node {
function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includePrecedingTokenAtEndPosition: (n: Node) => boolean, includeEndPosition: boolean, includeJsDocComment: boolean): Node {
let current: Node = sourceFile;
outer: while (true) {
if (isToken(current)) {
@@ -636,7 +643,7 @@ namespace ts {
// find the child that contains 'position'
for (const child of current.getChildren()) {
if (isJSDocNode(child) && !includeJsDocComment) {
if (!includeJsDocComment && isJSDocNode(child)) {
continue;
}
@@ -646,13 +653,13 @@ namespace ts {
}
const end = child.getEnd();
if (position < end || (position === end && child.kind === SyntaxKind.EndOfFileToken)) {
if (position < end || (position === end && (child.kind === SyntaxKind.EndOfFileToken || includeEndPosition))) {
current = child;
continue outer;
}
else if (includeItemAtEndPosition && end === position) {
else if (includePrecedingTokenAtEndPosition && end === position) {
const previousToken = findPrecedingToken(position, sourceFile, child);
if (previousToken && includeItemAtEndPosition(previousToken)) {
if (previousToken && includePrecedingTokenAtEndPosition(previousToken)) {
return previousToken;
}
}
@@ -707,7 +714,7 @@ namespace ts {
}
}
export function findPrecedingToken(position: number, sourceFile: SourceFile, startNode?: Node, includeJsDocComment?: boolean): Node {
export function findPrecedingToken(position: number, sourceFile: SourceFile, startNode?: Node, includeJsDoc?: boolean): Node {
return find(startNode || sourceFile);
function findRightmostToken(n: Node): Node {
@@ -738,7 +745,7 @@ namespace ts {
// NOTE: JsxText is a weird kind of node that can contain only whitespaces (since they are not counted as trivia).
// if this is the case - then we should assume that token in question is located in previous child.
if (position < child.end && (nodeHasTokens(child) || child.kind === SyntaxKind.JsxText)) {
const start = child.getStart(sourceFile, includeJsDocComment);
const start = child.getStart(sourceFile, includeJsDoc);
const lookInPreviousChild =
(start >= position) || // cursor in the leading trivia
(child.kind === SyntaxKind.JsxText && start === child.end); // whitespace only JsxText
@@ -755,7 +762,7 @@ namespace ts {
}
}
Debug.assert(startNode !== undefined || n.kind === SyntaxKind.SourceFile);
Debug.assert(startNode !== undefined || n.kind === SyntaxKind.SourceFile || isJSDocCommentContainingNode(n));
// Here we know that none of child token nodes embrace the position,
// the only known case is when position is at the end of the file.
@@ -901,42 +908,6 @@ namespace ts {
}
}
/**
* Get the corresponding JSDocTag node if the position is in a jsDoc comment
*/
export function getJsDocTagAtPosition(sourceFile: SourceFile, position: number): JSDocTag {
let node = ts.getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false);
if (isToken(node)) {
switch (node.kind) {
case SyntaxKind.VarKeyword:
case SyntaxKind.LetKeyword:
case SyntaxKind.ConstKeyword:
// if the current token is var, let or const, skip the VariableDeclarationList
node = node.parent === undefined ? undefined : node.parent.parent;
break;
default:
node = node.parent;
break;
}
}
if (node) {
if (node.jsDoc) {
for (const jsDoc of node.jsDoc) {
if (jsDoc.tags) {
for (const tag of jsDoc.tags) {
if (tag.pos <= position && position <= tag.end) {
return tag;
}
}
}
}
}
}
return undefined;
}
function nodeHasTokens(n: Node): boolean {
// If we have a token or node that has a non-zero width, it must have tokens.
// Note, that getWidth() does not take trivia into account.
+2 -2
View File
@@ -25,11 +25,11 @@ class Board {
>allShipsSunk : Symbol(Board.allShipsSunk, Decl(2dArrays.ts, 9, 18))
return this.ships.every(function (val) { return val.isSunk; });
>this.ships.every : Symbol(Array.every, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>this.ships.every : Symbol(Array.every, Decl(lib.d.ts, --, --))
>this.ships : Symbol(Board.ships, Decl(2dArrays.ts, 7, 13))
>this : Symbol(Board, Decl(2dArrays.ts, 5, 1))
>ships : Symbol(Board.ships, Decl(2dArrays.ts, 7, 13))
>every : Symbol(Array.every, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>every : Symbol(Array.every, Decl(lib.d.ts, --, --))
>val : Symbol(val, Decl(2dArrays.ts, 12, 42))
>val.isSunk : Symbol(Ship.isSunk, Decl(2dArrays.ts, 3, 12))
>val : Symbol(val, Decl(2dArrays.ts, 12, 42))
+3 -3
View File
@@ -26,12 +26,12 @@ class Board {
return this.ships.every(function (val) { return val.isSunk; });
>this.ships.every(function (val) { return val.isSunk; }) : boolean
>this.ships.every : { (callbackfn: (this: void, value: Ship, index: number, array: Ship[]) => boolean): boolean; (callbackfn: (this: void, value: Ship, index: number, array: Ship[]) => boolean, thisArg: undefined): boolean; <Z>(callbackfn: (this: Z, value: Ship, index: number, array: Ship[]) => boolean, thisArg: Z): boolean; }
>this.ships.every : (callbackfn: (value: Ship, index: number, array: Ship[]) => boolean, thisArg?: any) => boolean
>this.ships : Ship[]
>this : this
>ships : Ship[]
>every : { (callbackfn: (this: void, value: Ship, index: number, array: Ship[]) => boolean): boolean; (callbackfn: (this: void, value: Ship, index: number, array: Ship[]) => boolean, thisArg: undefined): boolean; <Z>(callbackfn: (this: Z, value: Ship, index: number, array: Ship[]) => boolean, thisArg: Z): boolean; }
>function (val) { return val.isSunk; } : (this: void, val: Ship) => boolean
>every : (callbackfn: (value: Ship, index: number, array: Ship[]) => boolean, thisArg?: any) => boolean
>function (val) { return val.isSunk; } : (val: Ship) => boolean
>val : Ship
>val.isSunk : boolean
>val : Ship
@@ -11,7 +11,7 @@ declare var fs: {
existsSync(path: string): boolean;
readdirSync(path: string): string[];
readFileSync(filename: string, encoding?: string): string;
writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void;
writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; } | string): void;
watchFile(filename: string, options: { persistent?: boolean; interval?: number; }, listener: (curr: { mtime: Date }, prev: { mtime: Date }) => void): void;
};
declare var path: any;
@@ -40,6 +40,7 @@
"end": 27,
"text": "name1"
},
"isBracketed": false,
"comment": "Description"
},
"length": 1,
@@ -40,6 +40,7 @@
"end": 32,
"text": "name1"
},
"isBracketed": false,
"comment": "Description"
},
"length": 1,
@@ -40,6 +40,7 @@
"end": 29,
"text": "name1"
},
"isBracketed": false,
"comment": ""
},
"length": 1,
@@ -40,6 +40,7 @@
"end": 29,
"text": "name1"
},
"isBracketed": false,
"comment": "Description text follows"
},
"length": 1,
@@ -40,6 +40,7 @@
"end": 20,
"text": "name1"
},
"isBracketed": false,
"comment": ""
},
"length": 1,
@@ -40,6 +40,7 @@
"end": 20,
"text": "name1"
},
"isBracketed": false,
"comment": "Description"
},
"length": 1,
@@ -30,6 +30,7 @@
"end": 18,
"text": "foo"
},
"isBracketed": false,
"comment": ""
},
"length": 1,
@@ -40,6 +40,7 @@
"end": 29,
"text": "name1"
},
"isBracketed": false,
"comment": ""
},
"1": {
@@ -79,6 +80,7 @@
"end": 55,
"text": "name2"
},
"isBracketed": false,
"comment": ""
},
"length": 2,
@@ -40,6 +40,7 @@
"end": 29,
"text": "name1"
},
"isBracketed": false,
"comment": ""
},
"1": {
@@ -79,6 +80,7 @@
"end": 51,
"text": "name2"
},
"isBracketed": false,
"comment": ""
},
"length": 2,
@@ -103,7 +103,8 @@
"pos": 66,
"end": 69,
"text": "age"
}
},
"isBracketed": false
},
{
"kind": "JSDocPropertyTag",
@@ -141,7 +142,8 @@
"pos": 93,
"end": 97,
"text": "name"
}
},
"isBracketed": false
}
]
},
@@ -35,16 +35,16 @@ paired.reduce((b3, b4) => b3.concat({}), []);
>b3 : Symbol(b3, Decl(anyInferenceAnonymousFunctions.ts, 13, 15))
paired.map((c1) => c1.count);
>paired.map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>paired.map : Symbol(Array.map, Decl(lib.d.ts, --, --))
>paired : Symbol(paired, Decl(anyInferenceAnonymousFunctions.ts, 0, 3))
>map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>map : Symbol(Array.map, Decl(lib.d.ts, --, --))
>c1 : Symbol(c1, Decl(anyInferenceAnonymousFunctions.ts, 15, 12))
>c1 : Symbol(c1, Decl(anyInferenceAnonymousFunctions.ts, 15, 12))
paired.map(function (c2) { return c2.count; });
>paired.map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>paired.map : Symbol(Array.map, Decl(lib.d.ts, --, --))
>paired : Symbol(paired, Decl(anyInferenceAnonymousFunctions.ts, 0, 3))
>map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>map : Symbol(Array.map, Decl(lib.d.ts, --, --))
>c2 : Symbol(c2, Decl(anyInferenceAnonymousFunctions.ts, 16, 21))
>c2 : Symbol(c2, Decl(anyInferenceAnonymousFunctions.ts, 16, 21))
@@ -57,10 +57,10 @@ paired.reduce((b3, b4) => b3.concat({}), []);
paired.map((c1) => c1.count);
>paired.map((c1) => c1.count) : any[]
>paired.map : { <U>(this: [any, any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U, U, U]; <U>(this: [any, any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U, U, U]; <Z, U>(this: [any, any, any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U, U, U]; <U>(this: [any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U, U]; <U>(this: [any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U, U]; <Z, U>(this: [any, any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U, U]; <U>(this: [any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U]; <U>(this: [any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U]; <Z, U>(this: [any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U]; <U>(this: [any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U]; <U>(this: [any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U]; <Z, U>(this: [any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U]; <U>(callbackfn: (this: void, value: any, index: number, array: any[]) => U): U[]; <U>(callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): U[]; <Z, U>(callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): U[]; }
>paired.map : <U>(callbackfn: (value: any, index: number, array: any[]) => U, thisArg?: any) => U[]
>paired : any[]
>map : { <U>(this: [any, any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U, U, U]; <U>(this: [any, any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U, U, U]; <Z, U>(this: [any, any, any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U, U, U]; <U>(this: [any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U, U]; <U>(this: [any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U, U]; <Z, U>(this: [any, any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U, U]; <U>(this: [any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U]; <U>(this: [any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U]; <Z, U>(this: [any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U]; <U>(this: [any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U]; <U>(this: [any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U]; <Z, U>(this: [any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U]; <U>(callbackfn: (this: void, value: any, index: number, array: any[]) => U): U[]; <U>(callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): U[]; <Z, U>(callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): U[]; }
>(c1) => c1.count : (this: void, c1: any) => any
>map : <U>(callbackfn: (value: any, index: number, array: any[]) => U, thisArg?: any) => U[]
>(c1) => c1.count : (c1: any) => any
>c1 : any
>c1.count : any
>c1 : any
@@ -68,10 +68,10 @@ paired.map((c1) => c1.count);
paired.map(function (c2) { return c2.count; });
>paired.map(function (c2) { return c2.count; }) : any[]
>paired.map : { <U>(this: [any, any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U, U, U]; <U>(this: [any, any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U, U, U]; <Z, U>(this: [any, any, any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U, U, U]; <U>(this: [any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U, U]; <U>(this: [any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U, U]; <Z, U>(this: [any, any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U, U]; <U>(this: [any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U]; <U>(this: [any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U]; <Z, U>(this: [any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U]; <U>(this: [any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U]; <U>(this: [any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U]; <Z, U>(this: [any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U]; <U>(callbackfn: (this: void, value: any, index: number, array: any[]) => U): U[]; <U>(callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): U[]; <Z, U>(callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): U[]; }
>paired.map : <U>(callbackfn: (value: any, index: number, array: any[]) => U, thisArg?: any) => U[]
>paired : any[]
>map : { <U>(this: [any, any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U, U, U]; <U>(this: [any, any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U, U, U]; <Z, U>(this: [any, any, any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U, U, U]; <U>(this: [any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U, U]; <U>(this: [any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U, U]; <Z, U>(this: [any, any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U, U]; <U>(this: [any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U]; <U>(this: [any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U]; <Z, U>(this: [any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U]; <U>(this: [any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U]; <U>(this: [any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U]; <Z, U>(this: [any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U]; <U>(callbackfn: (this: void, value: any, index: number, array: any[]) => U): U[]; <U>(callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): U[]; <Z, U>(callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): U[]; }
>function (c2) { return c2.count; } : (this: void, c2: any) => any
>map : <U>(callbackfn: (value: any, index: number, array: any[]) => U, thisArg?: any) => U[]
>function (c2) { return c2.count; } : (c2: any) => any
>c2 : any
>c2.count : any
>c2 : any
@@ -34,8 +34,8 @@ function myFunction(myType: MyType) {
>x : Symbol(x, Decl(argumentsAsPropertyName.ts, 11, 13))
[1, 2, 3].forEach(function(j) { use(x); })
>[1, 2, 3].forEach : Symbol(Array.forEach, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>forEach : Symbol(Array.forEach, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>[1, 2, 3].forEach : Symbol(Array.forEach, Decl(lib.d.ts, --, --))
>forEach : Symbol(Array.forEach, Decl(lib.d.ts, --, --))
>j : Symbol(j, Decl(argumentsAsPropertyName.ts, 12, 35))
>use : Symbol(use, Decl(argumentsAsPropertyName.ts, 3, 1))
>x : Symbol(x, Decl(argumentsAsPropertyName.ts, 11, 13))
@@ -42,13 +42,13 @@ function myFunction(myType: MyType) {
[1, 2, 3].forEach(function(j) { use(x); })
>[1, 2, 3].forEach(function(j) { use(x); }) : void
>[1, 2, 3].forEach : { (callbackfn: (this: void, value: number, index: number, array: number[]) => void): void; (callbackfn: (this: void, value: number, index: number, array: number[]) => void, thisArg: undefined): void; <Z>(callbackfn: (this: Z, value: number, index: number, array: number[]) => void, thisArg: Z): void; }
>[1, 2, 3].forEach : (callbackfn: (value: number, index: number, array: number[]) => void, thisArg?: any) => void
>[1, 2, 3] : number[]
>1 : 1
>2 : 2
>3 : 3
>forEach : { (callbackfn: (this: void, value: number, index: number, array: number[]) => void): void; (callbackfn: (this: void, value: number, index: number, array: number[]) => void, thisArg: undefined): void; <Z>(callbackfn: (this: Z, value: number, index: number, array: number[]) => void, thisArg: Z): void; }
>function(j) { use(x); } : (this: void, j: number) => void
>forEach : (callbackfn: (value: number, index: number, array: number[]) => void, thisArg?: any) => void
>function(j) { use(x); } : (j: number) => void
>j : number
>use(x) : any
>use : (s: any) => any
@@ -0,0 +1,44 @@
=== tests/cases/compiler/main.js ===
function allRest() { arguments; }
>allRest : Symbol(allRest, Decl(main.js, 0, 0))
>arguments : Symbol(arguments)
allRest();
>allRest : Symbol(allRest, Decl(main.js, 0, 0))
allRest(1, 2, 3);
>allRest : Symbol(allRest, Decl(main.js, 0, 0))
function someRest(x, y) { arguments; }
>someRest : Symbol(someRest, Decl(main.js, 2, 17))
>x : Symbol(x, Decl(main.js, 3, 18))
>y : Symbol(y, Decl(main.js, 3, 20))
>arguments : Symbol(arguments)
someRest(); // x and y are still optional because they are in a JS file
>someRest : Symbol(someRest, Decl(main.js, 2, 17))
someRest(1, 2, 3);
>someRest : Symbol(someRest, Decl(main.js, 2, 17))
/**
* @param {number} x - a thing
*/
function jsdocced(x) { arguments; }
>jsdocced : Symbol(jsdocced, Decl(main.js, 5, 18))
>x : Symbol(x, Decl(main.js, 10, 18))
>arguments : Symbol(arguments)
jsdocced(1);
>jsdocced : Symbol(jsdocced, Decl(main.js, 5, 18))
function dontDoubleRest(x, ...y) { arguments; }
>dontDoubleRest : Symbol(dontDoubleRest, Decl(main.js, 11, 12))
>x : Symbol(x, Decl(main.js, 13, 24))
>y : Symbol(y, Decl(main.js, 13, 26))
>arguments : Symbol(arguments)
dontDoubleRest(1, 2, 3);
>dontDoubleRest : Symbol(dontDoubleRest, Decl(main.js, 11, 12))
@@ -0,0 +1,60 @@
=== tests/cases/compiler/main.js ===
function allRest() { arguments; }
>allRest : (...args: any[]) => void
>arguments : IArguments
allRest();
>allRest() : void
>allRest : (...args: any[]) => void
allRest(1, 2, 3);
>allRest(1, 2, 3) : void
>allRest : (...args: any[]) => void
>1 : 1
>2 : 2
>3 : 3
function someRest(x, y) { arguments; }
>someRest : (x: any, y: any, ...args: any[]) => void
>x : any
>y : any
>arguments : IArguments
someRest(); // x and y are still optional because they are in a JS file
>someRest() : void
>someRest : (x: any, y: any, ...args: any[]) => void
someRest(1, 2, 3);
>someRest(1, 2, 3) : void
>someRest : (x: any, y: any, ...args: any[]) => void
>1 : 1
>2 : 2
>3 : 3
/**
* @param {number} x - a thing
*/
function jsdocced(x) { arguments; }
>jsdocced : (x: number) => void
>x : number
>arguments : IArguments
jsdocced(1);
>jsdocced(1) : void
>jsdocced : (x: number) => void
>1 : 1
function dontDoubleRest(x, ...y) { arguments; }
>dontDoubleRest : (x: any, ...y: any[]) => void
>x : any
>y : any[]
>arguments : IArguments
dontDoubleRest(1, 2, 3);
>dontDoubleRest(1, 2, 3) : void
>dontDoubleRest : (x: any, ...y: any[]) => void
>1 : 1
>2 : 2
>3 : 3
@@ -1,14 +1,14 @@
=== tests/cases/compiler/arrayConcatMap.ts ===
var x = [].concat([{ a: 1 }], [{ a: 2 }])
>x : Symbol(x, Decl(arrayConcatMap.ts, 0, 3))
>[].concat([{ a: 1 }], [{ a: 2 }]) .map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>[].concat([{ a: 1 }], [{ a: 2 }]) .map : Symbol(Array.map, Decl(lib.d.ts, --, --))
>[].concat : Symbol(Array.concat, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>concat : Symbol(Array.concat, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>a : Symbol(a, Decl(arrayConcatMap.ts, 0, 20))
>a : Symbol(a, Decl(arrayConcatMap.ts, 0, 32))
.map(b => b.a);
>map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>map : Symbol(Array.map, Decl(lib.d.ts, --, --))
>b : Symbol(b, Decl(arrayConcatMap.ts, 1, 15))
>b : Symbol(b, Decl(arrayConcatMap.ts, 1, 15))
@@ -2,7 +2,7 @@
var x = [].concat([{ a: 1 }], [{ a: 2 }])
>x : any[]
>[].concat([{ a: 1 }], [{ a: 2 }]) .map(b => b.a) : any[]
>[].concat([{ a: 1 }], [{ a: 2 }]) .map : { <U>(this: [any, any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U, U, U]; <U>(this: [any, any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U, U, U]; <Z, U>(this: [any, any, any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U, U, U]; <U>(this: [any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U, U]; <U>(this: [any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U, U]; <Z, U>(this: [any, any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U, U]; <U>(this: [any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U]; <U>(this: [any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U]; <Z, U>(this: [any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U]; <U>(this: [any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U]; <U>(this: [any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U]; <Z, U>(this: [any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U]; <U>(callbackfn: (this: void, value: any, index: number, array: any[]) => U): U[]; <U>(callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): U[]; <Z, U>(callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): U[]; }
>[].concat([{ a: 1 }], [{ a: 2 }]) .map : <U>(callbackfn: (value: any, index: number, array: any[]) => U, thisArg?: any) => U[]
>[].concat([{ a: 1 }], [{ a: 2 }]) : any[]
>[].concat : { (...items: any[][]): any[]; (...items: any[]): any[]; }
>[] : undefined[]
@@ -17,8 +17,8 @@ var x = [].concat([{ a: 1 }], [{ a: 2 }])
>2 : 2
.map(b => b.a);
>map : { <U>(this: [any, any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U, U, U]; <U>(this: [any, any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U, U, U]; <Z, U>(this: [any, any, any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U, U, U]; <U>(this: [any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U, U]; <U>(this: [any, any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U, U]; <Z, U>(this: [any, any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U, U]; <U>(this: [any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U, U]; <U>(this: [any, any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U, U]; <Z, U>(this: [any, any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U, U]; <U>(this: [any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U): [U, U]; <U>(this: [any, any], callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): [U, U]; <Z, U>(this: [any, any], callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): [U, U]; <U>(callbackfn: (this: void, value: any, index: number, array: any[]) => U): U[]; <U>(callbackfn: (this: void, value: any, index: number, array: any[]) => U, thisArg: undefined): U[]; <Z, U>(callbackfn: (this: Z, value: any, index: number, array: any[]) => U, thisArg: Z): U[]; }
>b => b.a : (this: void, b: any) => any
>map : <U>(callbackfn: (value: any, index: number, array: any[]) => U, thisArg?: any) => U[]
>b => b.a : (b: any) => any
>b : any
>b.a : any
>b : any
@@ -14,9 +14,9 @@ var foo = [
]
foo.filter(x => x.name); //should accepted all possible types not only boolean!
>foo.filter : Symbol(Array.filter, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>foo.filter : Symbol(Array.filter, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>foo : Symbol(foo, Decl(arrayFilter.ts, 0, 3))
>filter : Symbol(Array.filter, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>filter : Symbol(Array.filter, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>x : Symbol(x, Decl(arrayFilter.ts, 6, 11))
>x.name : Symbol(name, Decl(arrayFilter.ts, 1, 5))
>x : Symbol(x, Decl(arrayFilter.ts, 6, 11))
+3 -3
View File
@@ -22,10 +22,10 @@ var foo = [
foo.filter(x => x.name); //should accepted all possible types not only boolean!
>foo.filter(x => x.name) : { name: string; }[]
>foo.filter : { (callbackfn: (this: void, value: { name: string; }, index: number, array: { name: string; }[]) => any): { name: string; }[]; (callbackfn: (this: void, value: { name: string; }, index: number, array: { name: string; }[]) => any, thisArg: undefined): { name: string; }[]; <Z>(callbackfn: (this: Z, value: { name: string; }, index: number, array: { name: string; }[]) => any, thisArg: Z): { name: string; }[]; }
>foo.filter : { <S extends { name: string; }>(callbackfn: (value: { name: string; }, index: number, array: { name: string; }[]) => value is S, thisArg?: any): S[]; (callbackfn: (value: { name: string; }, index: number, array: { name: string; }[]) => any, thisArg?: any): { name: string; }[]; }
>foo : { name: string; }[]
>filter : { (callbackfn: (this: void, value: { name: string; }, index: number, array: { name: string; }[]) => any): { name: string; }[]; (callbackfn: (this: void, value: { name: string; }, index: number, array: { name: string; }[]) => any, thisArg: undefined): { name: string; }[]; <Z>(callbackfn: (this: Z, value: { name: string; }, index: number, array: { name: string; }[]) => any, thisArg: Z): { name: string; }[]; }
>x => x.name : (this: void, x: { name: string; }) => string
>filter : { <S extends { name: string; }>(callbackfn: (value: { name: string; }, index: number, array: { name: string; }[]) => value is S, thisArg?: any): S[]; (callbackfn: (value: { name: string; }, index: number, array: { name: string; }[]) => any, thisArg?: any): { name: string; }[]; }
>x => x.name : (x: { name: string; }) => string
>x : { name: string; }
>x.name : string
>x : { name: string; }
@@ -1,12 +1,12 @@
tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts(13,1): error TS2322: Type 'A[]' is not assignable to type 'ReadonlyArray<B>'.
Types of property 'concat' are incompatible.
Type '{ (...items: A[][]): A[]; (...items: (A | A[])[]): A[]; }' is not assignable to type '{ <U extends ReadonlyArray<B>>(...items: U[]): B[]; (...items: B[][]): B[]; (...items: (B | B[])[]): B[]; }'.
Type '{ (...items: A[][]): A[]; (...items: (A | A[])[]): A[]; }' is not assignable to type '{ (...items: B[][]): B[]; (...items: (B | B[])[]): B[]; }'.
Type 'A[]' is not assignable to type 'B[]'.
Type 'A' is not assignable to type 'B'.
Property 'b' is missing in type 'A'.
tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts(18,1): error TS2322: Type 'C<A>' is not assignable to type 'ReadonlyArray<B>'.
Types of property 'concat' are incompatible.
Type '{ (...items: A[][]): A[]; (...items: (A | A[])[]): A[]; }' is not assignable to type '{ <U extends ReadonlyArray<B>>(...items: U[]): B[]; (...items: B[][]): B[]; (...items: (B | B[])[]): B[]; }'.
Type '{ (...items: A[][]): A[]; (...items: (A | A[])[]): A[]; }' is not assignable to type '{ (...items: B[][]): B[]; (...items: (B | B[])[]): B[]; }'.
Type 'A[]' is not assignable to type 'B[]'.
@@ -27,7 +27,7 @@ tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts(18,1): error T
~~~
!!! error TS2322: Type 'A[]' is not assignable to type 'ReadonlyArray<B>'.
!!! error TS2322: Types of property 'concat' are incompatible.
!!! error TS2322: Type '{ (...items: A[][]): A[]; (...items: (A | A[])[]): A[]; }' is not assignable to type '{ <U extends ReadonlyArray<B>>(...items: U[]): B[]; (...items: B[][]): B[]; (...items: (B | B[])[]): B[]; }'.
!!! error TS2322: Type '{ (...items: A[][]): A[]; (...items: (A | A[])[]): A[]; }' is not assignable to type '{ (...items: B[][]): B[]; (...items: (B | B[])[]): B[]; }'.
!!! error TS2322: Type 'A[]' is not assignable to type 'B[]'.
!!! error TS2322: Type 'A' is not assignable to type 'B'.
!!! error TS2322: Property 'b' is missing in type 'A'.
@@ -39,6 +39,6 @@ tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts(18,1): error T
~~~
!!! error TS2322: Type 'C<A>' is not assignable to type 'ReadonlyArray<B>'.
!!! error TS2322: Types of property 'concat' are incompatible.
!!! error TS2322: Type '{ (...items: A[][]): A[]; (...items: (A | A[])[]): A[]; }' is not assignable to type '{ <U extends ReadonlyArray<B>>(...items: U[]): B[]; (...items: B[][]): B[]; (...items: (B | B[])[]): B[]; }'.
!!! error TS2322: Type '{ (...items: A[][]): A[]; (...items: (A | A[])[]): A[]; }' is not assignable to type '{ (...items: B[][]): B[]; (...items: (B | B[])[]): B[]; }'.
!!! error TS2322: Type 'A[]' is not assignable to type 'B[]'.

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