Merge remote-tracking branch 'origin/master' into release-3.6

This commit is contained in:
Daniel Rosenwasser
2019-08-12 17:23:15 -07:00
663 changed files with 19856 additions and 4885 deletions
+20 -20
View File
@@ -41,7 +41,7 @@ const generateLibs = () => {
.pipe(concat(relativeTarget, { newLine: "\n\n" }))
.pipe(dest("built/local"))));
};
task("lib", generateLibs)
task("lib", generateLibs);
task("lib").description = "Builds the library targets";
const cleanLib = () => del(libs.map(lib => lib.target));
@@ -168,7 +168,7 @@ task("services", series(preBuild, buildServices));
task("services").description = "Builds the language service";
task("services").flags = {
" --built": "Compile using the built version of the compiler."
}
};
const cleanServices = async () => {
if (fs.existsSync("built/local/typescriptServices.tsconfig.json")) {
@@ -200,14 +200,14 @@ task("watch-services", series(preBuild, parallel(watchLib, watchDiagnostics, wat
task("watch-services").description = "Watches for changes and rebuild language service only";
task("watch-services").flags = {
" --built": "Compile using the built version of the compiler."
}
};
const buildServer = () => buildProject("src/tsserver", cmdLineOptions);
task("tsserver", series(preBuild, buildServer));
task("tsserver").description = "Builds the language server";
task("tsserver").flags = {
" --built": "Compile using the built version of the compiler."
}
};
const cleanServer = () => cleanProject("src/tsserver");
cleanTasks.push(cleanServer);
@@ -219,13 +219,13 @@ task("watch-tsserver", series(preBuild, parallel(watchLib, watchDiagnostics, wat
task("watch-tsserver").description = "Watch for changes and rebuild the language server only";
task("watch-tsserver").flags = {
" --built": "Compile using the built version of the compiler."
}
};
task("min", series(preBuild, parallel(buildTsc, buildServer)));
task("min").description = "Builds only tsc and tsserver";
task("min").flags = {
" --built": "Compile using the built version of the compiler."
}
};
task("clean-min", series(cleanTsc, cleanServer));
task("clean-min").description = "Cleans outputs for tsc and tsserver";
@@ -234,7 +234,7 @@ task("watch-min", series(preBuild, parallel(watchLib, watchDiagnostics, watchTsc
task("watch-min").description = "Watches for changes to a tsc and tsserver only";
task("watch-min").flags = {
" --built": "Compile using the built version of the compiler."
}
};
const buildLssl = (() => {
// build tsserverlibrary.out.js
@@ -268,7 +268,7 @@ task("lssl", series(preBuild, buildLssl));
task("lssl").description = "Builds language service server library";
task("lssl").flags = {
" --built": "Compile using the built version of the compiler."
}
};
const cleanLssl = async () => {
if (fs.existsSync("built/local/tsserverlibrary.tsconfig.json")) {
@@ -302,14 +302,14 @@ task("watch-lssl", series(preBuild, parallel(watchLib, watchDiagnostics, watchLs
task("watch-lssl").description = "Watch for changes and rebuild tsserverlibrary only";
task("watch-lssl").flags = {
" --built": "Compile using the built version of the compiler."
}
};
const buildTests = () => buildProject("src/testRunner");
task("tests", series(preBuild, parallel(buildLssl, buildTests)));
task("tests").description = "Builds the test infrastructure";
task("tests").flags = {
" --built": "Compile using the built version of the compiler."
}
};
const cleanTests = () => cleanProject("src/testRunner");
cleanTasks.push(cleanTests);
@@ -381,13 +381,13 @@ task("local", series(buildFoldStart, preBuild, parallel(localize, buildTsc, buil
task("local").description = "Builds the full compiler and services";
task("local").flags = {
" --built": "Compile using the built version of the compiler."
}
};
task("watch-local", series(preBuild, parallel(watchLib, watchDiagnostics, watchTsc, watchServices, watchServer, watchLssl)));
task("watch-local").description = "Watches for changes to projects in src/ (but does not execute tests).";
task("watch-local").flags = {
" --built": "Compile using the built version of the compiler."
}
};
const generateCodeCoverage = () => exec("istanbul", ["cover", "node_modules/mocha/bin/_mocha", "--", "-R", "min", "-t", "" + cmdLineOptions.testTimeout, "built/local/run.js"]);
task("generate-code-coverage", series(preBuild, buildTests, generateCodeCoverage));
@@ -417,7 +417,7 @@ task("runtests").flags = {
" --built": "Compile using the built version of the compiler.",
" --shards": "Total number of shards running tests (default: 1)",
" --shardId": "1-based ID of this shard (default: 1)",
}
};
const runTestsParallel = () => runConsoleTests("built/local/run.js", "min", /*runInParallel*/ true, /*watchMode*/ false);
task("runtests-parallel", series(preBuild, preTest, runTestsParallel, postTest));
@@ -436,10 +436,10 @@ task("runtests-parallel").flags = {
" --shardId": "1-based ID of this shard (default: 1)",
};
task("diff", () => exec(getDiffTool(), [refBaseline, localBaseline], { ignoreExitCode: true }));
task("diff", () => exec(getDiffTool(), [refBaseline, localBaseline], { ignoreExitCode: true, waitForExit: false }));
task("diff").description = "Diffs the compiler baselines using the diff tool specified by the 'DIFF' environment variable";
task("diff-rwc", () => exec(getDiffTool(), [refRwcBaseline, localRwcBaseline], { ignoreExitCode: true }));
task("diff-rwc", () => exec(getDiffTool(), [refRwcBaseline, localRwcBaseline], { ignoreExitCode: true, waitForExit: false }));
task("diff-rwc").description = "Diffs the RWC baselines using the diff tool specified by the 'DIFF' environment variable";
/**
@@ -478,7 +478,7 @@ task("tsc-instrumented", series(lkgPreBuild, parallel(localize, buildTsc, buildS
task("tsc-instrumented").description = "Builds an instrumented tsc.js";
task("tsc-instrumented").flags = {
"-t --tests=<testname>": "The test to run."
}
};
// TODO(rbuckton): Determine if we still need this task. Depending on a relative
// path here seems like a bad idea.
@@ -533,7 +533,7 @@ task("LKG", series(lkgPreBuild, parallel(localize, buildTsc, buildServer, buildS
task("LKG").description = "Makes a new LKG out of the built js files";
task("LKG").flags = {
" --built": "Compile using the built version of the compiler.",
}
};
const generateSpec = () => exec("cscript", ["//nologo", "scripts/word2md.js", path.resolve("doc/TypeScript Language Specification.docx"), path.resolve("doc/spec.md")]);
task("generate-spec", series(buildScripts, generateSpec));
@@ -542,15 +542,15 @@ task("generate-spec").description = "Generates a Markdown version of the Languag
task("clean", series(parallel(cleanTasks), cleanBuilt));
task("clean").description = "Cleans build outputs";
const configureNightly = () => exec(process.execPath, ["scripts/configurePrerelease.js", "dev", "package.json", "src/compiler/core.ts"])
const configureNightly = () => exec(process.execPath, ["scripts/configurePrerelease.js", "dev", "package.json", "src/compiler/core.ts"]);
task("configure-nightly", series(buildScripts, configureNightly));
task("configure-nightly").description = "Runs scripts/configurePrerelease.ts to prepare a build for nightly publishing";
const configureInsiders = () => exec(process.execPath, ["scripts/configurePrerelease.js", "insiders", "package.json", "src/compiler/core.ts"])
const configureInsiders = () => exec(process.execPath, ["scripts/configurePrerelease.js", "insiders", "package.json", "src/compiler/core.ts"]);
task("configure-insiders", series(buildScripts, configureInsiders));
task("configure-insiders").description = "Runs scripts/configurePrerelease.ts to prepare a build for insiders publishing";
const configureExperimental = () => exec(process.execPath, ["scripts/configurePrerelease.js", "experimental", "package.json", "src/compiler/core.ts"])
const configureExperimental = () => exec(process.execPath, ["scripts/configurePrerelease.js", "experimental", "package.json", "src/compiler/core.ts"]);
task("configure-experimental", series(buildScripts, configureExperimental));
task("configure-experimental").description = "Runs scripts/configurePrerelease.ts to prepare a build for experimental publishing";
+4 -2
View File
@@ -42,12 +42,13 @@
"@types/gulp-sourcemaps": "0.0.32",
"@types/jake": "latest",
"@types/merge2": "latest",
"@types/microsoft__typescript-etw": "latest",
"@types/minimatch": "latest",
"@types/minimist": "latest",
"@types/mkdirp": "latest",
"@types/mocha": "latest",
"@types/ms": "latest",
"@types/node": "^8.10.51",
"@types/node": "latest",
"@types/node-fetch": "^2.3.4",
"@types/q": "latest",
"@types/source-map-support": "latest",
@@ -109,7 +110,8 @@
"browser": {
"fs": false,
"os": false,
"path": false
"path": false,
"@microsoft/typescript-etw": false
},
"dependencies": {}
}
+23 -15
View File
@@ -25,10 +25,11 @@ const isWindows = /^win/.test(process.platform);
* @property {boolean} [ignoreExitCode]
* @property {import("prex").CancellationToken} [cancelToken]
* @property {boolean} [hidePrompt]
* @property {boolean} [waitForExit=true]
*/
function exec(cmd, args, options = {}) {
return /**@type {Promise<{exitCode: number}>}*/(new Promise((resolve, reject) => {
const { ignoreExitCode, cancelToken = CancellationToken.none } = options;
const { ignoreExitCode, cancelToken = CancellationToken.none, waitForExit = true } = options;
cancelToken.throwIfCancellationRequested();
// TODO (weswig): Update child_process types to add windowsVerbatimArguments to the type definition
@@ -36,26 +37,33 @@ function exec(cmd, args, options = {}) {
const command = isWindows ? [possiblyQuote(cmd), ...args] : [`${cmd} ${args.join(" ")}`];
if (!options.hidePrompt) log(`> ${chalk.green(cmd)} ${args.join(" ")}`);
const proc = spawn(isWindows ? "cmd" : "/bin/sh", [subshellFlag, ...command], { stdio: "inherit", windowsVerbatimArguments: true });
const proc = spawn(isWindows ? "cmd" : "/bin/sh", [subshellFlag, ...command], { stdio: waitForExit ? "inherit" : "ignore", windowsVerbatimArguments: true });
const registration = cancelToken.register(() => {
log(`${chalk.red("killing")} '${chalk.green(cmd)} ${args.join(" ")}'...`);
proc.kill("SIGINT");
proc.kill("SIGTERM");
reject(new CancelError());
});
proc.on("exit", exitCode => {
registration.unregister();
if (exitCode === 0 || ignoreExitCode) {
resolve({ exitCode });
}
else {
reject(new Error(`Process exited with code: ${exitCode}`));
}
});
proc.on("error", error => {
registration.unregister();
reject(error);
});
if (waitForExit) {
proc.on("exit", exitCode => {
registration.unregister();
if (exitCode === 0 || ignoreExitCode) {
resolve({ exitCode });
}
else {
reject(new Error(`Process exited with code: ${exitCode}`));
}
});
proc.on("error", error => {
registration.unregister();
reject(error);
});
}
else {
proc.unref();
// wait a short period in order to allow the process to start successfully before Node exits.
setTimeout(() => resolve({ exitCode: undefined }), 100);
}
}));
}
exports.exec = exec;
+1 -1
View File
@@ -30,7 +30,7 @@ async function copyLocalizedDiagnostics() {
for (const d of dir) {
const fileName = path.join(source, d);
if (fs.statSync(fileName).isDirectory()) {
if (d === 'tslint') continue;
if (d === 'tslint' || d === 'enu') continue;
await fs.copy(fileName, path.join(dest, d));
}
}
@@ -0,0 +1,28 @@
const MAX_UNICODE_CODEPOINT = 0x10FFFF;
const isStart = c => /[\p{ID_Start}\u{2118}\u{212E}\u{309B}\u{309C}]/u.test(c); // Other_ID_Start explicitly included for back compat - see http://www.unicode.org/reports/tr31/#Introduction
const isPart = c => /[\p{ID_Continue}\u{00B7}\u{0387}\u{19DA}\u{1369}\u{136A}\u{136B}\u{136C}\u{136D}\u{136E}\u{136F}\u{1370}\u{1371}]/u.test(c) || isStart(c); // Likewise for Other_ID_Continue
const parts = [];
let partsActive = false;
let startsActive = false;
const starts = [];
for (let i = 0; i < MAX_UNICODE_CODEPOINT; i++) {
if (isStart(String.fromCodePoint(i)) !== startsActive) {
starts.push(i - +startsActive);
startsActive = !startsActive;
}
if (isPart(String.fromCodePoint(i)) !== partsActive) {
parts.push(i - +partsActive);
partsActive = !partsActive;
}
}
console.log(`/**
* Generated by scripts/regenerate-unicode-identifier-parts.js on node ${process.version} with unicode ${process.versions.unicode}
* based on http://www.unicode.org/reports/tr31/ and https://www.ecma-international.org/ecma-262/6.0/#sec-names-and-keywords
* unicodeESNextIdentifierStart corresponds to the ID_Start and Other_ID_Start property, and
* unicodeESNextIdentifierPart corresponds to ID_Continue, Other_ID_Continue, plus ID_Start and Other_ID_Start
*/`);
console.log(`const unicodeESNextIdentifierStart = [${starts.join(", ")}];`);
console.log(`const unicodeESNextIdentifierPart = [${parts.join(", ")}];`);
+36 -18
View File
@@ -106,7 +106,9 @@ namespace ts {
export function bindSourceFile(file: SourceFile, options: CompilerOptions) {
performance.mark("beforeBind");
perfLogger.logStartBindFile("" + file.fileName);
binder(file, options);
perfLogger.logStopBindFile();
performance.mark("afterBind");
performance.measure("Bind", "beforeBind", "afterBind");
}
@@ -120,7 +122,7 @@ namespace ts {
let thisParentContainer: Node; // Container one level up
let blockScopeContainer: Node;
let lastContainer: Node;
let delayedTypeAliases: (JSDocTypedefTag | JSDocCallbackTag)[];
let delayedTypeAliases: (JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag)[];
let seenThisKeyword: boolean;
// state used by control flow analysis
@@ -490,11 +492,11 @@ namespace ts {
// and should never be merged directly with other augmentation, and the latter case would be possible if automatic merge is allowed.
if (isJSDocTypeAlias(node)) Debug.assert(isInJSFile(node)); // We shouldn't add symbols for JSDoc nodes if not in a JS file.
if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || isJSDocTypeAlias(node)) {
if (hasModifier(node, ModifierFlags.Default) && !getDeclarationName(node)) {
if (!container.locals || (hasModifier(node, ModifierFlags.Default) && !getDeclarationName(node))) {
return declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes); // No local symbol for an unnamed default!
}
const exportKind = symbolFlags & SymbolFlags.Value ? SymbolFlags.ExportValue : 0;
const local = declareSymbol(container.locals!, /*parent*/ undefined, node, exportKind, symbolExcludes);
const local = declareSymbol(container.locals, /*parent*/ undefined, node, exportKind, symbolExcludes);
local.exportSymbol = declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes);
node.localSymbol = local;
return local;
@@ -732,7 +734,8 @@ namespace ts {
break;
case SyntaxKind.JSDocTypedefTag:
case SyntaxKind.JSDocCallbackTag:
bindJSDocTypeAlias(node as JSDocTypedefTag | JSDocCallbackTag);
case SyntaxKind.JSDocEnumTag:
bindJSDocTypeAlias(node as JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag);
break;
// In source files and blocks, bind functions first to match hoisting that occurs at runtime
case SyntaxKind.SourceFile: {
@@ -1436,9 +1439,9 @@ namespace ts {
}
}
function bindJSDocTypeAlias(node: JSDocTypedefTag | JSDocCallbackTag) {
function bindJSDocTypeAlias(node: JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag) {
node.tagName.parent = node;
if (node.fullName) {
if (node.kind !== SyntaxKind.JSDocEnumTag && node.fullName) {
setParentPointers(node, node.fullName);
}
}
@@ -1805,7 +1808,19 @@ namespace ts {
currentFlow = { flags: FlowFlags.Start };
parent = typeAlias;
bind(typeAlias.typeExpression);
if (!typeAlias.fullName || typeAlias.fullName.kind === SyntaxKind.Identifier) {
const declName = getNameOfDeclaration(typeAlias);
if ((isJSDocEnumTag(typeAlias) || !typeAlias.fullName) && declName && isPropertyAccessEntityNameExpression(declName.parent)) {
// typedef anchored to an A.B.C assignment - we need to bind into B's namespace under name C
const isTopLevel = isTopLevelNamespaceAssignment(declName.parent);
if (isTopLevel) {
bindPotentiallyMissingNamespaces(file.symbol, declName.parent, isTopLevel, !!findAncestor(declName, d => isPropertyAccessExpression(d) && d.name.escapedText === "prototype"));
const oldContainer = container;
container = isPropertyAccessExpression(declName.parent.expression) ? declName.parent.expression.name : declName.parent.expression;
declareModuleMember(typeAlias, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
container = oldContainer;
}
}
else if (isJSDocEnumTag(typeAlias) || !typeAlias.fullName || typeAlias.fullName.kind === SyntaxKind.Identifier) {
parent = typeAlias.parent;
bindBlockScopedDeclaration(typeAlias, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
}
@@ -1827,7 +1842,8 @@ namespace ts {
node.originalKeywordKind! >= SyntaxKind.FirstFutureReservedWord &&
node.originalKeywordKind! <= SyntaxKind.LastFutureReservedWord &&
!isIdentifierName(node) &&
!(node.flags & NodeFlags.Ambient)) {
!(node.flags & NodeFlags.Ambient) &&
!(node.flags & NodeFlags.JSDoc)) {
// Report error only if there are no parse errors in file
if (!file.parseDiagnostics.length) {
@@ -2319,7 +2335,8 @@ namespace ts {
return declareSymbolAndAddToSymbolTable(propTag, flags, SymbolFlags.PropertyExcludes);
case SyntaxKind.JSDocTypedefTag:
case SyntaxKind.JSDocCallbackTag:
return (delayedTypeAliases || (delayedTypeAliases = [])).push(node as JSDocTypedefTag | JSDocCallbackTag);
case SyntaxKind.JSDocEnumTag:
return (delayedTypeAliases || (delayedTypeAliases = [])).push(node as JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag);
}
}
@@ -2605,7 +2622,7 @@ namespace ts {
}
function bindPotentiallyMissingNamespaces(namespaceSymbol: Symbol | undefined, entityName: EntityNameExpression, isToplevel: boolean, isPrototypeProperty: boolean) {
if (isToplevel && !isPrototypeProperty && (!namespaceSymbol || !(namespaceSymbol.flags & SymbolFlags.Namespace))) {
if (isToplevel && !isPrototypeProperty) {
// make symbols or add declarations for intermediate containers
const flags = SymbolFlags.Module | SymbolFlags.Assignment;
const excludeFlags = SymbolFlags.ValueModuleExcludes & ~SymbolFlags.Assignment;
@@ -2640,11 +2657,15 @@ namespace ts {
declareSymbol(symbolTable, namespaceSymbol, declaration, includes | SymbolFlags.Assignment, excludes & ~SymbolFlags.Assignment);
}
function bindPropertyAssignment(name: EntityNameExpression, propertyAccess: PropertyAccessEntityNameExpression, isPrototypeProperty: boolean) {
let namespaceSymbol = lookupSymbolForPropertyAccess(name);
const isToplevel = isBinaryExpression(propertyAccess.parent)
function isTopLevelNamespaceAssignment(propertyAccess: PropertyAccessEntityNameExpression) {
return isBinaryExpression(propertyAccess.parent)
? getParentOfBinaryExpression(propertyAccess.parent).parent.kind === SyntaxKind.SourceFile
: propertyAccess.parent.parent.kind === SyntaxKind.SourceFile;
}
function bindPropertyAssignment(name: EntityNameExpression, propertyAccess: PropertyAccessEntityNameExpression, isPrototypeProperty: boolean) {
let namespaceSymbol = lookupSymbolForPropertyAccess(name);
const isToplevel = isTopLevelNamespaceAssignment(propertyAccess);
namespaceSymbol = bindPotentiallyMissingNamespaces(namespaceSymbol, propertyAccess.expression, isToplevel, isPrototypeProperty);
bindPotentiallyNewExpandoMemberToNamespace(propertyAccess, namespaceSymbol, isPrototypeProperty);
}
@@ -2766,11 +2787,8 @@ namespace ts {
}
if (!isBindingPattern(node.name)) {
const isEnum = isInJSFile(node) && !!getJSDocEnumTag(node);
const enumFlags = (isEnum ? SymbolFlags.RegularEnum : SymbolFlags.None);
const enumExcludes = (isEnum ? SymbolFlags.RegularEnumExcludes : SymbolFlags.None);
if (isBlockOrCatchScoped(node)) {
bindBlockScopedDeclaration(node, SymbolFlags.BlockScopedVariable | enumFlags, SymbolFlags.BlockScopedVariableExcludes | enumExcludes);
bindBlockScopedDeclaration(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes);
}
else if (isParameterDeclaration(node)) {
// It is safe to walk up parent chain to find whether the node is a destructuring parameter declaration
@@ -2785,7 +2803,7 @@ namespace ts {
declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes);
}
else {
declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable | enumFlags, SymbolFlags.FunctionScopedVariableExcludes | enumExcludes);
declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.FunctionScopedVariableExcludes);
}
}
}
+653 -510
View File
File diff suppressed because it is too large Load Diff
+13 -3
View File
@@ -1743,6 +1743,16 @@ namespace ts {
return false;
}
/** @internal */
export interface TSConfig {
compilerOptions: CompilerOptions;
compileOnSave: boolean | undefined;
exclude?: ReadonlyArray<string>;
files: ReadonlyArray<string> | undefined;
include?: ReadonlyArray<string>;
references: ReadonlyArray<ProjectReference> | undefined;
}
/**
* Generate an uncommented, complete tsconfig for use with "--showConfig"
* @param configParseResult options to be generated into tsconfig.json
@@ -1750,7 +1760,7 @@ namespace ts {
* @param host provides current directory and case sensitivity services
*/
/** @internal */
export function convertToTSConfig(configParseResult: ParsedCommandLine, configFileName: string, host: { getCurrentDirectory(): string, useCaseSensitiveFileNames: boolean }): object {
export function convertToTSConfig(configParseResult: ParsedCommandLine, configFileName: string, host: { getCurrentDirectory(): string, useCaseSensitiveFileNames: boolean }): TSConfig {
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
const files = map(
filter(
@@ -1778,13 +1788,13 @@ namespace ts {
build: undefined,
version: undefined,
},
references: map(configParseResult.projectReferences, r => ({ ...r, path: r.originalPath, originalPath: undefined })),
references: map(configParseResult.projectReferences, r => ({ ...r, path: r.originalPath ? r.originalPath : "", originalPath: undefined })),
files: length(files) ? files : undefined,
...(configParseResult.configFileSpecs ? {
include: filterSameAsDefaultInclude(configParseResult.configFileSpecs.validatedIncludeSpecs),
exclude: configParseResult.configFileSpecs.validatedExcludeSpecs
} : {}),
compilerOnSave: !!configParseResult.compileOnSave ? true : undefined
compileOnSave: !!configParseResult.compileOnSave ? true : undefined
};
return config;
}
+11
View File
@@ -1381,6 +1381,17 @@ namespace ts {
return keys;
}
export function getAllKeys(obj: object): string[] {
const result: string[] = [];
do {
const names = Object.getOwnPropertyNames(obj);
for (const name of names) {
pushIfUnique(result, name);
}
} while (obj = Object.getPrototypeOf(obj));
return result;
}
export function getOwnValues<T>(sparseArray: T[]): T[] {
const values: T[] = [];
for (const key in sparseArray) {
+1 -1
View File
@@ -258,4 +258,4 @@ namespace ts {
isDebugInfoEnabled = true;
}
}
}
}
+5 -5
View File
@@ -243,10 +243,6 @@
"category": "Error",
"code": 1085
},
"An accessor cannot be declared in an ambient context.": {
"category": "Error",
"code": 1086
},
"'{0}' modifier cannot appear on a constructor declaration.": {
"category": "Error",
"code": 1089
@@ -855,6 +851,10 @@
"category": "Error",
"code": 1259
},
"Keywords cannot contain escape characters.": {
"category": "Error",
"code": 1260
},
"'with' statements are not allowed in an async function block.": {
"category": "Error",
"code": 1300
@@ -983,7 +983,7 @@
"category": "Error",
"code": 1342
},
"The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options.": {
"The 'import.meta' meta-property is only allowed when the '--module' option is 'esnext' or 'system'.": {
"category": "Error",
"code": 1343
},
+1 -1
View File
@@ -1605,7 +1605,7 @@ namespace ts {
for (let i = 0; i < numNodes; i++) {
const currentNode = bundle ? i < numPrepends ? bundle.prepends[i] : bundle.sourceFiles[i - numPrepends] : node;
const sourceFile = isSourceFile(currentNode) ? currentNode : isUnparsedSource(currentNode) ? undefined : currentSourceFile!;
const shouldSkip = printerOptions.noEmitHelpers || (!!sourceFile && getExternalHelpersModuleName(sourceFile) !== undefined);
const shouldSkip = printerOptions.noEmitHelpers || (!!sourceFile && hasRecordedExternalHelpers(sourceFile));
const shouldBundle = (isSourceFile(currentNode) || isUnparsedSource(currentNode)) && !isOwnFileEmit;
const helpers = isUnparsedSource(currentNode) ? currentNode.helpers : getSortedEmitHelpers(currentNode);
if (helpers) {
+75 -8
View File
@@ -3628,23 +3628,28 @@ namespace ts {
// Helpers
export function getHelperName(name: string) {
/**
* Gets an identifier for the name of an *unscoped* emit helper.
*/
export function getUnscopedHelperName(name: string) {
return setEmitFlags(createIdentifier(name), EmitFlags.HelperName | EmitFlags.AdviseOnEmitNode);
}
export const valuesHelper: UnscopedEmitHelper = {
name: "typescript:values",
importName: "__values",
scoped: false,
text: `
var __values = (this && this.__values) || function (o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
return {
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};`
};
@@ -3652,7 +3657,7 @@ namespace ts {
context.requestEmitHelper(valuesHelper);
return setTextRange(
createCall(
getHelperName("__values"),
getUnscopedHelperName("__values"),
/*typeArguments*/ undefined,
[expression]
),
@@ -3662,6 +3667,7 @@ namespace ts {
export const readHelper: UnscopedEmitHelper = {
name: "typescript:read",
importName: "__read",
scoped: false,
text: `
var __read = (this && this.__read) || function (o, n) {
@@ -3686,7 +3692,7 @@ namespace ts {
context.requestEmitHelper(readHelper);
return setTextRange(
createCall(
getHelperName("__read"),
getUnscopedHelperName("__read"),
/*typeArguments*/ undefined,
count !== undefined
? [iteratorRecord, createLiteral(count)]
@@ -3698,6 +3704,7 @@ namespace ts {
export const spreadHelper: UnscopedEmitHelper = {
name: "typescript:spread",
importName: "__spread",
scoped: false,
text: `
var __spread = (this && this.__spread) || function () {
@@ -3711,7 +3718,7 @@ namespace ts {
context.requestEmitHelper(spreadHelper);
return setTextRange(
createCall(
getHelperName("__spread"),
getUnscopedHelperName("__spread"),
/*typeArguments*/ undefined,
argumentList
),
@@ -3721,6 +3728,7 @@ namespace ts {
export const spreadArraysHelper: UnscopedEmitHelper = {
name: "typescript:spreadArrays",
importName: "__spreadArrays",
scoped: false,
text: `
var __spreadArrays = (this && this.__spreadArrays) || function () {
@@ -3736,7 +3744,7 @@ namespace ts {
context.requestEmitHelper(spreadArraysHelper);
return setTextRange(
createCall(
getHelperName("__spreadArrays"),
getUnscopedHelperName("__spreadArrays"),
/*typeArguments*/ undefined,
argumentList
),
@@ -4862,6 +4870,65 @@ namespace ts {
return emitNode && emitNode.externalHelpersModuleName;
}
export function hasRecordedExternalHelpers(sourceFile: SourceFile) {
const parseNode = getOriginalNode(sourceFile, isSourceFile);
const emitNode = parseNode && parseNode.emitNode;
return !!emitNode && (!!emitNode.externalHelpersModuleName || !!emitNode.externalHelpers);
}
export function createExternalHelpersImportDeclarationIfNeeded(sourceFile: SourceFile, compilerOptions: CompilerOptions, hasExportStarsToExportValues?: boolean, hasImportStar?: boolean, hasImportDefault?: boolean) {
if (compilerOptions.importHelpers && isEffectiveExternalModule(sourceFile, compilerOptions)) {
let namedBindings: NamedImportBindings | undefined;
const moduleKind = getEmitModuleKind(compilerOptions);
if (moduleKind >= ModuleKind.ES2015 && moduleKind <= ModuleKind.ESNext) {
// use named imports
const helpers = getEmitHelpers(sourceFile);
if (helpers) {
const helperNames: string[] = [];
for (const helper of helpers) {
if (!helper.scoped) {
const importName = (helper as UnscopedEmitHelper).importName;
if (importName) {
pushIfUnique(helperNames, importName);
}
}
}
if (some(helperNames)) {
helperNames.sort(compareStringsCaseSensitive);
// Alias the imports if the names are used somewhere in the file.
// NOTE: We don't need to care about global import collisions as this is a module.
namedBindings = createNamedImports(
map(helperNames, name => isFileLevelUniqueName(sourceFile, name)
? createImportSpecifier(/*propertyName*/ undefined, createIdentifier(name))
: createImportSpecifier(createIdentifier(name), getUnscopedHelperName(name))
)
);
const parseNode = getOriginalNode(sourceFile, isSourceFile);
const emitNode = getOrCreateEmitNode(parseNode);
emitNode.externalHelpers = true;
}
}
}
else {
// use a namespace import
const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(sourceFile, compilerOptions, hasExportStarsToExportValues, hasImportStar || hasImportDefault);
if (externalHelpersModuleName) {
namedBindings = createNamespaceImport(externalHelpersModuleName);
}
}
if (namedBindings) {
const externalHelpersImportDeclaration = createImportDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createImportClause(/*name*/ undefined, namedBindings),
createLiteral(externalHelpersModuleNameText)
);
addEmitFlags(externalHelpersImportDeclaration, EmitFlags.NeverApplyImportHelper);
return externalHelpersImportDeclaration;
}
}
}
export function getOrCreateExternalHelpersModuleNameIfNeeded(node: SourceFile, compilerOptions: CompilerOptions, hasExportStarsToExportValues?: boolean, hasImportStarOrImportDefault?: boolean) {
if (compilerOptions.importHelpers && isEffectiveExternalModule(node, compilerOptions)) {
const externalHelpersModuleName = getExternalHelpersModuleName(node);
+3
View File
@@ -665,6 +665,7 @@ namespace ts {
}
}
perfLogger.logStartResolveModule(moduleName /* , containingFile, ModuleResolutionKind[moduleResolution]*/);
switch (moduleResolution) {
case ModuleResolutionKind.NodeJs:
result = nodeModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference);
@@ -675,6 +676,8 @@ namespace ts {
default:
return Debug.fail(`Unexpected moduleResolution: ${moduleResolution}`);
}
if (result && result.resolvedModule) perfLogger.logInfoEvent(`Module "${moduleName}" resolved to "${result.resolvedModule.resolvedFileName}"`);
perfLogger.logStopResolveModule((result && result.resolvedModule) ? "" + result.resolvedModule.resolvedFileName : "null");
if (perFolderCache) {
perFolderCache.set(moduleName, result);
+6 -4
View File
@@ -93,7 +93,7 @@ namespace ts.moduleSpecifiers {
const info = getInfo(importingSourceFile.path, host);
const moduleSourceFile = getSourceFileOfNode(moduleSymbol.valueDeclaration || getNonAugmentationDeclaration(moduleSymbol));
const modulePaths = getAllModulePaths(files, importingSourceFile.path, moduleSourceFile.fileName, info.getCanonicalFileName, host, redirectTargetsMap);
const modulePaths = getAllModulePaths(files, importingSourceFile.path, moduleSourceFile.originalFileName, info.getCanonicalFileName, host, redirectTargetsMap);
const preferences = getPreferences(userPreferences, compilerOptions, importingSourceFile);
const global = mapDefined(modulePaths, moduleFileName => tryGetModuleNameAsNodeModule(moduleFileName, info, host, compilerOptions));
@@ -114,7 +114,7 @@ namespace ts.moduleSpecifiers {
function getLocalModuleSpecifier(moduleFileName: string, { getCanonicalFileName, sourceDirectory }: Info, compilerOptions: CompilerOptions, { ending, relativePreference }: Preferences): string {
const { baseUrl, paths, rootDirs } = compilerOptions;
const relativePath = rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName) ||
const relativePath = rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName, ending, compilerOptions) ||
removeExtensionAndIndexPostFix(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), ending, compilerOptions);
if (!baseUrl || relativePreference === RelativePreference.Relative) {
return relativePath;
@@ -248,7 +248,7 @@ namespace ts.moduleSpecifiers {
}
}
function tryGetModuleNameFromRootDirs(rootDirs: ReadonlyArray<string>, moduleFileName: string, sourceDirectory: string, getCanonicalFileName: (file: string) => string): string | undefined {
function tryGetModuleNameFromRootDirs(rootDirs: ReadonlyArray<string>, moduleFileName: string, sourceDirectory: string, getCanonicalFileName: (file: string) => string, ending: Ending, compilerOptions: CompilerOptions): string | undefined {
const normalizedTargetPath = getPathRelativeToRootDirs(moduleFileName, rootDirs, getCanonicalFileName);
if (normalizedTargetPath === undefined) {
return undefined;
@@ -256,7 +256,9 @@ namespace ts.moduleSpecifiers {
const normalizedSourcePath = getPathRelativeToRootDirs(sourceDirectory, rootDirs, getCanonicalFileName);
const relativePath = normalizedSourcePath !== undefined ? ensurePathIsNonModuleName(getRelativePathFromDirectory(normalizedSourcePath, normalizedTargetPath, getCanonicalFileName)) : normalizedTargetPath;
return removeFileExtension(relativePath);
return getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeJs
? removeExtensionAndIndexPostFix(relativePath, ending, compilerOptions)
: removeFileExtension(relativePath);
}
function tryGetModuleNameAsNodeModule(moduleFileName: string, { getCanonicalFileName, sourceDirectory }: Info, host: ModuleSpecifierResolutionHost, options: CompilerOptions): string | undefined {
+56 -7
View File
@@ -512,12 +512,16 @@ namespace ts {
export function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false, scriptKind?: ScriptKind): SourceFile {
performance.mark("beforeParse");
let result: SourceFile;
perfLogger.logStartParseSourceFile(fileName);
if (languageVersion === ScriptTarget.JSON) {
result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, ScriptKind.JSON);
}
else {
result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind);
}
perfLogger.logStopParseSourceFile();
performance.mark("afterParse");
performance.measure("Parse", "beforeParse", "afterParse");
return result;
@@ -605,6 +609,8 @@ namespace ts {
let parsingContext: ParsingContext;
let notParenthesizedArrow: Map<true> | undefined;
// Flags that dictate what parsing context we're in. For example:
// Whether or not we are in strict parsing mode. All that changes in strict parsing mode is
// that some tokens that would be considered identifiers may be considered keywords.
@@ -826,6 +832,7 @@ namespace ts {
identifiers = undefined!;
syntaxCursor = undefined;
sourceText = undefined!;
notParenthesizedArrow = undefined!;
}
function parseSourceFileWorker(fileName: string, languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind): SourceFile {
@@ -1079,10 +1086,19 @@ namespace ts {
return currentToken;
}
function nextToken(): SyntaxKind {
function nextTokenWithoutCheck() {
return currentToken = scanner.scan();
}
function nextToken(): SyntaxKind {
// if the keyword had an escape
if (isKeyword(currentToken) && (scanner.hasUnicodeEscape() || scanner.hasExtendedUnicodeEscape())) {
// issue a parse error for the escape
parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), Diagnostics.Keywords_cannot_contain_escape_characters);
}
return nextTokenWithoutCheck();
}
function nextTokenJSDoc(): JSDocSyntaxKind {
return currentToken = scanner.scanJsDocToken();
}
@@ -1373,7 +1389,7 @@ namespace ts {
node.originalKeywordKind = token();
}
node.escapedText = escapeLeadingUnderscores(internIdentifier(scanner.getTokenValue()));
nextToken();
nextTokenWithoutCheck();
return finishNode(node);
}
@@ -2428,6 +2444,25 @@ namespace ts {
function parseJSDocType(): TypeNode {
scanner.setInJSDocType(true);
const moduleSpecifier = parseOptionalToken(SyntaxKind.ModuleKeyword);
if (moduleSpecifier) {
const moduleTag = createNode(SyntaxKind.JSDocNamepathType, moduleSpecifier.pos) as JSDocNamepathType;
terminate: while (true) {
switch (token()) {
case SyntaxKind.CloseBraceToken:
case SyntaxKind.EndOfFileToken:
case SyntaxKind.CommaToken:
case SyntaxKind.WhitespaceTrivia:
break terminate;
default:
nextTokenJSDoc();
}
}
scanner.setInJSDocType(false);
return finishNode(moduleTag);
}
const dotdotdot = parseOptionalToken(SyntaxKind.DotDotDotToken);
let type = parseTypeOrTypePredicate();
scanner.setInJSDocType(false);
@@ -3676,7 +3711,17 @@ namespace ts {
}
function parsePossibleParenthesizedArrowFunctionExpressionHead(): ArrowFunction | undefined {
return parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity*/ false);
const tokenPos = scanner.getTokenPos();
if (notParenthesizedArrow && notParenthesizedArrow.has(tokenPos.toString())) {
return undefined;
}
const result = parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity*/ false);
if (!result) {
(notParenthesizedArrow || (notParenthesizedArrow = createMap())).set(tokenPos.toString(), true);
}
return result;
}
function tryParseAsyncSimpleArrowFunctionExpression(): ArrowFunction | undefined {
@@ -6417,7 +6462,7 @@ namespace ts {
export function parseIsolatedJSDocComment(content: string, start: number | undefined, length: number | undefined): { jsDoc: JSDoc, diagnostics: Diagnostic[] } | undefined {
initializeState(content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS);
sourceFile = <SourceFile>{ languageVariant: LanguageVariant.Standard, text: content }; // tslint:disable-line no-object-literal-type-assertion
const jsDoc = parseJSDocCommentWorker(start, length);
const jsDoc = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length));
const diagnostics = parseDiagnostics;
clearState();
@@ -6429,7 +6474,7 @@ namespace ts {
const saveParseDiagnosticsLength = parseDiagnostics.length;
const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode;
const comment = parseJSDocCommentWorker(start, length);
const comment = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length));
if (comment) {
comment.parent = parent;
}
@@ -6460,7 +6505,7 @@ namespace ts {
CallbackParameter = 1 << 2,
}
export function parseJSDocCommentWorker(start = 0, length: number | undefined): JSDoc | undefined {
function parseJSDocCommentWorker(start = 0, length: number | undefined): JSDoc | undefined {
const content = sourceText;
const end = length === undefined ? content.length : start + length;
length = end - start;
@@ -7288,10 +7333,14 @@ namespace ts {
return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ !message, message || Diagnostics.Identifier_expected);
}
identifierCount++;
const pos = scanner.getTokenPos();
const end = scanner.getTextPos();
const result = <Identifier>createNode(SyntaxKind.Identifier, pos);
result.escapedText = escapeLeadingUnderscores(scanner.getTokenText());
if (token() !== SyntaxKind.Identifier) {
result.originalKeywordKind = token();
}
result.escapedText = escapeLeadingUnderscores(internIdentifier(scanner.getTokenValue()));
finishNode(result, end);
nextTokenJSDoc();
+43
View File
@@ -0,0 +1,43 @@
/* @internal */
namespace ts {
type PerfLogger = typeof import("@microsoft/typescript-etw"); // tslint:disable-line:no-implicit-dependencies
const nullLogger: PerfLogger = {
logEvent: noop,
logErrEvent: noop,
logPerfEvent: noop,
logInfoEvent: noop,
logStartCommand: noop,
logStopCommand: noop,
logStartUpdateProgram: noop,
logStopUpdateProgram: noop,
logStartUpdateGraph: noop,
logStopUpdateGraph: noop,
logStartResolveModule: noop,
logStopResolveModule: noop,
logStartParseSourceFile: noop,
logStopParseSourceFile: noop,
logStartReadFile: noop,
logStopReadFile: noop,
logStartBindFile: noop,
logStopBindFile: noop,
logStartScheduledOperation: noop,
logStopScheduledOperation: noop,
};
// Load optional module to enable Event Tracing for Windows
// See https://github.com/microsoft/typescript-etw for more information
let etwModule;
try {
// require() will throw an exception if the module is not installed
// It may also return undefined if not installed properly
etwModule = require("@microsoft/typescript-etw"); // tslint:disable-line:no-implicit-dependencies
}
catch (e) {
etwModule = undefined;
}
/** Performance logger that will generate ETW events if possible */
export const perfLogger: PerfLogger = etwModule ? etwModule : nullLogger;
perfLogger.logInfoEvent(`Starting TypeScript v${versionMajorMinor} with command line: ${JSON.stringify(process.argv)}`);
}
+6 -3
View File
@@ -762,7 +762,7 @@ namespace ts {
let resolveModuleNamesWorker: (moduleNames: string[], containingFile: string, reusedNames?: string[], redirectedReference?: ResolvedProjectReference) => ResolvedModuleFull[];
const hasInvalidatedResolution = host.hasInvalidatedResolution || returnFalse;
if (host.resolveModuleNames) {
resolveModuleNamesWorker = (moduleNames, containingFile, reusedNames, redirectedReference) => host.resolveModuleNames!(Debug.assertEachDefined(moduleNames), containingFile, reusedNames, redirectedReference).map(resolved => {
resolveModuleNamesWorker = (moduleNames, containingFile, reusedNames, redirectedReference) => host.resolveModuleNames!(Debug.assertEachDefined(moduleNames), containingFile, reusedNames, redirectedReference, options).map(resolved => {
// An older host may have omitted extension, in which case we should infer it from the file extension of resolvedFileName.
if (!resolved || (resolved as ResolvedModuleFull).extension !== undefined) {
return resolved as ResolvedModuleFull;
@@ -780,7 +780,7 @@ namespace ts {
let resolveTypeReferenceDirectiveNamesWorker: (typeDirectiveNames: string[], containingFile: string, redirectedReference?: ResolvedProjectReference) => (ResolvedTypeReferenceDirective | undefined)[];
if (host.resolveTypeReferenceDirectives) {
resolveTypeReferenceDirectiveNamesWorker = (typeDirectiveNames, containingFile, redirectedReference) => host.resolveTypeReferenceDirectives!(Debug.assertEachDefined(typeDirectiveNames), containingFile, redirectedReference);
resolveTypeReferenceDirectiveNamesWorker = (typeDirectiveNames, containingFile, redirectedReference) => host.resolveTypeReferenceDirectives!(Debug.assertEachDefined(typeDirectiveNames), containingFile, redirectedReference, options);
}
else {
const loader = (typesRef: string, containingFile: string, redirectedReference: ResolvedProjectReference | undefined) => resolveTypeReferenceDirective(typesRef, containingFile, options, host, redirectedReference).resolvedTypeReferenceDirective!; // TODO: GH#18217
@@ -814,7 +814,10 @@ namespace ts {
let mapFromFileToProjectReferenceRedirects: Map<Path> | undefined;
const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options);
const structuralIsReused = tryReuseStructureFromOldProgram();
// We set `structuralIsReused` to `undefined` because `tryReuseStructureFromOldProgram` calls `tryReuseStructureFromOldProgram` which checks
// `structuralIsReused`, which would be a TDZ violation if it was not set in advance to `undefined`.
let structuralIsReused: StructureIsReused | undefined;
structuralIsReused = tryReuseStructureFromOldProgram();
if (structuralIsReused !== StructureIsReused.Completely) {
processingDefaultLibFiles = [];
processingOtherFiles = [];
+131 -29
View File
File diff suppressed because one or more lines are too long
+156 -51
View File
@@ -304,6 +304,53 @@ namespace ts {
}
}
/* @internal */
export function createSingleFileWatcherPerName(
watchFile: HostWatchFile,
useCaseSensitiveFileNames: boolean
): HostWatchFile {
interface SingleFileWatcher {
watcher: FileWatcher;
refCount: number;
}
const cache = createMap<SingleFileWatcher>();
const callbacksCache = createMultiMap<FileWatcherCallback>();
const toCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
return (fileName, callback, pollingInterval) => {
const path = toCanonicalFileName(fileName);
const existing = cache.get(path);
if (existing) {
existing.refCount++;
}
else {
cache.set(path, {
watcher: watchFile(
fileName,
(fileName, eventKind) => forEach(
callbacksCache.get(path),
cb => cb(fileName, eventKind)
),
pollingInterval
),
refCount: 1
});
}
callbacksCache.add(path, callback);
return {
close: () => {
const watcher = Debug.assertDefined(cache.get(path));
callbacksCache.remove(path, callback);
watcher.refCount--;
if (watcher.refCount) return;
cache.delete(path);
closeFileWatcherOf(watcher);
}
};
};
}
/**
* Returns true if file status changed
*/
@@ -332,6 +379,9 @@ namespace ts {
/*@internal*/
export const ignoredPaths = ["/node_modules/.", "/.git", "/.#"];
/*@internal*/
export let sysLog: (s: string) => void = noop;
/*@internal*/
export interface RecursiveDirectoryWatcherHost {
watchDirectory: HostWatchDirectory;
@@ -472,59 +522,81 @@ namespace ts {
}
}
/*@internal*/
export type BufferEncoding = "ascii" | "utf8" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "latin1" | "binary" | "hex";
/*@internal*/
interface NodeBuffer extends Uint8Array {
write(str: string, offset?: number, length?: number, encoding?: string): number;
constructor: any;
write(str: string, encoding?: BufferEncoding): number;
write(str: string, offset: number, encoding?: BufferEncoding): number;
write(str: string, offset: number, length: number, encoding?: BufferEncoding): number;
toString(encoding?: string, start?: number, end?: number): string;
toJSON(): { type: "Buffer", data: any[] };
equals(otherBuffer: Buffer): boolean;
compare(otherBuffer: Buffer, targetStart?: number, targetEnd?: number, sourceStart?: number, sourceEnd?: number): number;
copy(targetBuffer: Buffer, targetStart?: number, sourceStart?: number, sourceEnd?: number): number;
slice(start?: number, end?: number): Buffer;
writeUIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number;
writeUIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number;
writeIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number;
writeIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number;
readUIntLE(offset: number, byteLength: number, noAssert?: boolean): number;
readUIntBE(offset: number, byteLength: number, noAssert?: boolean): number;
readIntLE(offset: number, byteLength: number, noAssert?: boolean): number;
readIntBE(offset: number, byteLength: number, noAssert?: boolean): number;
readUInt8(offset: number, noAssert?: boolean): number;
readUInt16LE(offset: number, noAssert?: boolean): number;
readUInt16BE(offset: number, noAssert?: boolean): number;
readUInt32LE(offset: number, noAssert?: boolean): number;
readUInt32BE(offset: number, noAssert?: boolean): number;
readInt8(offset: number, noAssert?: boolean): number;
readInt16LE(offset: number, noAssert?: boolean): number;
readInt16BE(offset: number, noAssert?: boolean): number;
readInt32LE(offset: number, noAssert?: boolean): number;
readInt32BE(offset: number, noAssert?: boolean): number;
readFloatLE(offset: number, noAssert?: boolean): number;
readFloatBE(offset: number, noAssert?: boolean): number;
readDoubleLE(offset: number, noAssert?: boolean): number;
readDoubleBE(offset: number, noAssert?: boolean): number;
toJSON(): { type: "Buffer"; data: number[] };
equals(otherBuffer: Uint8Array): boolean;
compare(
otherBuffer: Uint8Array,
targetStart?: number,
targetEnd?: number,
sourceStart?: number,
sourceEnd?: number
): number;
copy(targetBuffer: Uint8Array, targetStart?: number, sourceStart?: number, sourceEnd?: number): number;
slice(begin?: number, end?: number): Buffer;
subarray(begin?: number, end?: number): Buffer;
writeUIntLE(value: number, offset: number, byteLength: number): number;
writeUIntBE(value: number, offset: number, byteLength: number): number;
writeIntLE(value: number, offset: number, byteLength: number): number;
writeIntBE(value: number, offset: number, byteLength: number): number;
readUIntLE(offset: number, byteLength: number): number;
readUIntBE(offset: number, byteLength: number): number;
readIntLE(offset: number, byteLength: number): number;
readIntBE(offset: number, byteLength: number): number;
readUInt8(offset: number): number;
readUInt16LE(offset: number): number;
readUInt16BE(offset: number): number;
readUInt32LE(offset: number): number;
readUInt32BE(offset: number): number;
readInt8(offset: number): number;
readInt16LE(offset: number): number;
readInt16BE(offset: number): number;
readInt32LE(offset: number): number;
readInt32BE(offset: number): number;
readFloatLE(offset: number): number;
readFloatBE(offset: number): number;
readDoubleLE(offset: number): number;
readDoubleBE(offset: number): number;
reverse(): this;
swap16(): Buffer;
swap32(): Buffer;
swap64(): Buffer;
writeUInt8(value: number, offset: number, noAssert?: boolean): number;
writeUInt16LE(value: number, offset: number, noAssert?: boolean): number;
writeUInt16BE(value: number, offset: number, noAssert?: boolean): number;
writeUInt32LE(value: number, offset: number, noAssert?: boolean): number;
writeUInt32BE(value: number, offset: number, noAssert?: boolean): number;
writeInt8(value: number, offset: number, noAssert?: boolean): number;
writeInt16LE(value: number, offset: number, noAssert?: boolean): number;
writeInt16BE(value: number, offset: number, noAssert?: boolean): number;
writeInt32LE(value: number, offset: number, noAssert?: boolean): number;
writeInt32BE(value: number, offset: number, noAssert?: boolean): number;
writeFloatLE(value: number, offset: number, noAssert?: boolean): number;
writeFloatBE(value: number, offset: number, noAssert?: boolean): number;
writeDoubleLE(value: number, offset: number, noAssert?: boolean): number;
writeDoubleBE(value: number, offset: number, noAssert?: boolean): number;
fill(value: any, offset?: number, end?: number): this;
indexOf(value: string | number | Buffer, byteOffset?: number, encoding?: string): number;
lastIndexOf(value: string | number | Buffer, byteOffset?: number, encoding?: string): number;
writeUInt8(value: number, offset: number): number;
writeUInt16LE(value: number, offset: number): number;
writeUInt16BE(value: number, offset: number): number;
writeUInt32LE(value: number, offset: number): number;
writeUInt32BE(value: number, offset: number): number;
writeInt8(value: number, offset: number): number;
writeInt16LE(value: number, offset: number): number;
writeInt16BE(value: number, offset: number): number;
writeInt32LE(value: number, offset: number): number;
writeInt32BE(value: number, offset: number): number;
writeFloatLE(value: number, offset: number): number;
writeFloatBE(value: number, offset: number): number;
writeDoubleLE(value: number, offset: number): number;
writeDoubleBE(value: number, offset: number): number;
readBigUInt64BE(offset?: number): bigint;
readBigUInt64LE(offset?: number): bigint;
readBigInt64BE(offset?: number): bigint;
readBigInt64LE(offset?: number): bigint;
writeBigInt64BE(value: bigint, offset?: number): number;
writeBigInt64LE(value: bigint, offset?: number): number;
writeBigUInt64BE(value: bigint, offset?: number): number;
writeBigUInt64LE(value: bigint, offset?: number): number;
fill(value: string | Uint8Array | number, offset?: number, end?: number, encoding?: BufferEncoding): this;
indexOf(value: string | number | Uint8Array, byteOffset?: number, encoding?: BufferEncoding): number;
lastIndexOf(value: string | number | Uint8Array, byteOffset?: number, encoding?: BufferEncoding): number;
entries(): IterableIterator<[number, number]>;
includes(value: string | number | Buffer, byteOffset?: number, encoding?: string): boolean;
includes(value: string | number | Buffer, byteOffset?: number, encoding?: BufferEncoding): boolean;
keys(): IterableIterator<number>;
values(): IterableIterator<number>;
}
@@ -661,6 +733,7 @@ namespace ts {
const nodeVersion = getNodeMajorVersion();
const isNode4OrLater = nodeVersion! >= 4;
const isLinuxOrMacOs = process.platform === "linux" || process.platform === "darwin";
const platform: string = _os.platform();
const useCaseSensitiveFileNames = isFileSystemCaseSensitive();
@@ -673,6 +746,7 @@ namespace ts {
const useNonPollingWatchers = process.env.TSC_NONPOLLING_WATCHER;
const tscWatchFile = process.env.TSC_WATCHFILE;
const tscWatchDirectory = process.env.TSC_WATCHDIRECTORY;
const fsWatchFile = createSingleFileWatcherPerName(fsWatchFileWorker, useCaseSensitiveFileNames);
let dynamicPollingWatchFile: HostWatchFile | undefined;
const nodeSystem: System = {
args: process.argv.slice(2),
@@ -813,7 +887,7 @@ namespace ts {
return useNonPollingWatchers ?
createNonPollingWatchFile() :
// Default to do not use polling interval as it is before this experiment branch
(fileName, callback) => fsWatchFile(fileName, callback);
(fileName, callback) => fsWatchFile(fileName, callback, /*pollingInterval*/ undefined);
}
function getWatchDirectory(): HostWatchDirectory {
@@ -894,7 +968,7 @@ namespace ts {
}
}
function fsWatchFile(fileName: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher {
function fsWatchFileWorker(fileName: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher {
_fs.watchFile(fileName, { persistent: true, interval: pollingInterval || 250 }, fileChanged);
let eventKind: FileWatcherEventKind;
return {
@@ -959,6 +1033,12 @@ namespace ts {
function fsWatch(fileOrDirectory: string, entryKind: FileSystemEntryKind.File | FileSystemEntryKind.Directory, callback: FsWatchCallback, recursive: boolean, fallbackPollingWatchFile: HostWatchFile, pollingInterval?: number): FileWatcher {
let options: any;
let lastDirectoryPartWithDirectorySeparator: string | undefined;
let lastDirectoryPart: string | undefined;
if (isLinuxOrMacOs) {
lastDirectoryPartWithDirectorySeparator = fileOrDirectory.substr(fileOrDirectory.lastIndexOf(directorySeparator));
lastDirectoryPart = lastDirectoryPartWithDirectorySeparator.slice(directorySeparator.length);
}
/** Watcher for the file system entry depending on whether it is missing or present */
let watcher = !fileSystemEntryExists(fileOrDirectory, entryKind) ?
watchMissingFileSystemEntry() :
@@ -976,6 +1056,7 @@ namespace ts {
* @param createWatcher
*/
function invokeCallbackAndUpdateWatcher(createWatcher: () => FileWatcher) {
sysLog(`sysLog:: ${fileOrDirectory}:: Changing watcher to ${createWatcher === watchPresentFileSystemEntry ? "Present" : "Missing"}FileSystemEntryWatcher`);
// Call the callback for current directory
callback("rename", "");
@@ -1002,11 +1083,12 @@ namespace ts {
}
}
try {
const presentWatcher = _fs.watch(
fileOrDirectory,
options,
callback
isLinuxOrMacOs ?
callbackChangingToMissingFileSystemEntry :
callback
);
// Watch the missing file or directory or error
presentWatcher.on("error", () => invokeCallbackAndUpdateWatcher(watchMissingFileSystemEntry));
@@ -1020,11 +1102,24 @@ namespace ts {
}
}
function callbackChangingToMissingFileSystemEntry(event: "rename" | "change", relativeName: string | undefined) {
// because relativeName is not guaranteed to be correct we need to check on each rename with few combinations
// Eg on ubuntu while watching app/node_modules the relativeName is "node_modules" which is neither relative nor full path
return event === "rename" &&
(!relativeName ||
relativeName === lastDirectoryPart ||
relativeName.lastIndexOf(lastDirectoryPartWithDirectorySeparator!) === relativeName.length - lastDirectoryPartWithDirectorySeparator!.length) &&
!fileSystemEntryExists(fileOrDirectory, entryKind) ?
invokeCallbackAndUpdateWatcher(watchMissingFileSystemEntry) :
callback(event, relativeName);
}
/**
* Watch the file or directory using fs.watchFile since fs.watch threw exception
* Eg. on linux the number of watches are limited and one could easily exhaust watches and the exception ENOSPC is thrown when creating watcher at that point
*/
function watchPresentFileSystemEntryWithFsWatchFile(): FileWatcher {
sysLog(`sysLog:: ${fileOrDirectory}:: Changing to fsWatchFile`);
return fallbackPollingWatchFile(fileOrDirectory, createFileWatcherCallback(callback), pollingInterval);
}
@@ -1064,7 +1159,7 @@ namespace ts {
return (directoryName, callback) => fsWatchFile(directoryName, () => callback(directoryName), PollingInterval.Medium);
}
function readFile(fileName: string, _encoding?: string): string | undefined {
function readFileWorker(fileName: string, _encoding?: string): string | undefined {
if (!fileExists(fileName)) {
return undefined;
}
@@ -1093,7 +1188,15 @@ namespace ts {
return buffer.toString("utf8");
}
function readFile(fileName: string, _encoding?: string): string | undefined {
perfLogger.logStartReadFile(fileName);
const file = readFileWorker(fileName, _encoding);
perfLogger.logStopReadFile();
return file;
}
function writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void {
perfLogger.logEvent("WriteFile: " + fileName);
// If a BOM is required, emit one
if (writeByteOrderMark) {
data = byteOrderMarkIndicator + data;
@@ -1113,6 +1216,7 @@ namespace ts {
}
function getAccessibleFileSystemEntries(path: string): FileSystemEntries {
perfLogger.logEvent("ReadDir: " + (path || "."));
try {
const entries = _fs.readdirSync(path || ".").sort();
const files: string[] = [];
@@ -1174,6 +1278,7 @@ namespace ts {
}
function getDirectories(path: string): string[] {
perfLogger.logEvent("ReadDir: " + path);
return filter<string>(_fs.readdirSync(path), dir => fileSystemEntryExists(combinePaths(path, dir), FileSystemEntryKind.Directory));
}
+82 -15
View File
@@ -83,6 +83,7 @@ namespace ts {
let currentSourceFile: SourceFile;
let refs: Map<SourceFile>;
let libs: Map<boolean>;
let emittedImports: readonly AnyImportSyntax[] | undefined; // must be declared in container so it can be `undefined` while transformer's first pass
const resolver = context.getEmitResolver();
const options = context.getCompilerOptions();
const newLine = getNewLineCharacter(options);
@@ -279,7 +280,7 @@ namespace ts {
const statements = visitNodes(node.statements, visitDeclarationStatements);
let combinedStatements = setTextRange(createNodeArray(transformAndReplaceLatePaintedStatements(statements)), node.statements);
refs.forEach(referenceVisitor);
const emittedImports = filter(combinedStatements, isAnyImportSyntax);
emittedImports = filter(combinedStatements, isAnyImportSyntax);
if (isExternalModule(node) && (!resultHasExternalModuleIndicator || (needsScopeFixMarker && !resultHasScopeMarker))) {
combinedStatements = setTextRange(createNodeArray([...combinedStatements, createEmptyExports()]), combinedStatements);
}
@@ -392,7 +393,7 @@ namespace ts {
}
}
function ensureParameter(p: ParameterDeclaration, modifierMask?: ModifierFlags): ParameterDeclaration {
function ensureParameter(p: ParameterDeclaration, modifierMask?: ModifierFlags, type?: TypeNode): ParameterDeclaration {
let oldDiag: typeof getSymbolAccessibilityDiagnostic | undefined;
if (!suppressNewDiagnosticContexts) {
oldDiag = getSymbolAccessibilityDiagnostic;
@@ -405,7 +406,7 @@ namespace ts {
p.dotDotDotToken,
filterBindingPatternInitializers(p.name),
resolver.isOptionalParameter(p) ? (p.questionToken || createToken(SyntaxKind.QuestionToken)) : undefined,
ensureType(p, p.type, /*ignorePrivate*/ true), // Ignore private param props, since this type is going straight back into a param
ensureType(p, type || p.type, /*ignorePrivate*/ true), // Ignore private param props, since this type is going straight back into a param
ensureNoInitializer(p)
);
if (!suppressNewDiagnosticContexts) {
@@ -534,6 +535,36 @@ namespace ts {
return createNodeArray(newParams, params.hasTrailingComma);
}
function updateAccessorParamsList(input: AccessorDeclaration, isPrivate: boolean) {
let newParams: ParameterDeclaration[] | undefined;
if (!isPrivate) {
const thisParameter = getThisParameter(input);
if (thisParameter) {
newParams = [ensureParameter(thisParameter)];
}
}
if (isSetAccessorDeclaration(input)) {
let newValueParameter: ParameterDeclaration | undefined;
if (!isPrivate) {
const valueParameter = getSetAccessorValueParameter(input);
if (valueParameter) {
const accessorType = getTypeAnnotationFromAllAccessorDeclarations(input, resolver.getAllAccessorDeclarations(input));
newValueParameter = ensureParameter(valueParameter, /*modifierMask*/ undefined, accessorType);
}
}
if (!newValueParameter) {
newValueParameter = createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
"value"
);
}
newParams = append(newParams, newValueParameter);
}
return createNodeArray(newParams || emptyArray) as NodeArray<ParameterDeclaration>;
}
function ensureTypeParams(node: Node, params: NodeArray<TypeParameterDeclaration> | undefined) {
return hasModifier(node, ModifierFlags.Private) ? undefined : visitNodes(params, visitDeclarationSubtree);
}
@@ -736,6 +767,12 @@ namespace ts {
}
const oldDiag = getSymbolAccessibilityDiagnostic;
// Setup diagnostic-related flags before first potential `cleanup` call, otherwise
// We'd see a TDZ violation at runtime
const canProduceDiagnostic = canProduceDiagnostics(input);
const oldWithinObjectLiteralType = suppressNewDiagnosticContexts;
let shouldEnterSuppressNewDiagnosticsContextContext = ((input.kind === SyntaxKind.TypeLiteral || input.kind === SyntaxKind.MappedType) && input.parent.kind !== SyntaxKind.TypeAliasDeclaration);
// Emit methods which are private as properties with no type information
if (isMethodDeclaration(input) || isMethodSignature(input)) {
if (hasModifier(input, ModifierFlags.Private)) {
@@ -744,8 +781,7 @@ namespace ts {
}
}
const canProdiceDiagnostic = canProduceDiagnostics(input);
if (canProdiceDiagnostic && !suppressNewDiagnosticContexts) {
if (canProduceDiagnostic && !suppressNewDiagnosticContexts) {
getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(input as DeclarationDiagnosticProducing);
}
@@ -753,8 +789,6 @@ namespace ts {
checkEntityNameVisibility(input.exprName, enclosingDeclaration);
}
const oldWithinObjectLiteralType = suppressNewDiagnosticContexts;
let shouldEnterSuppressNewDiagnosticsContextContext = ((input.kind === SyntaxKind.TypeLiteral || input.kind === SyntaxKind.MappedType) && input.parent.kind !== SyntaxKind.TypeAliasDeclaration);
if (shouldEnterSuppressNewDiagnosticsContextContext) {
// We stop making new diagnostic contexts within object literal types. Unless it's an object type on the RHS of a type alias declaration. Then we do.
suppressNewDiagnosticContexts = true;
@@ -807,10 +841,33 @@ namespace ts {
return cleanup(sig);
}
case SyntaxKind.GetAccessor: {
// For now, only emit class accessors as accessors if they were already declared in an ambient context.
if (input.flags & NodeFlags.Ambient) {
const isPrivate = hasModifier(input, ModifierFlags.Private);
const accessorType = getTypeAnnotationFromAllAccessorDeclarations(input, resolver.getAllAccessorDeclarations(input));
return cleanup(updateGetAccessor(
input,
/*decorators*/ undefined,
ensureModifiers(input),
input.name,
updateAccessorParamsList(input, isPrivate),
!isPrivate ? ensureType(input, accessorType) : undefined,
/*body*/ undefined));
}
const newNode = ensureAccessor(input);
return cleanup(newNode);
}
case SyntaxKind.SetAccessor: {
// For now, only emit class accessors as accessors if they were already declared in an ambient context.
if (input.flags & NodeFlags.Ambient) {
return cleanup(updateSetAccessor(
input,
/*decorators*/ undefined,
ensureModifiers(input),
input.name,
updateAccessorParamsList(input, hasModifier(input, ModifierFlags.Private)),
/*body*/ undefined));
}
const newNode = ensureAccessor(input);
return cleanup(newNode);
}
@@ -909,13 +966,13 @@ namespace ts {
return cleanup(visitEachChild(input, visitDeclarationSubtree, context));
function cleanup<T extends Node>(returnValue: T | undefined): T | undefined {
if (returnValue && canProdiceDiagnostic && hasDynamicName(input as Declaration)) {
if (returnValue && canProduceDiagnostic && hasDynamicName(input as Declaration)) {
checkName(input as DeclarationDiagnosticProducing);
}
if (isEnclosingDeclaration(input)) {
enclosingDeclaration = previousEnclosingDeclaration;
}
if (canProdiceDiagnostic && !suppressNewDiagnosticContexts) {
if (canProduceDiagnostic && !suppressNewDiagnosticContexts) {
getSymbolAccessibilityDiagnostic = oldDiag;
}
if (shouldEnterSuppressNewDiagnosticsContextContext) {
@@ -1370,17 +1427,27 @@ namespace ts {
return maskModifierFlags(node, mask, additions);
}
function getTypeAnnotationFromAllAccessorDeclarations(node: AccessorDeclaration, accessors: AllAccessorDeclarations) {
let accessorType = getTypeAnnotationFromAccessor(node);
if (!accessorType && node !== accessors.firstAccessor) {
accessorType = getTypeAnnotationFromAccessor(accessors.firstAccessor);
// If we end up pulling the type from the second accessor, we also need to change the diagnostic context to get the expected error message
getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(accessors.firstAccessor);
}
if (!accessorType && accessors.secondAccessor && node !== accessors.secondAccessor) {
accessorType = getTypeAnnotationFromAccessor(accessors.secondAccessor);
// If we end up pulling the type from the second accessor, we also need to change the diagnostic context to get the expected error message
getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(accessors.secondAccessor);
}
return accessorType;
}
function ensureAccessor(node: AccessorDeclaration): PropertyDeclaration | undefined {
const accessors = resolver.getAllAccessorDeclarations(node);
if (node.kind !== accessors.firstAccessor.kind) {
return;
}
let accessorType = getTypeAnnotationFromAccessor(node);
if (!accessorType && accessors.secondAccessor) {
accessorType = getTypeAnnotationFromAccessor(accessors.secondAccessor);
// If we end up pulling the type from the second accessor, we also need to change the diagnostic context to get the expected error message
getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(accessors.secondAccessor);
}
const accessorType = getTypeAnnotationFromAllAccessorDeclarations(node, accessors);
const prop = createProperty(/*decorators*/ undefined, maskModifiers(node, /*mask*/ undefined, (!accessors.setAccessor) ? ModifierFlags.Readonly : ModifierFlags.None), node.name, node.questionToken, ensureType(node, accessorType), /*initializer*/ undefined);
const leadingsSyntheticCommentRanges = accessors.secondAccessor && getLeadingCommentRangesOfNode(accessors.secondAccessor, currentSourceFile);
if (leadingsSyntheticCommentRanges) {
+2 -1
View File
@@ -514,6 +514,7 @@ namespace ts {
export const restHelper: UnscopedEmitHelper = {
name: "typescript:rest",
importName: "__rest",
scoped: false,
text: `
var __rest = (this && this.__rest) || function (s, e) {
@@ -557,7 +558,7 @@ namespace ts {
}
}
return createCall(
getHelperName("__rest"),
getUnscopedHelperName("__rest"),
/*typeArguments*/ undefined,
[
value,
+4 -2
View File
@@ -4339,7 +4339,7 @@ namespace ts {
function createExtendsHelper(context: TransformationContext, name: Identifier) {
context.requestEmitHelper(extendsHelper);
return createCall(
getHelperName("__extends"),
getUnscopedHelperName("__extends"),
/*typeArguments*/ undefined,
[
name,
@@ -4351,7 +4351,7 @@ namespace ts {
function createTemplateObjectHelper(context: TransformationContext, cooked: ArrayLiteralExpression, raw: ArrayLiteralExpression) {
context.requestEmitHelper(templateObjectHelper);
return createCall(
getHelperName("__makeTemplateObject"),
getUnscopedHelperName("__makeTemplateObject"),
/*typeArguments*/ undefined,
[
cooked,
@@ -4362,6 +4362,7 @@ namespace ts {
export const extendsHelper: UnscopedEmitHelper = {
name: "typescript:extends",
importName: "__extends",
scoped: false,
priority: 0,
text: `
@@ -4383,6 +4384,7 @@ namespace ts {
export const templateObjectHelper: UnscopedEmitHelper = {
name: "typescript:makeTemplateObject",
importName: "__makeTemplateObject",
scoped: false,
priority: 0,
text: `
+35 -7
View File
@@ -41,6 +41,8 @@ namespace ts {
/** A set of node IDs for generated super accessors (variable statements). */
const substitutedSuperAccessors: boolean[] = [];
let topLevel: boolean;
// Save the previous transformation hooks.
const previousOnEmitNode = context.onEmitNode;
const previousOnSubstituteNode = context.onSubstituteNode;
@@ -56,11 +58,26 @@ namespace ts {
return node;
}
topLevel = isEffectiveStrictModeSourceFile(node, compilerOptions);
const visited = visitEachChild(node, visitor, context);
addEmitHelpers(visited, context.readEmitHelpers());
return visited;
}
function doOutsideOfTopLevel<T, U>(cb: (value: T) => U, value: T) {
if (topLevel) {
topLevel = false;
const result = cb(value);
topLevel = true;
return result;
}
return cb(value);
}
function visitDefault(node: Node): VisitResult<Node> {
return visitEachChild(node, visitor, context);
}
function visitor(node: Node): VisitResult<Node> {
if ((node.transformFlags & TransformFlags.ContainsES2017) === 0) {
return node;
@@ -74,13 +91,13 @@ namespace ts {
return visitAwaitExpression(<AwaitExpression>node);
case SyntaxKind.MethodDeclaration:
return visitMethodDeclaration(<MethodDeclaration>node);
return doOutsideOfTopLevel(visitMethodDeclaration, <MethodDeclaration>node);
case SyntaxKind.FunctionDeclaration:
return visitFunctionDeclaration(<FunctionDeclaration>node);
return doOutsideOfTopLevel(visitFunctionDeclaration, <FunctionDeclaration>node);
case SyntaxKind.FunctionExpression:
return visitFunctionExpression(<FunctionExpression>node);
return doOutsideOfTopLevel(visitFunctionExpression, <FunctionExpression>node);
case SyntaxKind.ArrowFunction:
return visitArrowFunction(<ArrowFunction>node);
@@ -97,6 +114,13 @@ namespace ts {
}
return visitEachChild(node, visitor, context);
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.Constructor:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
return doOutsideOfTopLevel(visitDefault, node);
default:
return visitEachChild(node, visitor, context);
}
@@ -433,6 +457,7 @@ namespace ts {
createReturn(
createAwaiterHelper(
context,
!topLevel,
hasLexicalArguments,
promiseConstructor,
transformAsyncFunctionBodyWorker(<Block>node.body, statementOffset)
@@ -473,6 +498,7 @@ namespace ts {
else {
const expression = createAwaiterHelper(
context,
!topLevel,
hasLexicalArguments,
promiseConstructor,
transformAsyncFunctionBodyWorker(node.body!)
@@ -771,20 +797,22 @@ namespace ts {
export const awaiterHelper: UnscopedEmitHelper = {
name: "typescript:awaiter",
importName: "__awaiter",
scoped: false,
priority: 5,
text: `
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};`
};
function createAwaiterHelper(context: TransformationContext, hasLexicalArguments: boolean, promiseConstructor: EntityName | Expression | undefined, body: Block) {
function createAwaiterHelper(context: TransformationContext, hasLexicalThis: boolean, hasLexicalArguments: boolean, promiseConstructor: EntityName | Expression | undefined, body: Block) {
context.requestEmitHelper(awaiterHelper);
const generatorFunc = createFunctionExpression(
@@ -801,10 +829,10 @@ namespace ts {
(generatorFunc.emitNode || (generatorFunc.emitNode = {} as EmitNode)).flags |= EmitFlags.AsyncFunctionBody | EmitFlags.ReuseTempVariableScope;
return createCall(
getHelperName("__awaiter"),
getUnscopedHelperName("__awaiter"),
/*typeArguments*/ undefined,
[
createThis(),
hasLexicalThis ? createThis() : createVoidZero(),
hasLexicalArguments ? createIdentifier("arguments") : createVoidZero(),
promiseConstructor ? createExpressionFromEntityName(promiseConstructor) : createVoidZero(),
generatorFunc
+96 -18
View File
@@ -22,9 +22,11 @@ namespace ts {
const previousOnSubstituteNode = context.onSubstituteNode;
context.onSubstituteNode = onSubstituteNode;
let exportedVariableStatement = false;
let enabledSubstitutions: ESNextSubstitutionFlags;
let enclosingFunctionFlags: FunctionFlags;
let enclosingSuperContainerFlags: NodeCheckFlags = 0;
let topLevel: boolean;
/** Keeps track of property names accessed on super (`super.x`) within async functions. */
let capturedSuperProperties: UnderscoreEscapedMap<true>;
@@ -40,6 +42,8 @@ namespace ts {
return node;
}
exportedVariableStatement = false;
topLevel = isEffectiveStrictModeSourceFile(node, compilerOptions);
const visited = visitEachChild(node, visitor, context);
addEmitHelpers(visited, context.readEmitHelpers());
return visited;
@@ -60,6 +64,20 @@ namespace ts {
return node;
}
function doOutsideOfTopLevel<T, U>(cb: (value: T) => U, value: T) {
if (topLevel) {
topLevel = false;
const result = cb(value);
topLevel = true;
return result;
}
return cb(value);
}
function visitDefault(node: Node): VisitResult<Node> {
return visitEachChild(node, visitor, context);
}
function visitorWorker(node: Node, noDestructuringValue: boolean): VisitResult<Node> {
if ((node.transformFlags & TransformFlags.ContainsES2018) === 0) {
return node;
@@ -79,6 +97,8 @@ namespace ts {
return visitBinaryExpression(node as BinaryExpression, noDestructuringValue);
case SyntaxKind.CatchClause:
return visitCatchClause(node as CatchClause);
case SyntaxKind.VariableStatement:
return visitVariableStatement(node as VariableStatement);
case SyntaxKind.VariableDeclaration:
return visitVariableDeclaration(node as VariableDeclaration);
case SyntaxKind.ForOfStatement:
@@ -88,17 +108,17 @@ namespace ts {
case SyntaxKind.VoidExpression:
return visitVoidExpression(node as VoidExpression);
case SyntaxKind.Constructor:
return visitConstructorDeclaration(node as ConstructorDeclaration);
return doOutsideOfTopLevel(visitConstructorDeclaration, node as ConstructorDeclaration);
case SyntaxKind.MethodDeclaration:
return visitMethodDeclaration(node as MethodDeclaration);
return doOutsideOfTopLevel(visitMethodDeclaration, node as MethodDeclaration);
case SyntaxKind.GetAccessor:
return visitGetAccessorDeclaration(node as GetAccessorDeclaration);
return doOutsideOfTopLevel(visitGetAccessorDeclaration, node as GetAccessorDeclaration);
case SyntaxKind.SetAccessor:
return visitSetAccessorDeclaration(node as SetAccessorDeclaration);
return doOutsideOfTopLevel(visitSetAccessorDeclaration, node as SetAccessorDeclaration);
case SyntaxKind.FunctionDeclaration:
return visitFunctionDeclaration(node as FunctionDeclaration);
return doOutsideOfTopLevel(visitFunctionDeclaration, node as FunctionDeclaration);
case SyntaxKind.FunctionExpression:
return visitFunctionExpression(node as FunctionExpression);
return doOutsideOfTopLevel(visitFunctionExpression, node as FunctionExpression);
case SyntaxKind.ArrowFunction:
return visitArrowFunction(node as ArrowFunction);
case SyntaxKind.Parameter:
@@ -117,6 +137,9 @@ namespace ts {
hasSuperElementAccess = true;
}
return visitEachChild(node, visitor, context);
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
return doOutsideOfTopLevel(visitDefault, node);
default:
return visitEachChild(node, visitor, context);
}
@@ -229,14 +252,39 @@ namespace ts {
if (node.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
// spread elements emit like so:
// non-spread elements are chunked together into object literals, and then all are passed to __assign:
// { a, ...o, b } => __assign({a}, o, {b});
// { a, ...o, b } => __assign(__assign({a}, o), {b});
// If the first element is a spread element, then the first argument to __assign is {}:
// { ...o, a, b, ...o2 } => __assign({}, o, {a, b}, o2)
// { ...o, a, b, ...o2 } => __assign(__assign(__assign({}, o), {a, b}), o2)
//
// We cannot call __assign with more than two elements, since any element could cause side effects. For
// example:
// var k = { a: 1, b: 2 };
// var o = { a: 3, ...k, b: k.a++ };
// // expected: { a: 1, b: 1 }
// If we translate the above to `__assign({ a: 3 }, k, { b: k.a++ })`, the `k.a++` will evaluate before
// `k` is spread and we end up with `{ a: 2, b: 1 }`.
//
// This also occurs for spread elements, not just property assignments:
// var k = { a: 1, get b() { l = { z: 9 }; return 2; } };
// var l = { c: 3 };
// var o = { ...k, ...l };
// // expected: { a: 1, b: 2, z: 9 }
// If we translate the above to `__assign({}, k, l)`, the `l` will evaluate before `k` is spread and we
// end up with `{ a: 1, b: 2, c: 3 }`
const objects = chunkObjectLiteralElements(node.properties);
if (objects.length && objects[0].kind !== SyntaxKind.ObjectLiteralExpression) {
objects.unshift(createObjectLiteral());
}
return createAssignHelper(context, objects);
let expression: Expression = objects[0];
if (objects.length > 1) {
for (let i = 1; i < objects.length; i++) {
expression = createAssignHelper(context, [expression, objects[i]]);
}
return expression;
}
else {
return createAssignHelper(context, objects);
}
}
return visitEachChild(node, visitor, context);
}
@@ -296,19 +344,43 @@ namespace ts {
return visitEachChild(node, visitor, context);
}
function visitVariableStatement(node: VariableStatement): VisitResult<VariableStatement> {
if (hasModifier(node, ModifierFlags.Export)) {
const savedExportedVariableStatement = exportedVariableStatement;
exportedVariableStatement = true;
const visited = visitEachChild(node, visitor, context);
exportedVariableStatement = savedExportedVariableStatement;
return visited;
}
return visitEachChild(node, visitor, context);
}
/**
* Visits a VariableDeclaration node with a binding pattern.
*
* @param node A VariableDeclaration node.
*/
function visitVariableDeclaration(node: VariableDeclaration): VisitResult<VariableDeclaration> {
if (exportedVariableStatement) {
const savedExportedVariableStatement = exportedVariableStatement;
exportedVariableStatement = false;
const visited = visitVariableDeclarationWorker(node, /*exportedVariableStatement*/ true);
exportedVariableStatement = savedExportedVariableStatement;
return visited;
}
return visitVariableDeclarationWorker(node, /*exportedVariableStatement*/ false);
}
function visitVariableDeclarationWorker(node: VariableDeclaration, exportedVariableStatement: boolean): VisitResult<VariableDeclaration> {
// If we are here it is because the name contains a binding pattern with a rest somewhere in it.
if (isBindingPattern(node.name) && node.name.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
return flattenDestructuringBinding(
node,
visitor,
context,
FlattenLevel.ObjectRest
FlattenLevel.ObjectRest,
/*rval*/ undefined,
exportedVariableStatement
);
}
return visitEachChild(node, visitor, context);
@@ -701,7 +773,8 @@ namespace ts {
node.body!,
visitLexicalEnvironment(node.body!.statements, visitor, context, statementOffset)
)
)
),
!topLevel
)
);
@@ -942,6 +1015,7 @@ namespace ts {
export const assignHelper: UnscopedEmitHelper = {
name: "typescript:assign",
importName: "__assign",
scoped: false,
priority: 1,
text: `
@@ -966,7 +1040,7 @@ namespace ts {
}
context.requestEmitHelper(assignHelper);
return createCall(
getHelperName("__assign"),
getUnscopedHelperName("__assign"),
/*typeArguments*/ undefined,
attributesSegments
);
@@ -974,6 +1048,7 @@ namespace ts {
export const awaitHelper: UnscopedEmitHelper = {
name: "typescript:await",
importName: "__await",
scoped: false,
text: `
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }`
@@ -981,11 +1056,12 @@ namespace ts {
function createAwaitHelper(context: TransformationContext, expression: Expression) {
context.requestEmitHelper(awaitHelper);
return createCall(getHelperName("__await"), /*typeArguments*/ undefined, [expression]);
return createCall(getUnscopedHelperName("__await"), /*typeArguments*/ undefined, [expression]);
}
export const asyncGeneratorHelper: UnscopedEmitHelper = {
name: "typescript:asyncGenerator",
importName: "__asyncGenerator",
scoped: false,
text: `
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
@@ -1001,7 +1077,7 @@ namespace ts {
};`
};
function createAsyncGeneratorHelper(context: TransformationContext, generatorFunc: FunctionExpression) {
function createAsyncGeneratorHelper(context: TransformationContext, generatorFunc: FunctionExpression, hasLexicalThis: boolean) {
context.requestEmitHelper(awaitHelper);
context.requestEmitHelper(asyncGeneratorHelper);
@@ -1009,10 +1085,10 @@ namespace ts {
(generatorFunc.emitNode || (generatorFunc.emitNode = {} as EmitNode)).flags |= EmitFlags.AsyncFunctionBody;
return createCall(
getHelperName("__asyncGenerator"),
getUnscopedHelperName("__asyncGenerator"),
/*typeArguments*/ undefined,
[
createThis(),
hasLexicalThis ? createThis() : createVoidZero(),
createIdentifier("arguments"),
generatorFunc
]
@@ -1021,6 +1097,7 @@ namespace ts {
export const asyncDelegator: UnscopedEmitHelper = {
name: "typescript:asyncDelegator",
importName: "__asyncDelegator",
scoped: false,
text: `
var __asyncDelegator = (this && this.__asyncDelegator) || function (o) {
@@ -1035,7 +1112,7 @@ namespace ts {
context.requestEmitHelper(asyncDelegator);
return setTextRange(
createCall(
getHelperName("__asyncDelegator"),
getUnscopedHelperName("__asyncDelegator"),
/*typeArguments*/ undefined,
[expression]
),
@@ -1045,6 +1122,7 @@ namespace ts {
export const asyncValues: UnscopedEmitHelper = {
name: "typescript:asyncValues",
importName: "__asyncValues",
scoped: false,
text: `
var __asyncValues = (this && this.__asyncValues) || function (o) {
@@ -1060,7 +1138,7 @@ namespace ts {
context.requestEmitHelper(asyncValues);
return setTextRange(
createCall(
getHelperName("__asyncValues"),
getUnscopedHelperName("__asyncValues"),
/*typeArguments*/ undefined,
[expression]
),
+2 -1
View File
@@ -3176,7 +3176,7 @@ namespace ts {
function createGeneratorHelper(context: TransformationContext, body: FunctionExpression) {
context.requestEmitHelper(generatorHelper);
return createCall(
getHelperName("__generator"),
getUnscopedHelperName("__generator"),
/*typeArguments*/ undefined,
[createThis(), body]);
}
@@ -3242,6 +3242,7 @@ namespace ts {
// For examples of how these are used, see the comments in ./transformers/generators.ts
export const generatorHelper: UnscopedEmitHelper = {
name: "typescript:generator",
importName: "__generator",
scoped: false,
priority: 6,
text: `
+14 -22
View File
@@ -9,7 +9,7 @@ namespace ts {
context.enableEmitNotification(SyntaxKind.SourceFile);
context.enableSubstitution(SyntaxKind.Identifier);
let currentSourceFile: SourceFile | undefined;
let helperNameSubstitutions: Map<Identifier> | undefined;
return chainBundle(transformSourceFile);
function transformSourceFile(node: SourceFile) {
@@ -18,18 +18,11 @@ namespace ts {
}
if (isExternalModule(node) || compilerOptions.isolatedModules) {
const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(node, compilerOptions);
if (externalHelpersModuleName) {
const externalHelpersImportDeclaration = createExternalHelpersImportDeclarationIfNeeded(node, compilerOptions);
if (externalHelpersImportDeclaration) {
const statements: Statement[] = [];
const statementOffset = addPrologue(statements, node.statements);
const tslibImport = createImportDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createImportClause(/*name*/ undefined, createNamespaceImport(externalHelpersModuleName)),
createLiteral(externalHelpersModuleNameText)
);
addEmitFlags(tslibImport, EmitFlags.NeverApplyImportHelper);
append(statements, tslibImport);
append(statements, externalHelpersImportDeclaration);
addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset));
return updateSourceFileNode(
@@ -74,9 +67,9 @@ namespace ts {
*/
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
if (isSourceFile(node)) {
currentSourceFile = node;
helperNameSubstitutions = createMap<Identifier>();
previousOnEmitNode(hint, node, emitCallback);
currentSourceFile = undefined;
helperNameSubstitutions = undefined;
}
else {
previousOnEmitNode(hint, node, emitCallback);
@@ -95,21 +88,20 @@ namespace ts {
*/
function onSubstituteNode(hint: EmitHint, node: Node) {
node = previousOnSubstituteNode(hint, node);
if (isIdentifier(node) && hint === EmitHint.Expression) {
return substituteExpressionIdentifier(node);
if (helperNameSubstitutions && isIdentifier(node) && getEmitFlags(node) & EmitFlags.HelperName) {
return substituteHelperName(node);
}
return node;
}
function substituteExpressionIdentifier(node: Identifier): Expression {
if (getEmitFlags(node) & EmitFlags.HelperName) {
const externalHelpersModuleName = getExternalHelpersModuleName(currentSourceFile!);
if (externalHelpersModuleName) {
return createPropertyAccess(externalHelpersModuleName, node);
}
function substituteHelperName(node: Identifier): Expression {
const name = idText(node);
let substitution = helperNameSubstitutions!.get(name);
if (!substitution) {
helperNameSubstitutions!.set(name, substitution = createFileLevelUniqueName(name));
}
return node;
return substitution;
}
}
}
+7 -5
View File
@@ -698,7 +698,7 @@ namespace ts {
const promise = createNew(createIdentifier("Promise"), /*typeArguments*/ undefined, [func]);
if (compilerOptions.esModuleInterop) {
context.requestEmitHelper(importStarHelper);
return createCall(createPropertyAccess(promise, createIdentifier("then")), /*typeArguments*/ undefined, [getHelperName("__importStar")]);
return createCall(createPropertyAccess(promise, createIdentifier("then")), /*typeArguments*/ undefined, [getUnscopedHelperName("__importStar")]);
}
return promise;
}
@@ -713,7 +713,7 @@ namespace ts {
let requireCall = createCall(createIdentifier("require"), /*typeArguments*/ undefined, arg ? [arg] : []);
if (compilerOptions.esModuleInterop) {
context.requestEmitHelper(importStarHelper);
requireCall = createCall(getHelperName("__importStar"), /*typeArguments*/ undefined, [requireCall]);
requireCall = createCall(getUnscopedHelperName("__importStar"), /*typeArguments*/ undefined, [requireCall]);
}
let func: FunctionExpression | ArrowFunction;
@@ -753,11 +753,11 @@ namespace ts {
}
if (getImportNeedsImportStarHelper(node)) {
context.requestEmitHelper(importStarHelper);
return createCall(getHelperName("__importStar"), /*typeArguments*/ undefined, [innerExpr]);
return createCall(getUnscopedHelperName("__importStar"), /*typeArguments*/ undefined, [innerExpr]);
}
if (getImportNeedsImportDefaultHelper(node)) {
context.requestEmitHelper(importDefaultHelper);
return createCall(getHelperName("__importDefault"), /*typeArguments*/ undefined, [innerExpr]);
return createCall(getUnscopedHelperName("__importDefault"), /*typeArguments*/ undefined, [innerExpr]);
}
return innerExpr;
}
@@ -1793,7 +1793,7 @@ namespace ts {
function createExportStarHelper(context: TransformationContext, module: Expression) {
const compilerOptions = context.getCompilerOptions();
return compilerOptions.importHelpers
? createCall(getHelperName("__exportStar"), /*typeArguments*/ undefined, [module, createIdentifier("exports")])
? createCall(getUnscopedHelperName("__exportStar"), /*typeArguments*/ undefined, [module, createIdentifier("exports")])
: createCall(createIdentifier("__export"), /*typeArguments*/ undefined, [module]);
}
@@ -1808,6 +1808,7 @@ namespace ts {
// emit helper for `import * as Name from "foo"`
export const importStarHelper: UnscopedEmitHelper = {
name: "typescript:commonjsimportstar",
importName: "__importStar",
scoped: false,
text: `
var __importStar = (this && this.__importStar) || function (mod) {
@@ -1822,6 +1823,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
// emit helper for `import Name from "foo"`
export const importDefaultHelper: UnscopedEmitHelper = {
name: "typescript:commonjsimportdefault",
importName: "__importDefault",
scoped: false,
text: `
var __importDefault = (this && this.__importDefault) || function (mod) {
+15 -1
View File
@@ -24,12 +24,14 @@ namespace ts {
context.enableSubstitution(SyntaxKind.BinaryExpression); // Substitutes assignments to exported symbols.
context.enableSubstitution(SyntaxKind.PrefixUnaryExpression); // Substitutes updates to exported symbols.
context.enableSubstitution(SyntaxKind.PostfixUnaryExpression); // Substitutes updates to exported symbols.
context.enableSubstitution(SyntaxKind.MetaProperty); // Substitutes 'import.meta'
context.enableEmitNotification(SyntaxKind.SourceFile); // Restore state when substituting nodes in a file.
const moduleInfoMap: ExternalModuleInfo[] = []; // The ExternalModuleInfo for each file.
const deferredExports: (Statement[] | undefined)[] = []; // Exports to defer until an EndOfDeclarationMarker is found.
const exportFunctionsMap: Identifier[] = []; // The export function associated with a source file.
const noSubstitutionMap: boolean[][] = []; // Set of nodes for which substitution rules should be ignored for each file.
const contextObjectMap: Identifier[] = []; // The context object associated with a source file.
let currentSourceFile: SourceFile; // The current file.
let moduleInfo: ExternalModuleInfo; // ExternalModuleInfo for the current file.
@@ -75,7 +77,7 @@ namespace ts {
// existing identifiers.
exportFunction = createUniqueName("exports");
exportFunctionsMap[id] = exportFunction;
contextObject = createUniqueName("context");
contextObject = contextObjectMap[id] = createUniqueName("context");
// Add the body of the module.
const dependencyGroups = collectDependencyGroups(moduleInfo.externalImports);
@@ -1586,6 +1588,7 @@ namespace ts {
moduleInfo = moduleInfoMap[id];
exportFunction = exportFunctionsMap[id];
noSubstitution = noSubstitutionMap[id];
contextObject = contextObjectMap[id];
if (noSubstitution) {
delete noSubstitutionMap[id];
@@ -1596,6 +1599,7 @@ namespace ts {
currentSourceFile = undefined!;
moduleInfo = undefined!;
exportFunction = undefined!;
contextObject = undefined!;
noSubstitution = undefined;
}
else {
@@ -1641,6 +1645,7 @@ namespace ts {
}
return node;
}
/**
* Substitution for a ShorthandPropertyAssignment whose name that may contain an imported or exported symbol.
*
@@ -1694,6 +1699,8 @@ namespace ts {
case SyntaxKind.PrefixUnaryExpression:
case SyntaxKind.PostfixUnaryExpression:
return substituteUnaryExpression(<PrefixUnaryExpression | PostfixUnaryExpression>node);
case SyntaxKind.MetaProperty:
return substituteMetaProperty(<MetaProperty>node);
}
return node;
@@ -1830,6 +1837,13 @@ namespace ts {
return node;
}
function substituteMetaProperty(node: MetaProperty) {
if (isImportMeta(node)) {
return createPropertyAccess(contextObject, createIdentifier("meta"));
}
return node;
}
/**
* Gets the exports of a name.
*
+6 -3
View File
@@ -3282,7 +3282,7 @@ namespace ts {
context.requestEmitHelper(decorateHelper);
return setTextRange(
createCall(
getHelperName("__decorate"),
getUnscopedHelperName("__decorate"),
/*typeArguments*/ undefined,
argumentsArray
),
@@ -3292,6 +3292,7 @@ namespace ts {
export const decorateHelper: UnscopedEmitHelper = {
name: "typescript:decorate",
importName: "__decorate",
scoped: false,
priority: 2,
text: `
@@ -3306,7 +3307,7 @@ namespace ts {
function createMetadataHelper(context: TransformationContext, metadataKey: string, metadataValue: Expression) {
context.requestEmitHelper(metadataHelper);
return createCall(
getHelperName("__metadata"),
getUnscopedHelperName("__metadata"),
/*typeArguments*/ undefined,
[
createLiteral(metadataKey),
@@ -3317,6 +3318,7 @@ namespace ts {
export const metadataHelper: UnscopedEmitHelper = {
name: "typescript:metadata",
importName: "__metadata",
scoped: false,
priority: 3,
text: `
@@ -3329,7 +3331,7 @@ namespace ts {
context.requestEmitHelper(paramHelper);
return setTextRange(
createCall(
getHelperName("__param"),
getUnscopedHelperName("__param"),
/*typeArguments*/ undefined,
[
createLiteral(parameterOffset),
@@ -3342,6 +3344,7 @@ namespace ts {
export const paramHelper: UnscopedEmitHelper = {
name: "typescript:param",
importName: "__param",
scoped: false,
priority: 4,
text: `
+9 -10
View File
@@ -70,7 +70,8 @@ namespace ts {
let hasExportDefault = false;
let exportEquals: ExportAssignment | undefined;
let hasExportStarsToExportValues = false;
let hasImportStarOrImportDefault = false;
let hasImportStar = false;
let hasImportDefault = false;
for (const node of sourceFile.statements) {
switch (node.kind) {
@@ -80,7 +81,12 @@ namespace ts {
// import * as x from "mod"
// import { x, y } from "mod"
externalImports.push(<ImportDeclaration>node);
hasImportStarOrImportDefault = hasImportStarOrImportDefault || getImportNeedsImportStarHelper(<ImportDeclaration>node) || getImportNeedsImportDefaultHelper(<ImportDeclaration>node);
if (!hasImportStar && getImportNeedsImportStarHelper(<ImportDeclaration>node)) {
hasImportStar = true;
}
if (!hasImportDefault && getImportNeedsImportDefaultHelper(<ImportDeclaration>node)) {
hasImportDefault = true;
}
break;
case SyntaxKind.ImportEqualsDeclaration:
@@ -183,15 +189,8 @@ namespace ts {
}
}
const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(sourceFile, compilerOptions, hasExportStarsToExportValues, hasImportStarOrImportDefault);
const externalHelpersImportDeclaration = externalHelpersModuleName && createImportDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createImportClause(/*name*/ undefined, createNamespaceImport(externalHelpersModuleName)),
createLiteral(externalHelpersModuleNameText));
const externalHelpersImportDeclaration = createExternalHelpersImportDeclarationIfNeeded(sourceFile, compilerOptions, hasExportStarsToExportValues, hasImportStar, hasImportDefault);
if (externalHelpersImportDeclaration) {
addEmitFlags(externalHelpersImportDeclaration, EmitFlags.NeverApplyImportHelper);
externalImports.unshift(externalHelpersImportDeclaration);
}
+45 -2
View File
@@ -564,8 +564,51 @@ namespace ts {
}
function getBuildOrder(state: SolutionBuilderState) {
return state.buildOrder ||
(state.buildOrder = createBuildOrder(state, state.rootNames.map(f => resolveProjectName(state, f))));
return state.buildOrder || createStateBuildOrder(state);
}
function createStateBuildOrder(state: SolutionBuilderState) {
const buildOrder = createBuildOrder(state, state.rootNames.map(f => resolveProjectName(state, f)));
if (arrayIsEqualTo(state.buildOrder, buildOrder)) return state.buildOrder!;
// Clear all to ResolvedConfigFilePaths cache to start fresh
state.resolvedConfigFilePaths.clear();
const currentProjects = arrayToSet(
buildOrder,
resolved => toResolvedConfigFilePath(state, resolved)
) as ConfigFileMap<true>;
const noopOnDelete = { onDeleteValue: noop };
// Config file cache
mutateMapSkippingNewValues(state.configFileCache, currentProjects, noopOnDelete);
mutateMapSkippingNewValues(state.projectStatus, currentProjects, noopOnDelete);
mutateMapSkippingNewValues(state.buildInfoChecked, currentProjects, noopOnDelete);
mutateMapSkippingNewValues(state.builderPrograms, currentProjects, noopOnDelete);
mutateMapSkippingNewValues(state.diagnostics, currentProjects, noopOnDelete);
mutateMapSkippingNewValues(state.projectPendingBuild, currentProjects, noopOnDelete);
mutateMapSkippingNewValues(state.projectErrorsReported, currentProjects, noopOnDelete);
// Remove watches for the program no longer in the solution
if (state.watch) {
mutateMapSkippingNewValues(
state.allWatchedConfigFiles,
currentProjects,
{ onDeleteValue: closeFileWatcher }
);
mutateMapSkippingNewValues(
state.allWatchedWildcardDirectories,
currentProjects,
{ onDeleteValue: existingMap => existingMap.forEach(closeFileWatcherOf) }
);
mutateMapSkippingNewValues(
state.allWatchedInputFiles,
currentProjects,
{ onDeleteValue: existingMap => existingMap.forEach(closeFileWatcher) }
);
}
return state.buildOrder = buildOrder;
}
function getBuildOrderFor(state: SolutionBuilderState, project: string | undefined, onlyReferences: boolean | undefined) {
+1
View File
@@ -10,6 +10,7 @@
"core.ts",
"debug.ts",
"performance.ts",
"perfLogger.ts",
"semver.ts",
"types.ts",
+34 -11
View File
@@ -455,6 +455,8 @@ namespace ts {
JSDocOptionalType,
JSDocFunctionType,
JSDocVariadicType,
// https://jsdoc.app/about-namepaths.html
JSDocNamepathType,
JSDocComment,
JSDocTypeLiteral,
JSDocSignature,
@@ -1677,6 +1679,8 @@ namespace ts {
/* @internal */
ContainsSeparator = 1 << 9, // e.g. `0b1100_0101`
/* @internal */
UnicodeEscape = 1 << 10,
/* @internal */
BinaryOrOctalSpecifier = BinarySpecifier | OctalSpecifier,
/* @internal */
NumericLiteralFlags = Scientific | Octal | HexSpecifier | BinaryOrOctalSpecifier | ContainsSeparator
@@ -1862,6 +1866,12 @@ namespace ts {
name: Identifier;
}
/* @internal */
export interface ImportMetaProperty extends MetaProperty {
keywordToken: SyntaxKind.ImportKeyword;
name: Identifier & { escapedText: __String & "meta" };
}
/// A JSX expression of the form <TagName attrs>...</TagName>
export interface JsxElement extends PrimaryExpression {
kind: SyntaxKind.JsxElement;
@@ -2430,6 +2440,11 @@ namespace ts {
type: TypeNode;
}
export interface JSDocNamepathType extends JSDocType {
kind: SyntaxKind.JSDocNamepathType;
type: TypeNode;
}
export type JSDocTypeReferencingNode = JSDocVariadicType | JSDocOptionalType | JSDocNullableType | JSDocNonNullableType;
export interface JSDoc extends Node {
@@ -2466,7 +2481,8 @@ namespace ts {
kind: SyntaxKind.JSDocClassTag;
}
export interface JSDocEnumTag extends JSDocTag {
export interface JSDocEnumTag extends JSDocTag, Declaration {
parent: JSDoc;
kind: SyntaxKind.JSDocEnumTag;
typeExpression?: JSDocTypeExpression;
}
@@ -3660,8 +3676,8 @@ namespace ts {
Enum = RegularEnum | ConstEnum,
Variable = FunctionScopedVariable | BlockScopedVariable,
Value = Variable | Property | EnumMember | ObjectLiteral | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor | Assignment,
Type = Class | Interface | Enum | EnumMember | TypeLiteral | TypeParameter | TypeAlias | Assignment,
Value = Variable | Property | EnumMember | ObjectLiteral | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor,
Type = Class | Interface | Enum | EnumMember | TypeLiteral | TypeParameter | TypeAlias,
Namespace = ValueModule | NamespaceModule | Enum,
Module = ValueModule | NamespaceModule,
Accessor = GetAccessor | SetAccessor,
@@ -3677,12 +3693,12 @@ namespace ts {
ParameterExcludes = Value,
PropertyExcludes = None,
EnumMemberExcludes = Value | Type,
FunctionExcludes = Value & ~(Function | ValueModule),
ClassExcludes = (Value | Type) & ~(ValueModule | Interface), // class-interface mergability done in checker.ts
FunctionExcludes = Value & ~(Function | ValueModule | Class),
ClassExcludes = (Value | Type) & ~(ValueModule | Interface | Function), // class-interface mergability done in checker.ts
InterfaceExcludes = Type & ~(Interface | Class),
RegularEnumExcludes = (Value | Type) & ~(RegularEnum | ValueModule), // regular enums merge only with regular enums and modules
ConstEnumExcludes = (Value | Type) & ~ConstEnum, // const enums merge only with const enums
ValueModuleExcludes = Value & ~(Function | Class | RegularEnum | ValueModule | Assignment),
ValueModuleExcludes = Value & ~(Function | Class | RegularEnum | ValueModule),
NamespaceModuleExcludes = 0,
MethodExcludes = Value & ~Method,
GetAccessorExcludes = Value & ~SetAccessor,
@@ -4759,8 +4775,12 @@ namespace ts {
AMD = 2,
UMD = 3,
System = 4,
// NOTE: ES module kinds should be contiguous to more easily check whether a module kind is *any* ES module kind.
// Non-ES module kinds should not come between ES2015 (the earliest ES module kind) and ESNext (the last ES
// module kind).
ES2015 = 5,
ESNext = 6
ESNext = 99
}
export const enum JsxEmit {
@@ -4808,7 +4828,7 @@ namespace ts {
ES2018 = 5,
ES2019 = 6,
ES2020 = 7,
ESNext = 8,
ESNext = 99,
JSON = 100,
Latest = ESNext,
}
@@ -5172,11 +5192,11 @@ namespace ts {
* If resolveModuleNames is implemented then implementation for members from ModuleResolutionHost can be just
* 'throw new Error("NotImplemented")'
*/
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[], redirectedReference?: ResolvedProjectReference): (ResolvedModule | undefined)[];
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions): (ResolvedModule | undefined)[];
/**
* This method is a companion for 'resolveModuleNames' and is used to resolve 'types' references to actual type declaration files
*/
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string, redirectedReference?: ResolvedProjectReference): (ResolvedTypeReferenceDirective | undefined)[];
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions): (ResolvedTypeReferenceDirective | undefined)[];
getEnvironmentVariable?(name: string): string | undefined;
/* @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean): void;
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
@@ -5288,6 +5308,7 @@ namespace ts {
tokenSourceMapRanges?: (SourceMapRange | undefined)[]; // 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
externalHelpers?: boolean;
helpers?: EmitHelper[]; // Emit helpers for the node
startsOnNewLine?: boolean; // If the node should begin on a new line
}
@@ -5309,7 +5330,7 @@ namespace ts {
NoTrailingComments = 1 << 10, // Do not emit trailing comments for this node.
NoComments = NoLeadingComments | NoTrailingComments, // Do not emit comments for this node.
NoNestedComments = 1 << 11,
HelperName = 1 << 12,
HelperName = 1 << 12, // The Identifier refers to an *unscoped* emit helper (one that is emitted at the top of the file)
ExportName = 1 << 13, // Ensure an export prefix is added for an identifier that points to an exported declaration with a local name (see SymbolFlags.ExportHasLocal).
LocalName = 1 << 14, // Ensure an export prefix is not added for an identifier that points to an exported declaration.
InternalName = 1 << 15, // The name is internal to an ES5 class body function.
@@ -5335,6 +5356,8 @@ namespace ts {
export interface UnscopedEmitHelper extends EmitHelper {
readonly scoped: false; // Indicates whether the helper MUST be emitted in the current scope.
/* @internal */
readonly importName?: string; // The name of the helper to use when importing via `--importHelpers`.
readonly text: string; // ES3-compatible raw script text, or a function yielding such a string
}
+91 -12
View File
@@ -566,6 +566,8 @@ namespace ts {
return emitNode && emitNode.flags || 0;
}
const escapeNoSubstitutionTemplateLiteralText = compose(escapeString, escapeTemplateSubstitution);
const escapeNonAsciiNoSubstitutionTemplateLiteralText = compose(escapeNonAsciiString, escapeTemplateSubstitution);
export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile, neverAsciiEscape: boolean | undefined) {
// If we don't need to downlevel and we can reach the original source text using
// the node's parent reference, then simply get the text as it was originally written.
@@ -576,7 +578,11 @@ namespace ts {
return getSourceTextOfNodeFromSourceFile(sourceFile, node);
}
const escapeText = neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ? escapeString : escapeNonAsciiString;
// If a NoSubstitutionTemplateLiteral appears to have a substitution in it, the original text
// had to include a backslash: `not \${a} substitution`.
const escapeText = neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ?
node.kind === SyntaxKind.NoSubstitutionTemplateLiteral ? escapeNoSubstitutionTemplateLiteralText : escapeString :
node.kind === SyntaxKind.NoSubstitutionTemplateLiteral ? escapeNonAsciiNoSubstitutionTemplateLiteralText : escapeNonAsciiString;
// If we can't reach the original source text, use the canonical form if it's a number,
// or a (possibly escaped) quoted form of the original text if it's string-like.
@@ -694,6 +700,43 @@ namespace ts {
return isExternalModule(node) || compilerOptions.isolatedModules || ((getEmitModuleKind(compilerOptions) === ModuleKind.CommonJS) && !!node.commonJsModuleIndicator);
}
/**
* Returns whether the source file will be treated as if it were in strict mode at runtime.
*/
export function isEffectiveStrictModeSourceFile(node: SourceFile, compilerOptions: CompilerOptions) {
// We can only verify strict mode for JS/TS files
switch (node.scriptKind) {
case ScriptKind.JS:
case ScriptKind.TS:
case ScriptKind.JSX:
case ScriptKind.TSX:
break;
default:
return false;
}
// Strict mode does not matter for declaration files.
if (node.isDeclarationFile) {
return false;
}
// If `alwaysStrict` is set, then treat the file as strict.
if (getStrictOptionValue(compilerOptions, "alwaysStrict")) {
return true;
}
// Starting with a "use strict" directive indicates the file is strict.
if (startsWithUseStrict(node.statements)) {
return true;
}
if (isExternalModule(node) || compilerOptions.isolatedModules) {
// ECMAScript Modules are always strict.
if (getEmitModuleKind(compilerOptions) >= ModuleKind.ES2015) {
return true;
}
// Other modules are strict unless otherwise specified.
return !compilerOptions.noImplicitUseStrict;
}
return false;
}
export function isBlockScope(node: Node, parentNode: Node): boolean {
switch (node.kind) {
case SyntaxKind.SourceFile:
@@ -981,6 +1024,12 @@ namespace ts {
return n.kind === SyntaxKind.CallExpression && (<CallExpression>n).expression.kind === SyntaxKind.ImportKeyword;
}
export function isImportMeta(n: Node): n is ImportMetaProperty {
return isMetaProperty(n)
&& n.keywordToken === SyntaxKind.ImportKeyword
&& n.name.escapedText === "meta";
}
export function isLiteralImportTypeNode(n: Node): n is LiteralImportTypeNode {
return isImportTypeNode(n) && isLiteralTypeNode(n.argument) && isStringLiteral(n.argument.literal);
}
@@ -2147,11 +2196,11 @@ namespace ts {
return !!name && name.escapedText === "new";
}
export function isJSDocTypeAlias(node: Node): node is JSDocTypedefTag | JSDocCallbackTag {
return node.kind === SyntaxKind.JSDocTypedefTag || node.kind === SyntaxKind.JSDocCallbackTag;
export function isJSDocTypeAlias(node: Node): node is JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag {
return node.kind === SyntaxKind.JSDocTypedefTag || node.kind === SyntaxKind.JSDocCallbackTag || node.kind === SyntaxKind.JSDocEnumTag;
}
export function isTypeAlias(node: Node): node is JSDocTypedefTag | JSDocCallbackTag | TypeAliasDeclaration {
export function isTypeAlias(node: Node): node is JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag | TypeAliasDeclaration {
return isJSDocTypeAlias(node) || isTypeAliasDeclaration(node);
}
@@ -2633,6 +2682,10 @@ namespace ts {
return isKeyword(token) && !isContextualKeyword(token);
}
export function isFutureReservedKeyword(token: SyntaxKind): boolean {
return SyntaxKind.FirstFutureReservedWord <= token && token <= SyntaxKind.LastFutureReservedWord;
}
export function isStringANonContextualKeyword(name: string) {
const token = stringToToken(name);
return token !== undefined && isNonContextualKeyword(token);
@@ -3113,6 +3166,11 @@ namespace ts {
}
}
const templateSubstitutionRegExp = /\$\{/g;
function escapeTemplateSubstitution(str: string): string {
return str.replace(templateSubstitutionRegExp, "\\${");
}
// This consists of the first 19 unprintable ASCII characters, canonical escapes, lineSeparator,
// paragraphSeparator, and nextLine. The latter three are just desirable to suppress new lines in
// the language service. These characters should be escaped when printing, and if any characters are added,
@@ -3507,7 +3565,7 @@ namespace ts {
return find(node.members, (member): member is ConstructorDeclaration & { body: FunctionBody } => isConstructorDeclaration(member) && nodeIsPresent(member.body));
}
function getSetAccessorValueParameter(accessor: SetAccessorDeclaration): ParameterDeclaration | undefined {
export 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];
@@ -3542,7 +3600,7 @@ namespace ts {
return id.originalKeywordKind === SyntaxKind.ThisKeyword;
}
export function getAllAccessorDeclarations(declarations: NodeArray<Declaration>, accessor: AccessorDeclaration): AllAccessorDeclarations {
export function getAllAccessorDeclarations(declarations: readonly Declaration[], accessor: AccessorDeclaration): AllAccessorDeclarations {
// TODO: GH#18217
let firstAccessor!: AccessorDeclaration;
let secondAccessor!: AccessorDeclaration;
@@ -4466,8 +4524,7 @@ namespace ts {
map.clear();
}
export interface MutateMapOptions<T, U> {
createNewValue(key: string, valueInNewMap: U): T;
export interface MutateMapSkippingNewValuesOptions<T, U> {
onDeleteValue(existingValue: T, key: string): void;
/**
@@ -4482,8 +4539,12 @@ namespace ts {
/**
* Mutates the map with newMap such that keys in map will be same as newMap.
*/
export function mutateMap<T, U>(map: Map<T>, newMap: ReadonlyMap<U>, options: MutateMapOptions<T, U>) {
const { createNewValue, onDeleteValue, onExistingValue } = options;
export function mutateMapSkippingNewValues<T, U>(
map: Map<T>,
newMap: ReadonlyMap<U>,
options: MutateMapSkippingNewValuesOptions<T, U>
) {
const { onDeleteValue, onExistingValue } = options;
// Needs update
map.forEach((existingValue, key) => {
const valueInNewMap = newMap.get(key);
@@ -4497,7 +4558,20 @@ namespace ts {
onExistingValue(existingValue, valueInNewMap, key);
}
});
}
export interface MutateMapOptions<T, U> extends MutateMapSkippingNewValuesOptions<T, U> {
createNewValue(key: string, valueInNewMap: U): T;
}
/**
* Mutates the map with newMap such that keys in map will be same as newMap.
*/
export function mutateMap<T, U>(map: Map<T>, newMap: ReadonlyMap<U>, options: MutateMapOptions<T, U>) {
// Needs update
mutateMapSkippingNewValues(map, newMap, options);
const { createNewValue } = options;
// Add new values that are not already present
newMap.forEach((valueInNewMap, key) => {
if (!map.has(key)) {
@@ -5091,7 +5165,7 @@ namespace ts {
* attempt to draw the name from the node the declaration is on (as that declaration is what its' symbol
* will be merged with)
*/
function nameForNamelessJSDocTypedef(declaration: JSDocTypedefTag): Identifier | undefined {
function nameForNamelessJSDocTypedef(declaration: JSDocTypedefTag | JSDocEnumTag): Identifier | undefined {
const hostNode = declaration.parent.parent;
if (!hostNode) {
return undefined;
@@ -5108,7 +5182,10 @@ namespace ts {
}
break;
case SyntaxKind.ExpressionStatement:
const expr = hostNode.expression;
let expr = hostNode.expression;
if (expr.kind === SyntaxKind.BinaryExpression && (expr as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) {
expr = (expr as BinaryExpression).left;
}
switch (expr.kind) {
case SyntaxKind.PropertyAccessExpression:
return (expr as PropertyAccessExpression).name;
@@ -5177,6 +5254,8 @@ namespace ts {
}
case SyntaxKind.JSDocTypedefTag:
return getNameOfJSDocTypedef(declaration as JSDocTypedefTag);
case SyntaxKind.JSDocEnumTag:
return nameForNamelessJSDocTypedef(declaration as JSDocEnumTag);
case SyntaxKind.ExportAssignment: {
const { expression } = declaration as ExportAssignment;
return isIdentifier(expression) ? expression : undefined;
+13 -7
View File
@@ -538,9 +538,9 @@ namespace ts {
getEnvironmentVariable?(name: string): string | undefined;
/** If provided, used to resolve the module names, otherwise typescript's default module resolution */
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[], redirectedReference?: ResolvedProjectReference): (ResolvedModule | undefined)[];
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions): (ResolvedModule | undefined)[];
/** If provided, used to resolve type reference directives, otherwise typescript's default resolution */
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string, redirectedReference?: ResolvedProjectReference): (ResolvedTypeReferenceDirective | undefined)[];
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions): (ResolvedTypeReferenceDirective | undefined)[];
}
/** Internal interface used to wire emit through same host */
@@ -744,10 +744,10 @@ namespace ts {
);
// Resolve module using host module resolution strategy if provided otherwise use resolution cache to resolve module names
compilerHost.resolveModuleNames = host.resolveModuleNames ?
((moduleNames, containingFile, reusedNames, redirectedReference) => host.resolveModuleNames!(moduleNames, containingFile, reusedNames, redirectedReference)) :
((...args) => host.resolveModuleNames!(...args)) :
((moduleNames, containingFile, reusedNames, redirectedReference) => resolutionCache.resolveModuleNames(moduleNames, containingFile, reusedNames, redirectedReference));
compilerHost.resolveTypeReferenceDirectives = host.resolveTypeReferenceDirectives ?
((typeDirectiveNames, containingFile, redirectedReference) => host.resolveTypeReferenceDirectives!(typeDirectiveNames, containingFile, redirectedReference)) :
((...args) => host.resolveTypeReferenceDirectives!(...args)) :
((typeDirectiveNames, containingFile, redirectedReference) => resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile, redirectedReference));
const userProvidedResolution = !!host.resolveModuleNames || !!host.resolveTypeReferenceDirectives;
@@ -1005,13 +1005,19 @@ namespace ts {
switch (reloadLevel) {
case ConfigFileProgramReloadLevel.Partial:
return reloadFileNamesFromConfigFile();
perfLogger.logStartUpdateProgram("PartialConfigReload");
reloadFileNamesFromConfigFile();
break;
case ConfigFileProgramReloadLevel.Full:
return reloadConfigFile();
perfLogger.logStartUpdateProgram("FullConfigReload");
reloadConfigFile();
break;
default:
perfLogger.logStartUpdateProgram("SynchronizeProgram");
synchronizeProgram();
return;
break;
}
perfLogger.logStopUpdateProgram("Done");
}
function reloadFileNamesFromConfigFile() {
+3
View File
@@ -370,6 +370,9 @@ namespace ts {
const createFileWatcher: CreateFileWatcher<WatchFileHost, PollingInterval, FileWatcherEventKind, never, X, Y> = getCreateFileWatcher(watchLogLevel, watchFile);
const createFilePathWatcher: CreateFileWatcher<WatchFileHost, PollingInterval, FileWatcherEventKind, Path, X, Y> = watchLogLevel === WatchLogLevel.None ? watchFilePath : createFileWatcher;
const createDirectoryWatcher: CreateFileWatcher<WatchDirectoryHost, WatchDirectoryFlags, undefined, never, X, Y> = getCreateFileWatcher(watchLogLevel, watchDirectory);
if (watchLogLevel === WatchLogLevel.Verbose && sysLog === noop) {
sysLog = s => log(s);
}
return {
watchFile: (host, file, callback, pollingInterval, detailInfo1, detailInfo2) =>
createFileWatcher(host, file, callback, pollingInterval, /*passThrough*/ undefined, detailInfo1, detailInfo2, watchFile, log, "FileWatcher", getDetailWatchInfo),
+29 -64
View File
@@ -344,7 +344,8 @@ namespace FourSlash {
"getDocumentHighlights",
];
const proxy = {} as ts.LanguageService;
for (const k in ls) {
const keys = ts.getAllKeys(ls);
for (const k of keys) {
const key = k as keyof typeof ls;
if (cacheableMembers.indexOf(key) === -1) {
proxy[key] = (...args: any[]) => (ls[key] as Function)(...args);
@@ -797,7 +798,7 @@ namespace FourSlash {
for (const include of toArray(options.includes)) {
const name = typeof include === "string" ? include : include.name;
const found = nameToEntries.get(name);
if (!found) throw this.raiseError(`No completion ${name} found`);
if (!found) throw this.raiseError(`Includes: completion '${name}' not found.`);
assert(found.length === 1); // Must use 'exact' for multiple completions with same name
this.verifyCompletionEntry(ts.first(found), include);
}
@@ -806,7 +807,7 @@ namespace FourSlash {
for (const exclude of toArray(options.excludes)) {
assert(typeof exclude === "string");
if (nameToEntries.has(exclude)) {
this.raiseError(`Did not expect to get a completion named ${exclude}`);
this.raiseError(`Excludes: unexpected completion '${exclude}' found.`);
}
}
}
@@ -948,7 +949,7 @@ namespace FourSlash {
const actual = checker.typeToString(type);
if (actual !== expected) {
this.raiseError(`Expected: '${expected}', actual: '${actual}'`);
this.raiseError(displayExpectedAndActualString(expected, actual));
}
}
@@ -1024,9 +1025,7 @@ namespace FourSlash {
private assertObjectsEqual<T>(fullActual: T, fullExpected: T, msgPrefix = ""): void {
const recur = <U>(actual: U, expected: U, path: string) => {
const fail = (msg: string) => {
this.raiseError(`${msgPrefix} At ${path}: ${msg}
Expected: ${stringify(fullExpected)}
Actual: ${stringify(fullActual)}`);
this.raiseError(`${msgPrefix} At ${path}: ${msg} ${displayExpectedAndActualString(stringify(fullExpected), stringify(fullActual))}`);
};
if ((actual === undefined) !== (expected === undefined)) {
@@ -1058,9 +1057,7 @@ Actual: ${stringify(fullActual)}`);
if (fullActual === fullExpected) {
return;
}
this.raiseError(`${msgPrefix}
Expected: ${stringify(fullExpected)}
Actual: ${stringify(fullActual)}`);
this.raiseError(`${msgPrefix} ${displayExpectedAndActualString(stringify(fullExpected), stringify(fullActual))}`);
}
recur(fullActual, fullExpected, "");
@@ -1272,6 +1269,10 @@ Actual: ${stringify(fullActual)}`);
private verifySignatureHelpWorker(options: FourSlashInterface.VerifySignatureHelpOptions) {
const help = this.getSignatureHelp({ triggerReason: options.triggerReason })!;
if (!help) {
this.raiseError("Could not get a help signature");
}
const selectedItem = help.items[help.selectedItemIndex];
// Argument index may exceed number of parameters
const currentParameter = selectedItem.parameters[help.argumentIndex] as ts.SignatureHelpParameter | undefined;
@@ -2111,9 +2112,7 @@ Actual: ${stringify(fullActual)}`);
public verifyCurrentLineContent(text: string) {
const actual = this.getCurrentLineContent();
if (actual !== text) {
throw new Error("verifyCurrentLineContent\n" +
"\tExpected: \"" + text + "\"\n" +
"\t Actual: \"" + actual + "\"");
throw new Error("verifyCurrentLineContent\n" + displayExpectedAndActualString(text, actual, /* quoted */ true));
}
}
@@ -2139,25 +2138,19 @@ Actual: ${stringify(fullActual)}`);
public verifyTextAtCaretIs(text: string) {
const actual = this.getFileContent(this.activeFile.fileName).substring(this.currentCaretPosition, this.currentCaretPosition + text.length);
if (actual !== text) {
throw new Error("verifyTextAtCaretIs\n" +
"\tExpected: \"" + text + "\"\n" +
"\t Actual: \"" + actual + "\"");
throw new Error("verifyTextAtCaretIs\n" + displayExpectedAndActualString(text, actual, /* quoted */ true));
}
}
public verifyCurrentNameOrDottedNameSpanText(text: string) {
const span = this.languageService.getNameOrDottedNameSpan(this.activeFile.fileName, this.currentCaretPosition, this.currentCaretPosition);
if (!span) {
return this.raiseError("verifyCurrentNameOrDottedNameSpanText\n" +
"\tExpected: \"" + text + "\"\n" +
"\t Actual: undefined");
return this.raiseError("verifyCurrentNameOrDottedNameSpanText\n" + displayExpectedAndActualString("\"" + text + "\"", "undefined"));
}
const actual = this.getFileContent(this.activeFile.fileName).substring(span.start, ts.textSpanEnd(span));
if (actual !== text) {
this.raiseError("verifyCurrentNameOrDottedNameSpanText\n" +
"\tExpected: \"" + text + "\"\n" +
"\t Actual: \"" + actual + "\"");
this.raiseError("verifyCurrentNameOrDottedNameSpanText\n" + displayExpectedAndActualString(text, actual, /* quoted */ true));
}
}
@@ -2333,7 +2326,10 @@ Actual: ${stringify(fullActual)}`);
public applyCodeActionFromCompletion(markerName: string, options: FourSlashInterface.VerifyCompletionActionOptions) {
this.goToMarker(markerName);
const details = this.getCompletionEntryDetails(options.name, options.source, options.preferences)!;
const details = this.getCompletionEntryDetails(options.name, options.source, options.preferences);
if (!details) {
return this.raiseError(`No completions were found for the given name, source, and preferences.`);
}
const codeActions = details.codeActions!;
if (codeActions.length !== 1) {
this.raiseError(`Expected one code action, got ${codeActions.length}`);
@@ -2442,7 +2438,7 @@ Actual: ${stringify(fullActual)}`);
const oldText = this.tryGetFileContent(change.fileName);
ts.Debug.assert(!!change.isNewFile === (oldText === undefined));
const newContent = change.isNewFile ? ts.first(change.textChanges).newText : ts.textChanges.applyChanges(oldText!, change.textChanges);
assert.equal(newContent, expectedNewContent);
assert.equal(newContent, expectedNewContent, `String mis-matched in file ${change.fileName}`);
}
for (const newFileName in newFileContent) {
ts.Debug.assert(changes.some(c => c.fileName === newFileName), "No change in file", () => newFileName);
@@ -3690,7 +3686,7 @@ ${code}
expected = makeWhitespaceVisible(expected);
actual = makeWhitespaceVisible(actual);
}
return `Expected:\n${expected}\nActual:\n${actual}`;
return displayExpectedAndActualString(expected, actual);
}
function differOnlyByWhitespace(a: string, b: string) {
@@ -3710,6 +3706,14 @@ ${code}
}
}
}
function displayExpectedAndActualString(expected: string, actual: string, quoted = false) {
const expectMsg = "\x1b[1mExpected\x1b[0m\x1b[31m";
const actualMsg = "\x1b[1mActual\x1b[0m\x1b[31m";
const expectedString = quoted ? "\"" + expected + "\"" : expected;
const actualString = quoted ? "\"" + actual + "\"" : actual;
return `\n${expectMsg}:\n${expectedString}\n\n${actualMsg}:\n${actualString}`;
}
}
namespace FourSlashInterface {
@@ -4831,40 +4835,23 @@ namespace FourSlashInterface {
"interface",
"let",
"package",
"private",
"protected",
"public",
"static",
"yield",
"abstract",
"as",
"any",
"async",
"await",
"boolean",
"constructor",
"declare",
"get",
"infer",
"is",
"keyof",
"module",
"namespace",
"never",
"readonly",
"require",
"number",
"object",
"set",
"string",
"symbol",
"type",
"unique",
"unknown",
"from",
"global",
"bigint",
"of",
].map(keywordEntry);
export const statementKeywords: ReadonlyArray<ExpectedCompletionEntryObject> = statementKeywordsWithTypes.filter(k => {
@@ -5045,40 +5032,23 @@ namespace FourSlashInterface {
"interface",
"let",
"package",
"private",
"protected",
"public",
"static",
"yield",
"abstract",
"as",
"any",
"async",
"await",
"boolean",
"constructor",
"declare",
"get",
"infer",
"is",
"keyof",
"module",
"namespace",
"never",
"readonly",
"require",
"number",
"object",
"set",
"string",
"symbol",
"type",
"unique",
"unknown",
"from",
"global",
"bigint",
"of",
].map(keywordEntry);
export const globalInJsKeywords = getInJsKeywords(globalKeywords);
@@ -5131,11 +5101,6 @@ namespace FourSlashInterface {
export const insideMethodInJsKeywords = getInJsKeywords(insideMethodKeywords);
export const globalKeywordsPlusUndefined: ReadonlyArray<ExpectedCompletionEntryObject> = (() => {
const i = ts.findIndex(globalKeywords, x => x.name === "unique");
return [...globalKeywords.slice(0, i), keywordEntry("undefined"), ...globalKeywords.slice(i)];
})();
export const globals: ReadonlyArray<ExpectedCompletionEntryObject> = [
globalThisEntry,
...globalsVars,
+3 -1
View File
@@ -53,7 +53,7 @@ namespace Utils {
export function byteLength(s: string, encoding?: string): number {
// stub implementation if Buffer is not available (in-browser case)
return Buffer.byteLength(s, encoding);
return Buffer.byteLength(s, encoding as ts.BufferEncoding | undefined);
}
export function evalFile(fileContents: string, fileName: string, nodeContext?: any) {
@@ -726,6 +726,7 @@ namespace Harness {
includeBuiltFile?: string;
baselineFile?: string;
libFiles?: string;
noTypesAndSymbols?: boolean;
}
// Additional options not already in ts.optionDeclarations
@@ -742,6 +743,7 @@ namespace Harness {
{ name: "currentDirectory", type: "string" },
{ name: "symlink", type: "string" },
{ name: "link", type: "string" },
{ name: "noTypesAndSymbols", type: "boolean" },
// Emitted js baseline will print full paths for every output file
{ name: "fullEmitPaths", type: "boolean" }
];
+1 -1
View File
@@ -97,7 +97,7 @@ class TypeWriterWalker {
if (!isSymbolWalk) {
// Don't try to get the type of something that's already a type.
// Exception for `T` in `type T = something` because that may evaluate to some interesting type.
if (ts.isPartOfTypeNode(node) || ts.isIdentifier(node) && !(ts.getMeaningFromDeclaration(node.parent) & ts.SemanticMeaning.Value) && !(ts.isTypeAlias(node.parent) && node.parent.name === node)) {
if (ts.isPartOfTypeNode(node) || ts.isIdentifier(node) && !(ts.getMeaningFromDeclaration(node.parent) & ts.SemanticMeaning.Value) && !(ts.isTypeAliasDeclaration(node.parent) && node.parent.name === node)) {
return undefined;
}
+24 -2
View File
@@ -1525,8 +1525,11 @@ namespace vfs {
return typeof value === "string" || Buffer.isBuffer(value) ? new File(value) : new Directory(value);
}
export function formatPatch(patch: FileSet) {
return formatPatchWorker("", patch);
export function formatPatch(patch: FileSet): string;
export function formatPatch(patch: FileSet | undefined): string | null;
export function formatPatch(patch: FileSet | undefined) {
// tslint:disable-next-line:no-null-keyword
return patch ? formatPatchWorker("", patch) : null;
}
function formatPatchWorker(dirname: string, container: FileSet): string {
@@ -1559,5 +1562,24 @@ namespace vfs {
}
return text;
}
export function iteratePatch(patch: FileSet | undefined): IterableIterator<[string, string]> | null {
// tslint:disable-next-line:no-null-keyword
return patch ? Harness.Compiler.iterateOutputs(iteratePatchWorker("", patch)) : null;
}
function* iteratePatchWorker(dirname: string, container: FileSet): IterableIterator<documents.TextDocument> {
for (const name of Object.keys(container)) {
const entry = normalizeFileSetEntry(container[name]);
const file = dirname ? vpath.combine(dirname, name) : name;
if (entry instanceof Directory) {
yield* ts.arrayFrom(iteratePatchWorker(file, entry.files));
}
else if (entry instanceof File) {
const content = typeof entry.data === "string" ? entry.data : entry.data.toString("utf8");
yield new documents.TextDocument(file, content);
}
}
}
}
// tslint:enable:no-null-keyword
+30 -7
View File
@@ -314,6 +314,11 @@ interface Array<T> {}`
invokeFileDeleteCreateAsPartInsteadOfChange: boolean;
}
export enum Tsc_WatchFile {
DynamicPolling = "DynamicPriorityPolling",
SingleFileWatcherPerName = "SingleFileWatcherPerName"
}
export enum Tsc_WatchDirectory {
WatchFile = "RecursiveDirectoryUsingFsWatchFile",
NonRecursiveWatchDirectory = "RecursiveDirectoryUsingNonRecursiveWatchDirectory",
@@ -339,7 +344,7 @@ interface Array<T> {}`
readonly watchedFiles = createMultiMap<TestFileWatcher>();
private readonly executingFilePath: string;
private readonly currentDirectory: string;
private readonly dynamicPriorityWatchFile: HostWatchFile | undefined;
private readonly customWatchFile: HostWatchFile | undefined;
private readonly customRecursiveWatchDirectory: HostWatchDirectory | undefined;
public require: ((initialPath: string, moduleName: string) => server.RequireResult) | undefined;
@@ -349,9 +354,23 @@ interface Array<T> {}`
this.executingFilePath = this.getHostSpecificPath(executingFilePath);
this.currentDirectory = this.getHostSpecificPath(currentDirectory);
this.reloadFS(fileOrFolderorSymLinkList);
this.dynamicPriorityWatchFile = this.environmentVariables && this.environmentVariables.get("TSC_WATCHFILE") === "DynamicPriorityPolling" ?
createDynamicPriorityPollingWatchFile(this) :
undefined;
const tscWatchFile = this.environmentVariables && this.environmentVariables.get("TSC_WATCHFILE") as Tsc_WatchFile;
switch (tscWatchFile) {
case Tsc_WatchFile.DynamicPolling:
this.customWatchFile = createDynamicPriorityPollingWatchFile(this);
break;
case Tsc_WatchFile.SingleFileWatcherPerName:
this.customWatchFile = createSingleFileWatcherPerName(
this.watchFileWorker.bind(this),
this.useCaseSensitiveFileNames
);
break;
case undefined:
break;
default:
Debug.assertNever(tscWatchFile);
}
const tscWatchDirectory = this.environmentVariables && this.environmentVariables.get("TSC_WATCHDIRECTORY") as Tsc_WatchDirectory;
if (tscWatchDirectory === Tsc_WatchDirectory.WatchFile) {
const watchDirectory: HostWatchDirectory = (directory, cb) => this.watchFile(directory, () => cb(directory), PollingInterval.Medium);
@@ -405,7 +424,7 @@ interface Array<T> {}`
return s;
}
private now() {
now() {
this.time += timeIncrements;
return new Date(this.time);
}
@@ -854,10 +873,14 @@ interface Array<T> {}`
}
watchFile(fileName: string, cb: FileWatcherCallback, pollingInterval: number) {
if (this.dynamicPriorityWatchFile) {
return this.dynamicPriorityWatchFile(fileName, cb, pollingInterval);
if (this.customWatchFile) {
return this.customWatchFile(fileName, cb, pollingInterval);
}
return this.watchFileWorker(fileName, cb);
}
private watchFileWorker(fileName: string, cb: FileWatcherCallback) {
const path = this.toFullPath(fileName);
const callback: TestFileWatcher = { fileName, cb };
this.watchedFiles.add(path, callback);
+51 -24
View File
@@ -289,9 +289,8 @@ namespace ts.JsTyping {
}
export const enum PackageNameValidationResult {
export const enum NameValidationResult {
Ok,
ScopedPackagesNotSupported,
EmptyName,
NameTooLong,
NameStartsWithDot,
@@ -301,49 +300,77 @@ namespace ts.JsTyping {
const maxPackageNameLength = 214;
export interface ScopedPackageNameValidationResult {
name: string;
isScopeName: boolean;
result: NameValidationResult;
}
export type PackageNameValidationResult = NameValidationResult | ScopedPackageNameValidationResult;
/**
* Validates package name using rules defined at https://docs.npmjs.com/files/package.json
*/
export function validatePackageName(packageName: string): PackageNameValidationResult {
return validatePackageNameWorker(packageName, /*supportScopedPackage*/ true);
}
function validatePackageNameWorker(packageName: string, supportScopedPackage: false): NameValidationResult;
function validatePackageNameWorker(packageName: string, supportScopedPackage: true): PackageNameValidationResult;
function validatePackageNameWorker(packageName: string, supportScopedPackage: boolean): PackageNameValidationResult {
if (!packageName) {
return PackageNameValidationResult.EmptyName;
return NameValidationResult.EmptyName;
}
if (packageName.length > maxPackageNameLength) {
return PackageNameValidationResult.NameTooLong;
return NameValidationResult.NameTooLong;
}
if (packageName.charCodeAt(0) === CharacterCodes.dot) {
return PackageNameValidationResult.NameStartsWithDot;
return NameValidationResult.NameStartsWithDot;
}
if (packageName.charCodeAt(0) === CharacterCodes._) {
return PackageNameValidationResult.NameStartsWithUnderscore;
return NameValidationResult.NameStartsWithUnderscore;
}
// check if name is scope package like: starts with @ and has one '/' in the middle
// scoped packages are not currently supported
// TODO: when support will be added we'll need to split and check both scope and package name
if (/^@[^/]+\/[^/]+$/.test(packageName)) {
return PackageNameValidationResult.ScopedPackagesNotSupported;
if (supportScopedPackage) {
const matches = /^@([^/]+)\/([^/]+)$/.exec(packageName);
if (matches) {
const scopeResult = validatePackageNameWorker(matches[1], /*supportScopedPackage*/ false);
if (scopeResult !== NameValidationResult.Ok) {
return { name: matches[1], isScopeName: true, result: scopeResult };
}
const packageResult = validatePackageNameWorker(matches[2], /*supportScopedPackage*/ false);
if (packageResult !== NameValidationResult.Ok) {
return { name: matches[2], isScopeName: false, result: packageResult };
}
return NameValidationResult.Ok;
}
}
if (encodeURIComponent(packageName) !== packageName) {
return PackageNameValidationResult.NameContainsNonURISafeCharacters;
return NameValidationResult.NameContainsNonURISafeCharacters;
}
return PackageNameValidationResult.Ok;
return NameValidationResult.Ok;
}
export function renderPackageNameValidationFailure(result: PackageNameValidationResult, typing: string): string {
return typeof result === "object" ?
renderPackageNameValidationFailureWorker(typing, result.result, result.name, result.isScopeName) :
renderPackageNameValidationFailureWorker(typing, result, typing, /*isScopeName*/ false);
}
function renderPackageNameValidationFailureWorker(typing: string, result: NameValidationResult, name: string, isScopeName: boolean): string {
const kind = isScopeName ? "Scope" : "Package";
switch (result) {
case PackageNameValidationResult.EmptyName:
return `Package name '${typing}' cannot be empty`;
case PackageNameValidationResult.NameTooLong:
return `Package name '${typing}' should be less than ${maxPackageNameLength} characters`;
case PackageNameValidationResult.NameStartsWithDot:
return `Package name '${typing}' cannot start with '.'`;
case PackageNameValidationResult.NameStartsWithUnderscore:
return `Package name '${typing}' cannot start with '_'`;
case PackageNameValidationResult.ScopedPackagesNotSupported:
return `Package '${typing}' is scoped and currently is not supported`;
case PackageNameValidationResult.NameContainsNonURISafeCharacters:
return `Package name '${typing}' contains non URI safe characters`;
case PackageNameValidationResult.Ok:
case NameValidationResult.EmptyName:
return `'${typing}':: ${kind} name '${name}' cannot be empty`;
case NameValidationResult.NameTooLong:
return `'${typing}':: ${kind} name '${name}' should be less than ${maxPackageNameLength} characters`;
case NameValidationResult.NameStartsWithDot:
return `'${typing}':: ${kind} name '${name}' cannot start with '.'`;
case NameValidationResult.NameStartsWithUnderscore:
return `'${typing}':: ${kind} name '${name}' cannot start with '_'`;
case NameValidationResult.NameContainsNonURISafeCharacters:
return `'${typing}':: ${kind} name '${name}' contains non URI safe characters`;
case NameValidationResult.Ok:
return Debug.fail(); // Shouldn't have called this.
default:
throw Debug.assertNever(result);
+1 -1
View File
@@ -12,7 +12,7 @@ declare var Infinity: number;
declare function eval(x: string): any;
/**
* Converts A string to an integer.
* Converts a string to an integer.
* @param s A string to convert into a number.
* @param radix A value between 2 and 36 that specifies the base of the number in numString.
* If this argument is not supplied, strings with a prefix of '0x' are considered hexadecimal.
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<LCX SchemaVersion="6.0" Name="f:\ddSetup\sources\typescript\localization\compiler2.resx" PsrId="306" FileType="1" SrcCul="en-US" TgtCul="it-IT" xmlns="http://schemas.microsoft.com/locstudio/2006/6/lcx">
<Props>
<Str Name="CustomName1" Val="Custom 1" />
@@ -3301,7 +3301,7 @@
<Str Cat="Text">
<Val><![CDATA[Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Crea l'origine unitamente alle mappe di origine all'interno di un unico file. Richiede l'impostazione di '--inlineSourceMap' o '--sourceMap'.]]></Val>
<Val><![CDATA[Crea l'origine unitamente ai mapping di origine all'interno di un unico file. Richiede l'impostazione di '--inlineSourceMap' o '--sourceMap'.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -4123,7 +4123,7 @@
<Str Cat="Text">
<Val><![CDATA[Generates a sourcemap for each corresponding '.d.ts' file.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Genera un sourcemap per ogni file '.d.ts' corrispondente.]]></Val>
<Val><![CDATA[Genera un mapping di origine per ogni file '.d.ts' corrispondente.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<LCX SchemaVersion="6.0" Name="f:\ddSetup\sources\typescript\localization\compiler2.resx" PsrId="306" FileType="1" SrcCul="en-US" TgtCul="ru-RU" xmlns="http://schemas.microsoft.com/locstudio/2006/6/lcx">
<Props>
<Str Name="CustomName1" Val="Custom 1" />
@@ -3300,7 +3300,7 @@
<Str Cat="Text">
<Val><![CDATA[Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Порождать источник вместе с sourcemap в одном файле (нужно задать параметр --inlineSourceMap или --sourceMap).]]></Val>
<Val><![CDATA[Порождать источник вместе с сопоставителями с исходным кодом в одном файле (нужно задать параметр --inlineSourceMap или --sourceMap).]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -4122,7 +4122,7 @@
<Str Cat="Text">
<Val><![CDATA[Generates a sourcemap for each corresponding '.d.ts' file.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Создает sourcemap для каждого соответствующего файла ".d.ts".]]></Val>
<Val><![CDATA[Создает сопоставитель с исходным кодом для каждого соответствующего файла ".d.ts".]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
+48 -12
View File
@@ -284,6 +284,10 @@ namespace ts.server {
configFileErrors?: ReadonlyArray<Diagnostic>;
}
interface AssignProjectResult extends OpenConfiguredProjectResult {
defaultConfigProject: ConfiguredProject | undefined;
}
interface FilePropertyReader<T> {
getFileName(f: T): string;
getScriptKind(f: T, extraFileExtensions?: FileExtensionInfo[]): ScriptKind;
@@ -1087,7 +1091,24 @@ namespace ts.server {
project.close();
if (Debug.shouldAssert(AssertionLevel.Normal)) {
this.filenameToScriptInfo.forEach(info => Debug.assert(!info.isAttached(project), "Found script Info still attached to project", () => `${project.projectName}: ScriptInfos still attached: ${JSON.stringify(mapDefined(arrayFrom(this.filenameToScriptInfo.values()), info => info.isAttached(project) ? info : undefined))}`));
this.filenameToScriptInfo.forEach(info => Debug.assert(
!info.isAttached(project),
"Found script Info still attached to project",
() => `${project.projectName}: ScriptInfos still attached: ${JSON.stringify(
arrayFrom(
mapDefinedIterator(
this.filenameToScriptInfo.values(),
info => info.isAttached(project) ?
{
fileName: info.fileName,
projects: info.containingProjects.map(p => p.projectName),
hasMixedContent: info.hasMixedContent
} : undefined
)
),
/*replacer*/ undefined,
" "
)}`));
}
// Remove the project from pending project updates
this.pendingProjectUpdates.delete(project.getProjectName());
@@ -2618,10 +2639,11 @@ namespace ts.server {
return info;
}
private assignProjectToOpenedScriptInfo(info: ScriptInfo): OpenConfiguredProjectResult {
private assignProjectToOpenedScriptInfo(info: ScriptInfo): AssignProjectResult {
let configFileName: NormalizedPath | undefined;
let configFileErrors: ReadonlyArray<Diagnostic> | undefined;
let project: ConfiguredProject | ExternalProject | undefined = this.findExternalProjectContainingOpenScriptInfo(info);
let defaultConfigProject: ConfiguredProject | undefined;
if (!project && !this.syntaxOnly) { // Checking syntaxOnly is an optimization
configFileName = this.getConfigFileNameForFile(info);
if (configFileName) {
@@ -2642,6 +2664,7 @@ namespace ts.server {
// Ensure project is ready to check if it contains opened script info
updateProjectIfDirty(project);
}
defaultConfigProject = project;
}
}
@@ -2661,13 +2684,13 @@ namespace ts.server {
this.assignOrphanScriptInfoToInferredProject(info, this.openFiles.get(info.path));
}
Debug.assert(!info.isOrphan());
return { configFileName, configFileErrors };
return { configFileName, configFileErrors, defaultConfigProject };
}
private cleanupAfterOpeningFile() {
private cleanupAfterOpeningFile(toRetainConfigProjects: ConfiguredProject[] | ConfiguredProject | undefined) {
// This was postponed from closeOpenFile to after opening next file,
// so that we can reuse the project if we need to right away
this.removeOrphanConfiguredProjects();
this.removeOrphanConfiguredProjects(toRetainConfigProjects);
// Remove orphan inferred projects now that we have reused projects
// We need to create a duplicate because we cant guarantee order after removal
@@ -2688,14 +2711,22 @@ namespace ts.server {
openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult {
const info = this.getOrCreateOpenScriptInfo(fileName, fileContent, scriptKind, hasMixedContent, projectRootPath);
const result = this.assignProjectToOpenedScriptInfo(info);
this.cleanupAfterOpeningFile();
const { defaultConfigProject, ...result } = this.assignProjectToOpenedScriptInfo(info);
this.cleanupAfterOpeningFile(defaultConfigProject);
this.telemetryOnOpenFile(info);
return result;
}
private removeOrphanConfiguredProjects() {
private removeOrphanConfiguredProjects(toRetainConfiguredProjects: ConfiguredProject[] | ConfiguredProject | undefined) {
const toRemoveConfiguredProjects = cloneMap(this.configuredProjects);
if (toRetainConfiguredProjects) {
if (isArray(toRetainConfiguredProjects)) {
toRetainConfiguredProjects.forEach(retainConfiguredProject);
}
else {
retainConfiguredProject(toRetainConfiguredProjects);
}
}
// Do not remove configured projects that are used as original projects of other
this.inferredProjects.forEach(markOriginalProjectsAsUsed);
@@ -2703,7 +2734,7 @@ namespace ts.server {
this.configuredProjects.forEach(project => {
// If project has open ref (there are more than zero references from external project/open file), keep it alive as well as any project it references
if (project.hasOpenRef()) {
toRemoveConfiguredProjects.delete(project.canonicalConfigFilePath);
retainConfiguredProject(project);
markOriginalProjectsAsUsed(project);
}
else {
@@ -2712,7 +2743,7 @@ namespace ts.server {
if (ref) {
const refProject = this.configuredProjects.get(ref.sourceFile.path);
if (refProject && refProject.hasOpenRef()) {
toRemoveConfiguredProjects.delete(project.canonicalConfigFilePath);
retainConfiguredProject(project);
}
}
});
@@ -2727,6 +2758,10 @@ namespace ts.server {
project.originalConfiguredProjects.forEach((_value, configuredProjectPath) => toRemoveConfiguredProjects.delete(configuredProjectPath));
}
}
function retainConfiguredProject(project: ConfiguredProject) {
toRemoveConfiguredProjects.delete(project.canonicalConfigFilePath);
}
}
private removeOrphanScriptInfos() {
@@ -2869,8 +2904,9 @@ namespace ts.server {
}
// All the script infos now exist, so ok to go update projects for open files
let defaultConfigProjects: ConfiguredProject[] | undefined;
if (openScriptInfos) {
openScriptInfos.forEach(info => this.assignProjectToOpenedScriptInfo(info));
defaultConfigProjects = mapDefined(openScriptInfos, info => this.assignProjectToOpenedScriptInfo(info).defaultConfigProject);
}
// While closing files there could be open files that needed assigning new inferred projects, do it now
@@ -2879,7 +2915,7 @@ namespace ts.server {
}
// Cleanup projects
this.cleanupAfterOpeningFile();
this.cleanupAfterOpeningFile(defaultConfigProjects);
// Telemetry
forEach(openScriptInfos, info => this.telemetryOnOpenFile(info));
+7 -2
View File
@@ -851,6 +851,7 @@ namespace ts.server {
* @returns: true if set of files in the project stays the same and false - otherwise.
*/
updateGraph(): boolean {
perfLogger.logStartUpdateGraph();
this.resolutionCache.startRecordingFilesWithChangedResolutions();
const hasNewProgram = this.updateGraphWorker();
@@ -886,6 +887,7 @@ namespace ts.server {
if (hasNewProgram) {
this.projectProgramVersion++;
}
perfLogger.logStopUpdateGraph();
return !hasNewProgram;
}
@@ -1007,9 +1009,12 @@ namespace ts.server {
);
const elapsed = timestamp() - start;
this.writeLog(`Finishing updateGraphWorker: Project: ${this.getProjectName()} Version: ${this.getProjectVersion()} structureChanged: ${hasNewProgram} Elapsed: ${elapsed}ms`);
if (this.program !== oldProgram) {
if (this.hasAddedorRemovedFiles) {
this.print();
}
else if (this.program !== oldProgram) {
this.writeLog(`Different program with same set of files:: oldProgram.structureIsReused:: ${oldProgram && oldProgram.structureIsReused}`);
}
return hasNewProgram;
}
@@ -1275,7 +1280,7 @@ namespace ts.server {
private enableProxy(pluginModuleFactory: PluginModuleFactory, configEntry: PluginImport) {
try {
if (typeof pluginModuleFactory !== "function") {
this.projectService.logger.info(`Skipped loading plugin ${configEntry.name} because it did expose a proper factory function`);
this.projectService.logger.info(`Skipped loading plugin ${configEntry.name} because it did not expose a proper factory function`);
return;
}
+35 -11
View File
@@ -42,6 +42,11 @@ namespace ts.server {
return false;
}
function dtsChangeCanAffectEmit(compilationSettings: CompilerOptions) {
return getEmitDeclarations(compilationSettings) || !!compilationSettings.emitDecoratorMetadata;
}
function formatDiag(fileName: NormalizedPath, project: Project, diag: Diagnostic): protocol.Diagnostic {
const scriptInfo = project.getScriptInfoForNormalizedPath(fileName)!; // TODO: GH#18217
return {
@@ -684,7 +689,7 @@ namespace ts.server {
this.logErrorWorker(err, cmd);
}
private logErrorWorker(err: Error, cmd: string, fileRequest?: protocol.FileRequestArgs): void {
private logErrorWorker(err: Error & PossibleProgramFileInfo, cmd: string, fileRequest?: protocol.FileRequestArgs): void {
let msg = "Exception on executing command " + cmd;
if (err.message) {
msg += ":\n" + indent(err.message);
@@ -706,7 +711,9 @@ namespace ts.server {
catch { } // tslint:disable-line no-empty
}
if (err.message && err.message.indexOf(`Could not find sourceFile:`) !== -1) {
if (err.ProgramFiles) {
msg += `\n\nProgram files: ${JSON.stringify(err.ProgramFiles)}\n`;
msg += `\n\nProjects::\n`;
let counter = 0;
const addProjectInfo = (project: Project) => {
@@ -731,7 +738,9 @@ namespace ts.server {
}
return;
}
this.host.write(formatMessage(msg, this.logger, this.byteLength, this.host.newLine));
const msgText = formatMessage(msg, this.logger, this.byteLength, this.host.newLine);
perfLogger.logEvent(`Response message size: ${msgText.length}`);
this.host.write(msgText);
}
public event<T extends object>(body: T, eventName: string): void {
@@ -1604,15 +1613,22 @@ namespace ts.server {
path => this.projectService.getScriptInfoForPath(path)!,
projects,
(project, info) => {
let result: protocol.CompileOnSaveAffectedFileListSingleProject | undefined;
if (project.compileOnSaveEnabled && project.languageServiceEnabled && !project.isOrphan() && !project.getCompilationSettings().noEmit) {
result = {
projectFileName: project.getProjectName(),
fileNames: project.getCompileOnSaveAffectedFileList(info),
projectUsesOutFile: !!project.getCompilationSettings().outFile || !!project.getCompilationSettings().out
};
if (!project.compileOnSaveEnabled || !project.languageServiceEnabled || project.isOrphan()) {
return undefined;
}
return result;
const compilationSettings = project.getCompilationSettings();
if (!!compilationSettings.noEmit || fileExtensionIs(info.fileName, Extension.Dts) && !dtsChangeCanAffectEmit(compilationSettings)) {
// avoid triggering emit when a change is made in a .d.ts when declaration emit and decorator metadata emit are disabled
return undefined;
}
return {
projectFileName: project.getProjectName(),
fileNames: project.getCompileOnSaveAffectedFileList(info),
projectUsesOutFile: !!compilationSettings.outFile || !!compilationSettings.out
};
}
);
}
@@ -2509,6 +2525,8 @@ namespace ts.server {
try {
request = <protocol.Request>JSON.parse(message);
relevantFile = request.arguments && (request as protocol.FileRequest).arguments.file ? (request as protocol.FileRequest).arguments : undefined;
perfLogger.logStartCommand("" + request.command, message.substring(0, 100));
const { response, responseRequired } = this.executeCommand(request);
if (this.logger.hasLevel(LogLevel.requestTime)) {
@@ -2521,6 +2539,8 @@ namespace ts.server {
}
}
// Note: Log before writing the response, else the editor can complete its activity before the server does
perfLogger.logStopCommand("" + request.command, "Success");
if (response) {
this.doOutput(response, request.command, request.seq, /*success*/ true);
}
@@ -2531,10 +2551,14 @@ namespace ts.server {
catch (err) {
if (err instanceof OperationCanceledException) {
// Handle cancellation exceptions
perfLogger.logStopCommand("" + (request && request.command), "Canceled: " + err);
this.doOutput({ canceled: true }, request!.command, request!.seq, /*success*/ true);
return;
}
this.logErrorWorker(err, message, relevantFile);
perfLogger.logStopCommand("" + (request && request.command), "Error: " + err);
this.doOutput(
/*info*/ undefined,
request ? request.command : CommandNames.Unknown,
+4
View File
@@ -150,11 +150,13 @@ namespace ts.server {
}
private static run(self: ThrottledOperations, operationId: string, cb: () => void) {
perfLogger.logStartScheduledOperation(operationId);
self.pendingTimeouts.delete(operationId);
if (self.logger) {
self.logger.info(`Running: ${operationId}`);
}
cb();
perfLogger.logStopScheduledOperation();
}
}
@@ -174,6 +176,7 @@ namespace ts.server {
private static run(self: GcTimer) {
self.timerId = undefined;
perfLogger.logStartScheduledOperation("GC collect");
const log = self.logger.hasLevel(LogLevel.requestTime);
const before = log && self.host.getMemoryUsage!(); // TODO: GH#18217
@@ -182,6 +185,7 @@ namespace ts.server {
const after = self.host.getMemoryUsage!(); // TODO: GH#18217
self.logger.perftrc(`GC::before ${before}, after ${after}`);
}
perfLogger.logStopScheduledOperation();
}
}
+84
View File
@@ -1,4 +1,5 @@
namespace ts {
/** The classifier is used for syntactic highlighting in editors via the TSServer */
export function createClassifier(): Classifier {
const scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false);
@@ -683,6 +684,11 @@ namespace ts {
return;
}
}
else if (kind === SyntaxKind.SingleLineCommentTrivia) {
if (tryClassifyTripleSlashComment(start, width)) {
return;
}
}
// Simple comment. Just add as is.
pushCommentRange(start, width);
@@ -755,6 +761,84 @@ namespace ts {
}
}
function tryClassifyTripleSlashComment(start: number, width: number): boolean {
const tripleSlashXMLCommentRegEx = /^(\/\/\/\s*)(<)(?:(\S+)((?:[^/]|\/[^>])*)(\/>)?)?/im;
const attributeRegex = /(\S+)(\s*)(=)(\s*)('[^']+'|"[^"]+")/img;
const text = sourceFile.text.substr(start, width);
const match = tripleSlashXMLCommentRegEx.exec(text);
if (!match) {
return false;
}
let pos = start;
pushCommentRange(pos, match[1].length); // ///
pos += match[1].length;
pushClassification(pos, match[2].length, ClassificationType.punctuation); // <
pos += match[2].length;
if (!match[3]) {
return true;
}
pushClassification(pos, match[3].length, ClassificationType.jsxSelfClosingTagName); // element name
pos += match[3].length;
const attrText = match[4];
let attrPos = pos;
while (true) {
const attrMatch = attributeRegex.exec(attrText);
if (!attrMatch) {
break;
}
const newAttrPos = pos + attrMatch.index;
if (newAttrPos > attrPos) {
pushCommentRange(attrPos, newAttrPos - attrPos);
attrPos = newAttrPos;
}
pushClassification(attrPos, attrMatch[1].length, ClassificationType.jsxAttribute); // attribute name
attrPos += attrMatch[1].length;
if (attrMatch[2].length) {
pushCommentRange(attrPos, attrMatch[2].length); // whitespace
attrPos += attrMatch[2].length;
}
pushClassification(attrPos, attrMatch[3].length, ClassificationType.operator); // =
attrPos += attrMatch[3].length;
if (attrMatch[4].length) {
pushCommentRange(attrPos, attrMatch[4].length); // whitespace
attrPos += attrMatch[4].length;
}
pushClassification(attrPos, attrMatch[5].length, ClassificationType.jsxAttributeStringLiteralValue); // attribute value
attrPos += attrMatch[5].length;
}
pos += match[4].length;
if (pos > attrPos) {
pushCommentRange(attrPos, pos - attrPos);
}
if (match[5]) {
pushClassification(pos, match[5].length, ClassificationType.punctuation); // />
pos += match[5].length;
}
const end = start + width;
if (pos < end) {
pushCommentRange(pos, end - pos);
}
return true;
}
function processJSDocTemplateTag(tag: JSDocTemplateTag) {
for (const child of tag.getChildren()) {
processElement(child);
+42 -10
View File
@@ -55,10 +55,9 @@ namespace ts.codefix {
const modifiers = visibilityModifier ? createNodeArray([visibilityModifier]) : undefined;
const type = checker.getWidenedType(checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration));
const optional = !!(symbol.flags & SymbolFlags.Optional);
const ambient = !!(enclosingDeclaration.flags & NodeFlags.Ambient);
switch (declaration.kind) {
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.PropertySignature:
case SyntaxKind.PropertyDeclaration:
const typeNode = checker.typeToTypeNode(type, enclosingDeclaration, /*flags*/ undefined, getNoopSymbolTrackerWithResolver(context));
@@ -70,6 +69,37 @@ namespace ts.codefix {
typeNode,
/*initializer*/ undefined));
break;
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor: {
const allAccessors = getAllAccessorDeclarations(declarations, declaration as AccessorDeclaration);
const typeNode = checker.typeToTypeNode(type, enclosingDeclaration, /*flags*/ undefined, getNoopSymbolTrackerWithResolver(context));
const orderedAccessors = allAccessors.secondAccessor
? [allAccessors.firstAccessor, allAccessors.secondAccessor]
: [allAccessors.firstAccessor];
for (const accessor of orderedAccessors) {
if (isGetAccessorDeclaration(accessor)) {
out(createGetAccessor(
/*decorators*/ undefined,
modifiers,
name,
emptyArray,
typeNode,
ambient ? undefined : createStubbedMethodBody(preferences)));
}
else {
Debug.assertNode(accessor, isSetAccessorDeclaration);
const parameter = getSetAccessorValueParameter(accessor);
const parameterName = parameter && isIdentifier(parameter.name) ? idText(parameter.name) : undefined;
out(createSetAccessor(
/*decorators*/ undefined,
modifiers,
name,
createDummyParameters(1, [parameterName], [typeNode], 1, /*inJs*/ false),
ambient ? undefined : createStubbedMethodBody(preferences)));
}
}
break;
}
case SyntaxKind.MethodSignature:
case SyntaxKind.MethodDeclaration:
// The signature for the implementation appears as an entry in `signatures` iff
@@ -87,7 +117,7 @@ namespace ts.codefix {
if (declarations.length === 1) {
Debug.assert(signatures.length === 1);
const signature = signatures[0];
outputMethod(signature, modifiers, name, createStubbedMethodBody(preferences));
outputMethod(signature, modifiers, name, ambient ? undefined : createStubbedMethodBody(preferences));
break;
}
@@ -96,13 +126,15 @@ namespace ts.codefix {
outputMethod(signature, getSynthesizedDeepClones(modifiers, /*includeTrivia*/ false), getSynthesizedDeepClone(name, /*includeTrivia*/ false));
}
if (declarations.length > signatures.length) {
const signature = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration)!;
outputMethod(signature, modifiers, name, createStubbedMethodBody(preferences));
}
else {
Debug.assert(declarations.length === signatures.length);
out(createMethodImplementingSignatures(signatures, name, optional, modifiers, preferences));
if (!ambient) {
if (declarations.length > signatures.length) {
const signature = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration)!;
outputMethod(signature, modifiers, name, createStubbedMethodBody(preferences));
}
else {
Debug.assert(declarations.length === signatures.length);
out(createMethodImplementingSignatures(signatures, name, optional, modifiers, preferences));
}
}
break;
}
+63 -19
View File
@@ -135,7 +135,8 @@ namespace ts.codefix {
Named,
Default,
Namespace,
Equals
Equals,
ConstEquals
}
/** Information about how a symbol is exported from a module. (We don't need to store the exported symbol, just its module.) */
@@ -163,7 +164,7 @@ namespace ts.codefix {
position: number,
preferences: UserPreferences,
): { readonly moduleSpecifier: string, readonly codeAction: CodeAction } {
const exportInfos = getAllReExportingModules(exportedSymbol, moduleSymbol, symbolName, sourceFile, program.getCompilerOptions(), program.getTypeChecker(), program.getSourceFiles());
const exportInfos = getAllReExportingModules(sourceFile, exportedSymbol, moduleSymbol, symbolName, sourceFile, program.getCompilerOptions(), program.getTypeChecker(), program.getSourceFiles());
Debug.assert(exportInfos.some(info => info.moduleSymbol === moduleSymbol));
// We sort the best codefixes first, so taking `first` is best for completions.
const moduleSpecifier = first(getNewImportInfos(program, sourceFile, position, exportInfos, host, preferences)).moduleSpecifier;
@@ -175,7 +176,7 @@ namespace ts.codefix {
return { description, changes, commands };
}
function getAllReExportingModules(exportedSymbol: Symbol, exportingModuleSymbol: Symbol, symbolName: string, sourceFile: SourceFile, compilerOptions: CompilerOptions, checker: TypeChecker, allSourceFiles: ReadonlyArray<SourceFile>): ReadonlyArray<SymbolExportInfo> {
function getAllReExportingModules(importingFile: SourceFile, exportedSymbol: Symbol, exportingModuleSymbol: Symbol, symbolName: string, sourceFile: SourceFile, compilerOptions: CompilerOptions, checker: TypeChecker, allSourceFiles: ReadonlyArray<SourceFile>): ReadonlyArray<SymbolExportInfo> {
const result: SymbolExportInfo[] = [];
forEachExternalModule(checker, allSourceFiles, (moduleSymbol, moduleFile) => {
// Don't import from a re-export when looking "up" like to `./index` or `../index`.
@@ -183,7 +184,7 @@ namespace ts.codefix {
return;
}
const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions);
const defaultInfo = getDefaultLikeExportInfo(importingFile, moduleSymbol, checker, compilerOptions);
if (defaultInfo && defaultInfo.name === symbolName && skipAlias(defaultInfo.symbol, checker) === exportedSymbol) {
result.push({ moduleSymbol, importKind: defaultInfo.kind, exportedSymbolIsTypeOnly: isTypeOnlySymbol(defaultInfo.symbol, checker) });
}
@@ -329,7 +330,7 @@ namespace ts.codefix {
if (!umdSymbol) return undefined;
const symbol = checker.getAliasedSymbol(umdSymbol);
const symbolName = umdSymbol.name;
const exportInfos: ReadonlyArray<SymbolExportInfo> = [{ moduleSymbol: symbol, importKind: getUmdImportKind(program.getCompilerOptions()), exportedSymbolIsTypeOnly: false }];
const exportInfos: ReadonlyArray<SymbolExportInfo> = [{ moduleSymbol: symbol, importKind: getUmdImportKind(sourceFile, program.getCompilerOptions()), exportedSymbolIsTypeOnly: false }];
const fixes = getFixForImport(exportInfos, symbolName, isIdentifier(token) ? token.getStart(sourceFile) : undefined, program, sourceFile, host, preferences);
return { fixes, symbolName };
}
@@ -345,7 +346,7 @@ namespace ts.codefix {
: undefined;
}
function getUmdImportKind(compilerOptions: CompilerOptions): ImportKind {
function getUmdImportKind(importingFile: SourceFile, compilerOptions: CompilerOptions): ImportKind {
// Import a synthetic `default` if enabled.
if (getAllowSyntheticDefaultImports(compilerOptions)) {
return ImportKind.Default;
@@ -357,7 +358,10 @@ namespace ts.codefix {
case ModuleKind.AMD:
case ModuleKind.CommonJS:
case ModuleKind.UMD:
return ImportKind.Equals;
if (isInJSFile(importingFile)) {
return isExternalModule(importingFile) ? ImportKind.Namespace : ImportKind.ConstEquals;
}
return ImportKind.Equals;
case ModuleKind.System:
case ModuleKind.ES2015:
case ModuleKind.ESNext:
@@ -403,7 +407,7 @@ namespace ts.codefix {
forEachExternalModuleToImportFrom(checker, sourceFile, program.getSourceFiles(), moduleSymbol => {
cancellationToken.throwIfCancellationRequested();
const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, program.getCompilerOptions());
const defaultInfo = getDefaultLikeExportInfo(sourceFile, moduleSymbol, checker, program.getCompilerOptions());
if (defaultInfo && defaultInfo.name === symbolName && symbolHasMeaning(defaultInfo.symbolForMeaning, currentTokenMeaning)) {
addSymbol(moduleSymbol, defaultInfo.symbol, defaultInfo.kind);
}
@@ -418,20 +422,41 @@ namespace ts.codefix {
}
function getDefaultLikeExportInfo(
moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions,
): { readonly symbol: Symbol, readonly symbolForMeaning: Symbol, readonly name: string, readonly kind: ImportKind.Default | ImportKind.Equals } | undefined {
const exported = getDefaultLikeExportWorker(moduleSymbol, checker);
importingFile: SourceFile, moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions,
): { readonly symbol: Symbol, readonly symbolForMeaning: Symbol, readonly name: string, readonly kind: ImportKind } | undefined {
const exported = getDefaultLikeExportWorker(importingFile, moduleSymbol, checker, compilerOptions);
if (!exported) return undefined;
const { symbol, kind } = exported;
const info = getDefaultExportInfoWorker(symbol, moduleSymbol, checker, compilerOptions);
return info && { symbol, kind, ...info };
}
function getDefaultLikeExportWorker(moduleSymbol: Symbol, checker: TypeChecker): { readonly symbol: Symbol, readonly kind: ImportKind.Default | ImportKind.Equals } | undefined {
function getDefaultLikeExportWorker(importingFile: SourceFile, moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions): { readonly symbol: Symbol, readonly kind: ImportKind } | undefined {
const defaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol);
if (defaultExport) return { symbol: defaultExport, kind: ImportKind.Default };
const exportEquals = checker.resolveExternalModuleSymbol(moduleSymbol);
return exportEquals === moduleSymbol ? undefined : { symbol: exportEquals, kind: ImportKind.Equals };
return exportEquals === moduleSymbol ? undefined : { symbol: exportEquals, kind: getExportEqualsImportKind(importingFile, compilerOptions, checker) };
}
function getExportEqualsImportKind(importingFile: SourceFile, compilerOptions: CompilerOptions, checker: TypeChecker): ImportKind {
if (getAllowSyntheticDefaultImports(compilerOptions) && getEmitModuleKind(compilerOptions) >= ModuleKind.ES2015) {
return ImportKind.Default;
}
if (isInJSFile(importingFile)) {
return isExternalModule(importingFile) ? ImportKind.Default : ImportKind.ConstEquals;
}
for (const statement of importingFile.statements) {
if (isImportEqualsDeclaration(statement)) {
return ImportKind.Equals;
}
if (isImportDeclaration(statement) && statement.importClause && statement.importClause.name) {
const moduleSymbol = checker.getImmediateAliasedSymbol(statement.importClause.symbol);
if (moduleSymbol && moduleSymbol.name !== InternalSymbolName.Default) {
return ImportKind.Default;
}
}
}
return ImportKind.Equals;
}
function getDefaultExportInfoWorker(defaultExport: Symbol, moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions): { readonly symbolForMeaning: Symbol, readonly name: string } | undefined {
@@ -445,9 +470,12 @@ namespace ts.codefix {
const aliased = checker.getImmediateAliasedSymbol(defaultExport);
return aliased && getDefaultExportInfoWorker(aliased, Debug.assertDefined(aliased.parent), checker, compilerOptions);
}
else {
return { symbolForMeaning: defaultExport, name: moduleSymbolToValidIdentifier(moduleSymbol, compilerOptions.target!) };
if (defaultExport.escapedName !== InternalSymbolName.Default &&
defaultExport.escapedName !== InternalSymbolName.ExportEquals) {
return { symbolForMeaning: defaultExport, name: defaultExport.getName() };
}
return { symbolForMeaning: defaultExport, name: moduleSymbolToValidIdentifier(moduleSymbol, compilerOptions.target!) };
}
function getNameForExportDefault(symbol: Symbol): string | undefined {
@@ -540,7 +568,10 @@ namespace ts.codefix {
interface ImportsCollection {
readonly defaultImport: string | undefined;
readonly namedImports: string[];
readonly namespaceLikeImport: { readonly importKind: ImportKind.Equals | ImportKind.Namespace, readonly name: string } | undefined;
readonly namespaceLikeImport: {
readonly importKind: ImportKind.Equals | ImportKind.Namespace | ImportKind.ConstEquals;
readonly name: string;
} | undefined;
}
function addNewImports(changes: textChanges.ChangeTracker, sourceFile: SourceFile, moduleSpecifier: string, quotePreference: QuotePreference, { defaultImport, namedImports, namespaceLikeImport }: ImportsCollection): void {
const quotedModuleSpecifier = makeStringLiteral(moduleSpecifier, quotePreference);
@@ -551,12 +582,25 @@ namespace ts.codefix {
namedImports.map(n => createImportSpecifier(/*propertyName*/ undefined, createIdentifier(n))), moduleSpecifier, quotePreference));
}
if (namespaceLikeImport) {
insertImport(changes, sourceFile, namespaceLikeImport.importKind === ImportKind.Equals
? createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createIdentifier(namespaceLikeImport.name), createExternalModuleReference(quotedModuleSpecifier))
: createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createImportClause(/*name*/ undefined, createNamespaceImport(createIdentifier(namespaceLikeImport.name))), quotedModuleSpecifier));
insertImport(
changes,
sourceFile,
namespaceLikeImport.importKind === ImportKind.Equals ? createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createIdentifier(namespaceLikeImport.name), createExternalModuleReference(quotedModuleSpecifier)) :
namespaceLikeImport.importKind === ImportKind.ConstEquals ? createConstEqualsRequireDeclaration(namespaceLikeImport.name, quotedModuleSpecifier) :
createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createImportClause(/*name*/ undefined, createNamespaceImport(createIdentifier(namespaceLikeImport.name))), quotedModuleSpecifier));
}
}
function createConstEqualsRequireDeclaration(name: string, quotedModuleSpecifier: StringLiteral): VariableStatement {
return createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([
createVariableDeclaration(
createIdentifier(name),
/*type*/ undefined,
createCall(createIdentifier("require"), /*typeArguments*/ undefined, [quotedModuleSpecifier])
)
], NodeFlags.Const));
}
function symbolHasMeaning({ declarations }: Symbol, meaning: SemanticMeaning): boolean {
return some(declarations, decl => !!(getMeaningFromDeclaration(decl) & meaning));
}
+22 -16
View File
@@ -947,11 +947,13 @@ namespace ts.Completions {
// Right of dot member completion list
completionKind = CompletionKind.PropertyAccess;
// Since this is qualified name check its a type node location
// Since this is qualified name check it's a type node location
const isImportType = isLiteralImportTypeNode(node);
const isTypeLocation = insideJsDocTagTypeExpression || (isImportType && !(node as ImportTypeNode).isTypeOf) || isPartOfTypeNode(node.parent);
const isTypeLocation = insideJsDocTagTypeExpression
|| (isImportType && !(node as ImportTypeNode).isTypeOf)
|| isPartOfTypeNode(node.parent)
|| isPossiblyTypeArgumentPosition(contextToken, sourceFile, typeChecker);
const isRhsOfImportDeclaration = isInRightSideOfInternalImportEqualsDeclaration(node);
const allowTypeOrValue = isRhsOfImportDeclaration || (!isTypeLocation && isPossiblyTypeArgumentPosition(contextToken, sourceFile, typeChecker));
if (isEntityName(node) || isImportType) {
const isNamespaceName = isModuleDeclaration(node.parent);
if (isNamespaceName) isNewIdentifierLocation = true;
@@ -968,7 +970,7 @@ namespace ts.Completions {
isNamespaceName
// At `namespace N.M/**/`, if this is the only declaration of `M`, don't include `M` as a completion.
? symbol => !!(symbol.flags & SymbolFlags.Namespace) && !symbol.declarations.every(d => d.parent === node.parent)
: allowTypeOrValue ?
: isRhsOfImportDeclaration ?
// Any kind is allowed when dotting off namespace in internal import equals declaration
symbol => isValidTypeAccess(symbol) || isValidValueAccess(symbol) :
isTypeLocation ? isValidTypeAccess : isValidValueAccess;
@@ -1181,7 +1183,6 @@ namespace ts.Completions {
function filterGlobalCompletion(symbols: Symbol[]): void {
const isTypeOnly = isTypeOnlyCompletion();
const allowTypes = isTypeOnly || !isContextTokenValueLocation(contextToken) && isPossiblyTypeArgumentPosition(contextToken, sourceFile, typeChecker);
if (isTypeOnly) {
keywordFilters = isTypeAssertion()
? KeywordCompletionFilters.TypeAssertionKeywords
@@ -1202,12 +1203,9 @@ namespace ts.Completions {
return !!(symbol.flags & SymbolFlags.Namespace);
}
if (allowTypes) {
// Its a type, but you can reach it by namespace.type as well
const symbolAllowedAsType = symbolCanBeReferencedAtTypeLocation(symbol);
if (symbolAllowedAsType || isTypeOnly) {
return symbolAllowedAsType;
}
if (isTypeOnly) {
// It's a type, but you can reach it by namespace.type as well
return symbolCanBeReferencedAtTypeLocation(symbol);
}
}
@@ -1221,7 +1219,11 @@ namespace ts.Completions {
}
function isTypeOnlyCompletion(): boolean {
return insideJsDocTagTypeExpression || !isContextTokenValueLocation(contextToken) && (isPartOfTypeNode(location) || isContextTokenTypeLocation(contextToken));
return insideJsDocTagTypeExpression
|| !isContextTokenValueLocation(contextToken) &&
(isPossiblyTypeArgumentPosition(contextToken, sourceFile, typeChecker)
|| isPartOfTypeNode(location)
|| isContextTokenTypeLocation(contextToken));
}
function isContextTokenValueLocation(contextToken: Node) {
@@ -2060,16 +2062,18 @@ namespace ts.Completions {
case KeywordCompletionFilters.None:
return false;
case KeywordCompletionFilters.All:
return kind === SyntaxKind.AsyncKeyword || SyntaxKind.AwaitKeyword || !isContextualKeyword(kind) && !isClassMemberCompletionKeyword(kind) || kind === SyntaxKind.DeclareKeyword || kind === SyntaxKind.ModuleKeyword
return isFunctionLikeBodyKeyword(kind)
|| kind === SyntaxKind.DeclareKeyword
|| kind === SyntaxKind.ModuleKeyword
|| isTypeKeyword(kind) && kind !== SyntaxKind.UndefinedKeyword;
case KeywordCompletionFilters.FunctionLikeBodyKeywords:
return isFunctionLikeBodyKeyword(kind);
case KeywordCompletionFilters.ClassElementKeywords:
return isClassMemberCompletionKeyword(kind);
case KeywordCompletionFilters.InterfaceElementKeywords:
return isInterfaceOrTypeLiteralCompletionKeyword(kind);
case KeywordCompletionFilters.ConstructorParameterKeywords:
return isParameterPropertyModifier(kind);
case KeywordCompletionFilters.FunctionLikeBodyKeywords:
return isFunctionLikeBodyKeyword(kind);
case KeywordCompletionFilters.TypeAssertionKeywords:
return isTypeKeyword(kind) || kind === SyntaxKind.ConstKeyword;
case KeywordCompletionFilters.TypeKeywords:
@@ -2132,7 +2136,9 @@ namespace ts.Completions {
}
function isFunctionLikeBodyKeyword(kind: SyntaxKind) {
return kind === SyntaxKind.AsyncKeyword || kind === SyntaxKind.AwaitKeyword || !isContextualKeyword(kind) && !isClassMemberCompletionKeyword(kind);
return kind === SyntaxKind.AsyncKeyword
|| kind === SyntaxKind.AwaitKeyword
|| !isContextualKeyword(kind) && !isClassMemberCompletionKeyword(kind);
}
function keywordForNode(node: Node): SyntaxKind {
+4 -2
View File
@@ -193,7 +193,7 @@ namespace ts.DocumentHighlights {
function getNodesToSearchForModifier(declaration: Node, modifierFlag: ModifierFlags): ReadonlyArray<Node> | undefined {
// Types of node whose children might have modifiers.
const container = declaration.parent as ModuleBlock | SourceFile | Block | CaseClause | DefaultClause | ConstructorDeclaration | MethodDeclaration | FunctionDeclaration | ClassLikeDeclaration;
const container = declaration.parent as ModuleBlock | SourceFile | Block | CaseClause | DefaultClause | ConstructorDeclaration | MethodDeclaration | FunctionDeclaration | ObjectTypeDeclaration;
switch (container.kind) {
case SyntaxKind.ModuleBlock:
case SyntaxKind.SourceFile:
@@ -213,11 +213,13 @@ namespace ts.DocumentHighlights {
return [...container.parameters, ...(isClassLike(container.parent) ? container.parent.members : [])];
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.TypeLiteral:
const nodes = container.members;
// If we're an accessibility modifier, we're in an instance member and should search
// the constructor's parameter list for instance members as well.
if (modifierFlag & ModifierFlags.AccessibilityModifier) {
if (modifierFlag & (ModifierFlags.AccessibilityModifier | ModifierFlags.Readonly)) {
const constructor = find(container.members, isConstructorDeclaration);
if (constructor) {
return [...nodes, ...constructor.parameters];
+25 -4
View File
@@ -709,10 +709,28 @@ namespace ts.FindAllReferences.Core {
return references.length ? [{ definition: { type: DefinitionKind.Symbol, symbol }, references }] : emptyArray;
}
/** As in a `readonly prop: any` or `constructor(readonly prop: any)`, not a `readonly any[]`. */
function isReadonlyTypeOperator(node: Node): boolean {
return node.kind === SyntaxKind.ReadonlyKeyword
&& isTypeOperatorNode(node.parent)
&& node.parent.operator === SyntaxKind.ReadonlyKeyword;
}
/** getReferencedSymbols for special node kinds. */
function getReferencedSymbolsSpecial(node: Node, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken): SymbolAndEntries[] | undefined {
if (isTypeKeyword(node.kind)) {
return getAllReferencesForKeyword(sourceFiles, node.kind, cancellationToken);
// A modifier readonly (like on a property declaration) is not special;
// a readonly type keyword (like `readonly string[]`) is.
if (node.kind === SyntaxKind.ReadonlyKeyword && !isReadonlyTypeOperator(node)) {
return undefined;
}
// Likewise, when we *are* looking for a special keyword, make sure we
// *dont* include readonly member modifiers.
return getAllReferencesForKeyword(
sourceFiles,
node.kind,
cancellationToken,
node.kind === SyntaxKind.ReadonlyKeyword ? isReadonlyTypeOperator : undefined);
}
// Labels
@@ -1235,11 +1253,14 @@ namespace ts.FindAllReferences.Core {
}
}
function getAllReferencesForKeyword(sourceFiles: ReadonlyArray<SourceFile>, keywordKind: SyntaxKind, cancellationToken: CancellationToken): SymbolAndEntries[] | undefined {
function getAllReferencesForKeyword(sourceFiles: ReadonlyArray<SourceFile>, keywordKind: SyntaxKind, cancellationToken: CancellationToken, filter?: (node: Node) => boolean): SymbolAndEntries[] | undefined {
const references = flatMap(sourceFiles, sourceFile => {
cancellationToken.throwIfCancellationRequested();
return mapDefined(getPossibleSymbolReferenceNodes(sourceFile, tokenToString(keywordKind)!, sourceFile), referenceLocation =>
referenceLocation.kind === keywordKind ? nodeEntry(referenceLocation) : undefined);
return mapDefined(getPossibleSymbolReferenceNodes(sourceFile, tokenToString(keywordKind)!, sourceFile), referenceLocation => {
if (referenceLocation.kind === keywordKind && (!filter || filter(referenceLocation))) {
return nodeEntry(referenceLocation);
}
});
});
return references.length ? [{ definition: { type: DefinitionKind.Keyword, node: references[0].node }, references }] : undefined;
}
+6 -3
View File
@@ -233,20 +233,23 @@ namespace ts.GoToDefinition {
}
function getDefinitionFromSymbol(typeChecker: TypeChecker, symbol: Symbol, node: Node): DefinitionInfo[] | undefined {
return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(symbol.declarations, declaration => createDefinitionInfo(declaration, typeChecker, symbol, node));
// There are cases when you extend a function by adding properties to it afterwards,
// we want to strip those extra properties
const filteredDeclarations = filter(symbol.declarations, d => !isAssignmentDeclaration(d) || d === symbol.valueDeclaration) || undefined;
return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(filteredDeclarations, declaration => createDefinitionInfo(declaration, typeChecker, symbol, node));
function getConstructSignatureDefinition(): DefinitionInfo[] | undefined {
// Applicable only if we are in a new expression, or we are on a constructor declaration
// and in either case the symbol has a construct signature definition, i.e. class
if (symbol.flags & SymbolFlags.Class && (isNewExpressionTarget(node) || node.kind === SyntaxKind.ConstructorKeyword)) {
const cls = find(symbol.declarations, isClassLike) || Debug.fail("Expected declaration to have at least one class-like declaration");
const cls = find(filteredDeclarations, isClassLike) || Debug.fail("Expected declaration to have at least one class-like declaration");
return getSignatureDefinition(cls.members, /*selectConstructors*/ true);
}
}
function getCallSignatureDefinition(): DefinitionInfo[] | undefined {
return isCallOrNewExpressionTarget(node) || isNameOfFunctionDeclaration(node)
? getSignatureDefinition(symbol.declarations, /*selectConstructors*/ false)
? getSignatureDefinition(filteredDeclarations, /*selectConstructors*/ false)
: undefined;
}
+5 -5
View File
@@ -434,7 +434,7 @@ namespace ts.FindAllReferences {
/**
* Given a local reference, we might notice that it's an import/export and recursively search for references of that.
* If at an import, look locally for the symbol it imports.
* If an an export, look for all imports of it.
* If at an export, look for all imports of it.
* This doesn't handle export specifiers; that is done in `getReferencesAtExportSpecifier`.
* @param comingFromExport If we are doing a search for all exports, don't bother looking backwards for the imported symbol, since that's the reason we're here.
*/
@@ -577,10 +577,10 @@ namespace ts.FindAllReferences {
// 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: Node): Node | undefined {
if (parent.kind === SyntaxKind.VariableDeclaration) {
const p = parent as VariableDeclaration;
return p.name !== node ? undefined :
p.parent.kind === SyntaxKind.CatchClause ? undefined : p.parent.parent.kind === SyntaxKind.VariableStatement ? p.parent.parent : undefined;
const declaration = isVariableDeclaration(parent) ? parent : isBindingElement(parent) ? walkUpBindingElementsAndPatterns(parent) : undefined;
if (declaration) {
return (parent as VariableDeclaration | BindingElement).name !== node ? undefined :
isCatchClause(declaration.parent) ? undefined : isVariableStatement(declaration.parent.parent) ? declaration.parent.parent : undefined;
}
else {
return parent;
+2 -3
View File
@@ -71,9 +71,8 @@ namespace ts.OutliningElementsCollector {
function addRegionOutliningSpans(sourceFile: SourceFile, out: Push<OutliningSpan>): void {
const regions: OutliningSpan[] = [];
const lineStarts = sourceFile.getLineStarts();
for (let i = 0; i < lineStarts.length; i++) {
const currentLineStart = lineStarts[i];
const lineEnd = i + 1 === lineStarts.length ? sourceFile.getEnd() : lineStarts[i + 1] - 1;
for (const currentLineStart of lineStarts) {
const lineEnd = sourceFile.getLineEndOfPosition(currentLineStart);
const lineText = sourceFile.text.substring(currentLineStart, lineEnd);
const result = isRegionDelimiter(lineText);
if (!result || isInComment(sourceFile, currentLineStart)) {
+5 -1
View File
@@ -350,7 +350,11 @@ namespace ts.refactor {
}
if (namedBindings) {
if (namedBindingsUnused) {
changes.delete(sourceFile, namedBindings);
changes.replaceNode(
sourceFile,
importDecl.importClause,
updateImportClause(importDecl.importClause, name, /*namedBindings*/ undefined)
);
}
else if (namedBindings.kind === SyntaxKind.NamedImports) {
for (const element of namedBindings.elements) {
+10 -6
View File
@@ -1158,7 +1158,13 @@ namespace ts {
function getValidSourceFile(fileName: string): SourceFile {
const sourceFile = program.getSourceFile(fileName);
if (!sourceFile) {
throw new Error(`Could not find sourceFile: '${fileName}' in ${program && JSON.stringify(program.getSourceFiles().map(f => f.fileName))}.`);
const error: Error & PossibleProgramFileInfo = new Error(`Could not find source file: '${fileName}'.`);
// We've been having trouble debugging this, so attach sidecar data for the tsserver log.
// See https://github.com/microsoft/TypeScript/issues/30180.
error.ProgramFiles = program.getSourceFiles().map(f => f.fileName);
throw error;
}
return sourceFile;
}
@@ -1238,12 +1244,10 @@ namespace ts {
}
if (host.resolveModuleNames) {
compilerHost.resolveModuleNames = (moduleNames, containingFile, reusedNames, redirectedReference) => host.resolveModuleNames!(moduleNames, containingFile, reusedNames, redirectedReference);
compilerHost.resolveModuleNames = (...args) => host.resolveModuleNames!(...args);
}
if (host.resolveTypeReferenceDirectives) {
compilerHost.resolveTypeReferenceDirectives = (typeReferenceDirectiveNames, containingFile, redirectedReference) => {
return host.resolveTypeReferenceDirectives!(typeReferenceDirectiveNames, containingFile, redirectedReference);
};
compilerHost.resolveTypeReferenceDirectives = (...args) => host.resolveTypeReferenceDirectives!(...args);
}
const documentRegistryBucketKey = documentRegistry.getKeyForCompilationSettings(newSettings);
@@ -1561,7 +1565,7 @@ namespace ts {
const normalizedFileName = normalizePath(fileName);
Debug.assert(filesToSearch.some(f => normalizePath(f) === normalizedFileName));
synchronizeHostData();
const sourceFilesToSearch = filesToSearch.map(getValidSourceFile);
const sourceFilesToSearch = mapDefined(filesToSearch, fileName => program.getSourceFile(fileName));
const sourceFile = getValidSourceFile(fileName);
return DocumentHighlights.getDocumentHighlights(program, cancellationToken, sourceFile, position, sourceFilesToSearch);
}
+11 -6
View File
@@ -17,7 +17,7 @@ namespace ts.SmartSelectionRange {
break outer;
}
if (positionShouldSnapToNode(pos, node, nextNode)) {
if (positionShouldSnapToNode(sourceFile, pos, node)) {
// 1. Blocks are effectively redundant with SyntaxLists.
// 2. TemplateSpans, along with the SyntaxLists containing them, are a somewhat unintuitive grouping
// of things that should be considered independently.
@@ -64,6 +64,13 @@ namespace ts.SmartSelectionRange {
parentNode = node;
break;
}
// If we made it to the end of the for loop, were done.
// In practice, Ive only seen this happen at the very end
// of a SourceFile.
if (i === children.length - 1) {
break outer;
}
}
}
@@ -90,12 +97,11 @@ namespace ts.SmartSelectionRange {
* count too, unless that position belongs to the next node. In effect, makes
* selections able to snap to preceding tokens when the cursor is on the tail
* end of them with only whitespace ahead.
* @param sourceFile The source file containing the nodes.
* @param pos The position to check.
* @param node The candidate node to snap to.
* @param nextNode The next sibling node in the tree.
* @param sourceFile The source file containing the nodes.
*/
function positionShouldSnapToNode(pos: number, node: Node, nextNode: Node | undefined) {
function positionShouldSnapToNode(sourceFile: SourceFile, pos: number, node: Node) {
// Cant use 'ts.positionBelongsToNode()' here because it cleverly accounts
// for missing nodes, which cant really be considered when deciding what
// to select.
@@ -104,9 +110,8 @@ namespace ts.SmartSelectionRange {
return true;
}
const nodeEnd = node.getEnd();
const nextNodeStart = nextNode && nextNode.getStart();
if (nodeEnd === pos) {
return pos !== nextNodeStart;
return getTouchingPropertyName(sourceFile, pos).pos < node.end;
}
return false;
}
+9 -1
View File
@@ -26,7 +26,15 @@ namespace ts {
export function transpileModule(input: string, transpileOptions: TranspileOptions): TranspileOutput {
const diagnostics: Diagnostic[] = [];
const options: CompilerOptions = transpileOptions.compilerOptions ? fixupCompilerOptions(transpileOptions.compilerOptions, diagnostics) : getDefaultCompilerOptions();
const options: CompilerOptions = transpileOptions.compilerOptions ? fixupCompilerOptions(transpileOptions.compilerOptions, diagnostics) : {};
// mix in default options
const defaultOptions = getDefaultCompilerOptions();
for (const key in defaultOptions) {
if (hasProperty(defaultOptions, key) && options[key] === undefined) {
options[key] = defaultOptions[key];
}
}
options.isolatedModules = true;
+2 -2
View File
@@ -211,9 +211,9 @@ namespace ts {
*
* If this is implemented, `getResolvedModuleWithFailedLookupLocationsFromCache` should be too.
*/
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[], redirectedReference?: ResolvedProjectReference): (ResolvedModule | undefined)[];
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions): (ResolvedModule | undefined)[];
getResolvedModuleWithFailedLookupLocationsFromCache?(modulename: string, containingFile: string): ResolvedModuleWithFailedLookupLocations | undefined;
resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string, redirectedReference?: ResolvedProjectReference): (ResolvedTypeReferenceDirective | undefined)[];
resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions): (ResolvedTypeReferenceDirective | undefined)[];
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
+5
View File
@@ -967,6 +967,11 @@ namespace ts {
readonly called: Identifier;
readonly nTypeArguments: number;
}
export interface PossibleProgramFileInfo {
ProgramFiles?: string[];
}
// Get info for an expression like `f <` that may be the start of type arguments.
export function getPossibleTypeArgumentsInfo(tokenIn: Node, sourceFile: SourceFile): PossibleTypeArgumentInfo | undefined {
let token: Node | undefined = tokenIn;
+39 -10
View File
@@ -58,16 +58,18 @@ class CompilerBaselineRunner extends RunnerBase {
}
public checkTestCodeOutput(fileName: string, test?: CompilerFileBasedTest) {
if (test && test.configurations) {
if (test && ts.some(test.configurations)) {
test.configurations.forEach(configuration => {
describe(`${this.testSuiteName} tests for ${fileName}${configuration ? ` (${Harness.getFileBasedTestConfigurationDescription(configuration)})` : ``}`, () => {
this.runSuite(fileName, test, configuration);
});
});
}
describe(`${this.testSuiteName} tests for ${fileName}`, () => {
this.runSuite(fileName, test);
});
else {
describe(`${this.testSuiteName} tests for ${fileName}`, () => {
this.runSuite(fileName, test);
});
}
}
private runSuite(fileName: string, test?: CompilerFileBasedTest, configuration?: Harness.FileBasedTestConfiguration) {
@@ -112,6 +114,7 @@ class CompilerBaselineRunner extends RunnerBase {
class CompilerTest {
private fileName: string;
private justName: string;
private configuredName: string;
private lastUnit: Harness.TestCaseParser.TestUnitData;
private harnessSettings: Harness.TestCaseParser.CompilerSettings;
private hasNonDtsFiles: boolean;
@@ -126,6 +129,25 @@ class CompilerTest {
constructor(fileName: string, testCaseContent?: Harness.TestCaseParser.TestCaseContent, configurationOverrides?: Harness.TestCaseParser.CompilerSettings) {
this.fileName = fileName;
this.justName = vpath.basename(fileName);
this.configuredName = this.justName;
if (configurationOverrides) {
let configuredName = "";
const keys = Object
.keys(configurationOverrides)
.map(k => k.toLowerCase())
.sort();
for (const key of keys) {
if (configuredName) {
configuredName += ",";
}
configuredName += `${key}=${configurationOverrides[key].toLowerCase()}`;
}
if (configuredName) {
const extname = vpath.extname(this.justName);
const basename = vpath.basename(this.justName, extname, /*ignoreCase*/ true);
this.configuredName = `${basename}(${configuredName})${extname}`;
}
}
const rootDir = fileName.indexOf("conformance") === -1 ? "tests/cases/compiler/" : ts.getDirectoryPath(fileName) + "/";
@@ -205,7 +227,7 @@ class CompilerTest {
public verifyDiagnostics() {
// check errors
Harness.Compiler.doErrorBaseline(
this.justName,
this.configuredName,
this.tsConfigFiles.concat(this.toBeCompiled, this.otherFiles),
this.result.diagnostics,
!!this.options.pretty);
@@ -213,7 +235,7 @@ class CompilerTest {
public verifyModuleResolution() {
if (this.options.traceResolution) {
Harness.Baseline.runBaseline(this.justName.replace(/\.tsx?$/, ".trace.json"),
Harness.Baseline.runBaseline(this.configuredName.replace(/\.tsx?$/, ".trace.json"),
JSON.stringify(this.result.traces.map(utils.sanitizeTraceResolutionLogEntry), undefined, 4));
}
}
@@ -225,14 +247,14 @@ class CompilerTest {
// Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required.
? null // tslint:disable-line no-null-keyword
: record;
Harness.Baseline.runBaseline(this.justName.replace(/\.tsx?$/, ".sourcemap.txt"), baseline);
Harness.Baseline.runBaseline(this.configuredName.replace(/\.tsx?$/, ".sourcemap.txt"), baseline);
}
}
public verifyJavaScriptOutput() {
if (this.hasNonDtsFiles) {
Harness.Compiler.doJsEmitBaseline(
this.justName,
this.configuredName,
this.fileName,
this.options,
this.result,
@@ -245,7 +267,7 @@ class CompilerTest {
public verifySourceMapOutput() {
Harness.Compiler.doSourcemapBaseline(
this.justName,
this.configuredName,
this.options,
this.result,
this.harnessSettings);
@@ -256,8 +278,15 @@ class CompilerTest {
return;
}
const noTypesAndSymbols =
this.harnessSettings.noTypesAndSymbols &&
this.harnessSettings.noTypesAndSymbols.toLowerCase() === "true";
if (noTypesAndSymbols) {
return;
}
Harness.Compiler.doTypeAndSymbolBaseline(
this.justName,
this.configuredName,
this.result.program!,
this.toBeCompiled.concat(this.otherFiles).filter(file => !!this.result.program!.getSourceFile(file.unitName)),
/*opts*/ undefined,
+7 -3
View File
@@ -5,7 +5,7 @@ const del: typeof import("del") = require("del");
interface ExecResult {
stdout: Buffer;
stderr: Buffer;
status: number;
status: number | null;
}
interface UserConfig {
@@ -185,7 +185,8 @@ function stripRushStageNumbers(result: string): string {
* so we purge as much of the gulp output as we can
*/
function sanitizeUnimportantGulpOutput(result: string): string {
return result.replace(/^.*(\] (Starting)|(Finished)).*$/gm, "") // task start/end messages (nondeterministic order)
return result.replace(/^.*(\] (Starting)|(Finished)).*$/gm, "") // "gulp" task start/end messages (nondeterministic order)
.replace(/^.*(\] . (finished)|(started)).*$/gm, "") // "just" task start/end messages (nondeterministic order)
.replace(/^.*\] Respawned to PID: \d+.*$/gm, "") // PID of child is OS and system-load dependent (likely stableish in a container but still dangerous)
.replace(/\n+/g, "\n");
}
@@ -193,14 +194,17 @@ function sanitizeUnimportantGulpOutput(result: string): string {
function sanitizeTimestamps(result: string): string {
return result.replace(/\[\d?\d:\d\d:\d\d (A|P)M\]/g, "[XX:XX:XX XM]")
.replace(/\[\d?\d:\d\d:\d\d\]/g, "[XX:XX:XX]")
.replace(/\/\d+-\d+-[\d_TZ]+-debug.log/g, "\/XXXX-XX-XXXXXXXXX-debug.log")
.replace(/\d+(\.\d+)? sec(onds?)?/g, "? seconds")
.replace(/\d+(\.\d+)? min(utes?)?/g, "")
.replace(/\d+(\.\d+)?( m)?s/g, "?s");
.replace(/\d+(\.\d+)? ?m?s/g, "?s")
.replace(/ \(\?s\)/g, "");
}
function sanitizeVersionSpecifiers(result: string): string {
return result
.replace(/\d+.\d+.\d+-insiders.\d\d\d\d\d\d\d\d/g, "X.X.X-insiders.xxxxxxxx")
.replace(/Rush Multi-Project Build Tool (\d+)\.\d+\.\d+/g, "Rush Multi-Project Build Tool $1.X.X")
.replace(/([@v\()])\d+\.\d+\.\d+/g, "$1X.X.X");
}
+7 -1
View File
@@ -61,7 +61,6 @@
"unittests/semver.ts",
"unittests/shimMap.ts",
"unittests/transform.ts",
"unittests/tsbuildWatchMode.ts",
"unittests/config/commandLineParsing.ts",
"unittests/config/configurationExtension.ts",
"unittests/config/convertCompilerOptionsFromJson.ts",
@@ -73,7 +72,10 @@
"unittests/config/tsconfigParsing.ts",
"unittests/evaluation/asyncArrow.ts",
"unittests/evaluation/asyncGenerator.ts",
"unittests/evaluation/awaiter.ts",
"unittests/evaluation/forAwaitOf.ts",
"unittests/evaluation/forOf.ts",
"unittests/evaluation/objectRest.ts",
"unittests/services/cancellableLanguageServiceOperations.ts",
"unittests/services/colorization.ts",
"unittests/services/convertToAsyncFunction.ts",
@@ -96,11 +98,14 @@
"unittests/tsbuild/inferredTypeFromTransitiveModule.ts",
"unittests/tsbuild/lateBoundSymbol.ts",
"unittests/tsbuild/missingExtendedFile.ts",
"unittests/tsbuild/moduleSpecifiers.ts",
"unittests/tsbuild/outFile.ts",
"unittests/tsbuild/referencesWithRootDirInParent.ts",
"unittests/tsbuild/resolveJsonModule.ts",
"unittests/tsbuild/sample.ts",
"unittests/tsbuild/transitiveReferences.ts",
"unittests/tsbuild/watchEnvironment.ts",
"unittests/tsbuild/watchMode.ts",
"unittests/tscWatch/consoleClearing.ts",
"unittests/tscWatch/emit.ts",
"unittests/tscWatch/emitAndErrorUpdates.ts",
@@ -128,6 +133,7 @@
"unittests/tsserver/formatSettings.ts",
"unittests/tsserver/getApplicableRefactors.ts",
"unittests/tsserver/getEditsForFileRename.ts",
"unittests/tsserver/getExportReferences.ts",
"unittests/tsserver/importHelpers.ts",
"unittests/tsserver/inferredProjects.ts",
"unittests/tsserver/languageService.ts",
@@ -348,5 +348,4 @@ namespace ts {
});
});
});
}
@@ -53,6 +53,26 @@ namespace ts {
showTSConfigCorrectly("Show TSConfig with advanced options", ["--showConfig", "--declaration", "--declarationDir", "lib", "--skipLibCheck", "--noErrorTruncation"]);
showTSConfigCorrectly("Show TSConfig with compileOnSave and more", ["-p", "tsconfig.json"], {
compilerOptions: {
esModuleInterop: true,
target: "es5",
module: "commonjs",
strict: true,
},
compileOnSave: true,
exclude: [
"dist"
],
files: [],
include: [
"src/*"
],
references: [
{ path: "./test" }
],
});
// Regression test for https://github.com/Microsoft/TypeScript/issues/28836
showTSConfigCorrectly("Show TSConfig with paths and more", ["-p", "tsconfig.json"], {
compilerOptions: {
@@ -0,0 +1,24 @@
describe("unittests:: evaluation:: awaiter", () => {
// NOTE: This could break if the ECMAScript spec ever changes the timing behavior for Promises (again)
it("await (es5)", async () => {
const result = evaluator.evaluateTypeScript(`
async function a(msg: string) {
await Promise.resolve();
output.push(msg);
}
function b(msg: string) {
return Promise.resolve().then(() => {
output.push(msg);
});
}
export const output: string[] = [];
export async function main() {
const p1 = a('1');
const p2 = b('2');
await Promise.all([p1, p2]);
}
`);
await result.main();
assert.deepEqual(result.output, ["1", "2"]);
});
});
@@ -0,0 +1,119 @@
describe("unittests:: evaluation:: forOfEvaluation", () => {
it("es5 over a array with no Symbol", () => {
const result = evaluator.evaluateTypeScript(`
Symbol = undefined;
export var output = [];
export function main() {
let x = [1,2,3];
for (let value of x) {
output.push(value);
}
}
`, { downlevelIteration: true, target: ts.ScriptTarget.ES5 });
result.main();
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], 2);
assert.strictEqual(result.output[2], 3);
});
it("es5 over a string with no Symbol", () => {
const result = evaluator.evaluateTypeScript(`
Symbol = undefined;
export var output = [];
export function main() {
let x = "hello";
for (let value of x) {
output.push(value);
}
}
`, { downlevelIteration: true, target: ts.ScriptTarget.ES5 });
result.main();
assert.strictEqual(result.output[0], "h");
assert.strictEqual(result.output[1], "e");
assert.strictEqual(result.output[2], "l");
assert.strictEqual(result.output[3], "l");
assert.strictEqual(result.output[4], "o");
});
it("es5 over undefined with no Symbol", () => {
const result = evaluator.evaluateTypeScript(`
Symbol = undefined;
export function main() {
let x = undefined;
for (let value of x) {
}
}
`, { downlevelIteration: true, target: ts.ScriptTarget.ES5 });
assert.throws(() => result.main(), "Symbol.iterator is not defined");
});
it("es5 over undefined with Symbol", () => {
const result = evaluator.evaluateTypeScript(`
export function main() {
let x = undefined;
for (let value of x) {
}
}
`, { downlevelIteration: true, target: ts.ScriptTarget.ES5 });
assert.throws(() => result.main(), /cannot read property.*Symbol\(Symbol\.iterator\).*/i);
});
it("es5 over object with no Symbol.iterator with no Symbol", () => {
const result = evaluator.evaluateTypeScript(`
Symbol = undefined;
export function main() {
let x = {} as any;
for (let value of x) {
}
}
`, { downlevelIteration: true, target: ts.ScriptTarget.ES5 });
assert.throws(() => result.main(), "Symbol.iterator is not defined");
});
it("es5 over object with no Symbol.iterator with Symbol", () => {
const result = evaluator.evaluateTypeScript(`
export function main() {
let x = {} as any;
for (let value of x) {
}
}
`, { downlevelIteration: true, target: ts.ScriptTarget.ES5 });
assert.throws(() => result.main(), "Object is not iterable");
});
it("es5 over object with Symbol.iterator", () => {
const result = evaluator.evaluateTypeScript(`
export var output = [];
export function main() {
let thing : any = {};
thing[Symbol.iterator] = () => {
let i = 0;
return { next() { i++; return this; }, value: i, done: i < 10 };
};
for (let value of thing)
{
output.push(value)
}
}`, { downlevelIteration: true, target: ts.ScriptTarget.ES5 });
result.main();
});
});
@@ -0,0 +1,28 @@
describe("unittests:: evaluation:: objectRest", () => {
// https://github.com/microsoft/TypeScript/issues/31469
it("side effects in property assignment", async () => {
const result = evaluator.evaluateTypeScript(`
const k = { a: 1, b: 2 };
const o = { a: 3, ...k, b: k.a++ };
export const output = o;
`);
assert.deepEqual(result.output, { a: 1, b: 1 });
});
it("side effects in during spread", async () => {
const result = evaluator.evaluateTypeScript(`
const k = { a: 1, get b() { l = { c: 9 }; return 2; } };
let l = { c: 3 };
const o = { ...k, ...l };
export const output = o;
`);
assert.deepEqual(result.output, { a: 1, b: 2, c: 9 });
});
it("trailing literal-valued object-literal", async () => {
const result = evaluator.evaluateTypeScript(`
const k = { a: 1 }
const o = { ...k, ...{ b: 2 } };
export const output = o;
`);
assert.deepEqual(result.output, { a: 1, b: 2 });
});
});
+15
View File
@@ -31,3 +31,18 @@ describe("Public APIs", () => {
verifyApi("tsserverlibrary.d.ts");
});
});
describe("Public APIs:: token to string", () => {
function assertDefinedTokenToString(initial: ts.SyntaxKind, last: ts.SyntaxKind) {
for (let t = initial; t <= last; t++) {
assert.isDefined(ts.tokenToString(t), `Expected tokenToString defined for ${ts.Debug.formatSyntaxKind(t)}`);
}
}
it("for punctuations", () => {
assertDefinedTokenToString(ts.SyntaxKind.FirstPunctuation, ts.SyntaxKind.LastPunctuation);
});
it("for keywords", () => {
assertDefinedTokenToString(ts.SyntaxKind.FirstKeyword, ts.SyntaxKind.LastKeyword);
});
});
@@ -38,6 +38,18 @@ namespace ts {
verifyNewLines(content, { newLine: NewLineKind.LineFeed });
}
function verifyOutliningSpanNewLines(content: string, options: CompilerOptions) {
const ls = testLSWithFiles(options, [{
content,
fileOptions: {},
unitName: "input.ts"
}]);
const span = ls.getOutliningSpans("input.ts")[0];
const textAfterSpanCollapse = content.substring(span.textSpan.start + span.textSpan.length);
assert(textAfterSpanCollapse.match(options.newLine === NewLineKind.CarriageReturnLineFeed ? /\r\n/ : /[^\r]\n/), "expected to find appropriate newlines");
assert(!textAfterSpanCollapse.match(options.newLine === NewLineKind.CarriageReturnLineFeed ? /[^\r]\n/ : /\r\n/), "expected not to find inappropriate newlines");
}
it("should exist and respect provided compiler options", () => {
verifyBothNewLines(`
function foo() {
@@ -45,5 +57,15 @@ namespace ts {
}
`);
});
it("should respect CRLF line endings around outlining spans", () => {
verifyOutliningSpanNewLines("// comment not included\r\n// #region name\r\nlet x: string = \"x\";\r\n// #endregion name\r\n",
{ newLine: NewLineKind.CarriageReturnLineFeed });
});
it("should respect LF line endings around outlining spans", () => {
verifyOutliningSpanNewLines("// comment not included\n// #region name\nlet x: string = \"x\";\n// #endregion name\n\n",
{ newLine: NewLineKind.LineFeed });
});
});
}
@@ -17,7 +17,10 @@ namespace ts {
transpileOptions = testSettings.options || {};
if (!transpileOptions.compilerOptions) {
transpileOptions.compilerOptions = {};
transpileOptions.compilerOptions = { };
}
if (transpileOptions.compilerOptions.target === undefined) {
transpileOptions.compilerOptions.target = ScriptTarget.ES3;
}
if (transpileOptions.compilerOptions.newLine === undefined) {
@@ -0,0 +1,98 @@
namespace ts {
// https://github.com/microsoft/TypeScript/issues/31696
it("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers to referenced projects resolve correctly", () => {
const baseFs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, {
files: {
"/src/common/nominal.ts": utils.dedent`
export declare type Nominal<T, Name extends string> = T & {
[Symbol.species]: Name;
};
`,
"/src/common/tsconfig.json": utils.dedent`
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"composite": true
},
"include": ["nominal.ts"]
}`,
"/src/sub-project/index.ts": utils.dedent`
import { Nominal } from '../common/nominal';
export type MyNominal = Nominal<string, 'MyNominal'>;
`,
"/src/sub-project/tsconfig.json": utils.dedent`
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"composite": true
},
"references": [
{ "path": "../common" }
],
"include": ["./index.ts"]
}`,
"/src/sub-project-2/index.ts": utils.dedent`
import { MyNominal } from '../sub-project/index';
const variable = {
key: 'value' as MyNominal,
};
export function getVar(): keyof typeof variable {
return 'key';
}
`,
"/src/sub-project-2/tsconfig.json": utils.dedent`
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"composite": true
},
"references": [
{ "path": "../sub-project" }
],
"include": ["./index.ts"]
}`,
"/src/tsconfig.json": utils.dedent`
{
"compilerOptions": {
"composite": true
},
"references": [
{ "path": "./sub-project" },
{ "path": "./sub-project-2" }
],
"include": []
}`,
"/tsconfig.base.json": utils.dedent`
{
"compilerOptions": {
"skipLibCheck": true,
"rootDir": "./",
"outDir": "lib",
"lib": ["dom", "es2015", "es2015.symbol.wellknown"]
}
}`,
"/tsconfig.json": utils.dedent`{
"compilerOptions": {
"composite": true
},
"references": [
{ "path": "./src" }
],
"include": []
}`
},
cwd: "/"
});
const fs = baseFs.makeReadonly().shadow();
const sys = new fakes.System(fs, { executingFilePath: "/", newLine: "\n" });
const host = new fakes.SolutionBuilderHost(sys);
const builder = createSolutionBuilder(host, ["/tsconfig.json"], { dry: false, force: false, verbose: false });
builder.build();
// Prior to fixing GH31696 the import in `/lib/src/sub-project-2/index.d.ts` was `import("../../lib/src/common/nonterminal")`, which was invalid.
Harness.Baseline.runBaseline("tsbuild/moduleSpecifiers/initial-build/resolves-correctly.js", vfs.formatPatch(fs.diff(baseFs)));
});
}
@@ -0,0 +1,124 @@
namespace ts.tscWatch {
describe("unittests:: tsbuild:: watchEnvironment:: tsbuild:: watchMode:: with different watch environments", () => {
describe("when watchFile can create multiple watchers per file", () => {
verifyWatchFileOnMultipleProjects(/*singleWatchPerFile*/ false);
});
describe("when watchFile is single watcher per file", () => {
verifyWatchFileOnMultipleProjects(
/*singleWatchPerFile*/ true,
arrayToMap(["TSC_WATCHFILE"], identity, () => TestFSWithWatch.Tsc_WatchFile.SingleFileWatcherPerName)
);
});
function verifyWatchFileOnMultipleProjects(singleWatchPerFile: boolean, environmentVariables?: Map<string>) {
it("watchFile on same file multiple times because file is part of multiple projects", () => {
const project = `${TestFSWithWatch.tsbuildProjectsLocation}/myproject`;
let maxPkgs = 4;
const configPath = `${project}/tsconfig.json`;
const typing: File = {
path: `${project}/typings/xterm.d.ts`,
content: "export const typing = 10;"
};
const allPkgFiles = pkgs(pkgFiles);
const system = createWatchedSystem([libFile, typing, ...flatArray(allPkgFiles)], { currentDirectory: project, environmentVariables });
writePkgReferences();
const host = createSolutionBuilderWithWatchHost(system);
const solutionBuilder = createSolutionBuilderWithWatch(host, ["tsconfig.json"], { watch: true, verbose: true });
solutionBuilder.build();
checkOutputErrorsInitial(system, emptyArray, /*disableConsoleClears*/ undefined, [
`Projects in this build: \r\n${
concatenate(
pkgs(index => ` * pkg${index}/tsconfig.json`),
[" * tsconfig.json"]
).join("\r\n")}\n\n`,
...flatArray(pkgs(index => [
`Project 'pkg${index}/tsconfig.json' is out of date because output file 'pkg${index}/index.js' does not exist\n\n`,
`Building project '${project}/pkg${index}/tsconfig.json'...\n\n`
]))
]);
const watchFilesDetailed = arrayToMap(flatArray(allPkgFiles), f => f.path, () => 1);
watchFilesDetailed.set(configPath, 1);
watchFilesDetailed.set(typing.path, singleWatchPerFile ? 1 : maxPkgs);
checkWatchedFilesDetailed(system, watchFilesDetailed);
system.writeFile(typing.path, `${typing.content}export const typing1 = 10;`);
verifyInvoke();
// Make change
maxPkgs--;
writePkgReferences();
system.checkTimeoutQueueLengthAndRun(1);
checkOutputErrorsIncremental(system, emptyArray);
const lastFiles = last(allPkgFiles);
lastFiles.forEach(f => watchFilesDetailed.delete(f.path));
watchFilesDetailed.set(typing.path, singleWatchPerFile ? 1 : maxPkgs);
checkWatchedFilesDetailed(system, watchFilesDetailed);
system.writeFile(typing.path, typing.content);
verifyInvoke();
// Make change to remove all the watches
maxPkgs = 0;
writePkgReferences();
system.checkTimeoutQueueLengthAndRun(1);
checkOutputErrorsIncremental(system, [
`tsconfig.json(1,10): error TS18002: The 'files' list in config file '${configPath}' is empty.\n`
]);
checkWatchedFilesDetailed(system, [configPath], 1);
system.writeFile(typing.path, `${typing.content}export const typing1 = 10;`);
system.checkTimeoutQueueLength(0);
function flatArray<T>(arr: T[][]): readonly T[] {
return flatMap(arr, identity);
}
function pkgs<T>(cb: (index: number) => T): T[] {
const result: T[] = [];
for (let index = 0; index < maxPkgs; index++) {
result.push(cb(index));
}
return result;
}
function createPkgReference(index: number) {
return { path: `./pkg${index}` };
}
function pkgFiles(index: number): File[] {
return [
{
path: `${project}/pkg${index}/index.ts`,
content: `export const pkg${index} = ${index};`
},
{
path: `${project}/pkg${index}/tsconfig.json`,
content: JSON.stringify({
complerOptions: { composite: true },
include: [
"**/*.ts",
"../typings/xterm.d.ts"
]
})
}
];
}
function writePkgReferences() {
system.writeFile(configPath, JSON.stringify({
files: [],
include: [],
references: pkgs(createPkgReference)
}));
}
function verifyInvoke() {
pkgs(() => system.checkTimeoutQueueLengthAndRun(1));
checkOutputErrorsIncremental(system, emptyArray, /*disableConsoleClears*/ undefined, /*logsBeforeWatchDiagnostics*/ undefined, [
...flatArray(pkgs(index => [
`Project 'pkg${index}/tsconfig.json' is out of date because oldest output 'pkg${index}/index.js' is older than newest input 'typings/xterm.d.ts'\n\n`,
`Building project '${project}/pkg${index}/tsconfig.json'...\n\n`,
`Updating unchanged output timestamps of project '${project}/pkg${index}/tsconfig.json'...\n\n`
]))
]);
}
});
}
});
}
@@ -16,11 +16,19 @@ namespace ts.tscWatch {
return host;
}
export function createSolutionBuilder(system: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
const host = createSolutionBuilderHost(system);
host.now = system.now.bind(system);
return ts.createSolutionBuilder(host, rootNames, defaultOptions || {});
}
export function createSolutionBuilderWithWatchHost(system: WatchedSystem) {
const host = ts.createSolutionBuilderWithWatchHost(system);
host.now = system.now.bind(system);
return host;
}
function createSolutionBuilderWithWatch(system: TsBuildWatchSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
const host = createSolutionBuilderWithWatchHost(system);
const solutionBuilder = ts.createSolutionBuilderWithWatch(host, rootNames, defaultOptions || { watch: true });
@@ -33,7 +41,7 @@ namespace ts.tscWatch {
return [f, host.getModifiedTime(f), host.writtenFiles.has(host.toFullPath(f))] as OutputFileStamp;
}
describe("unittests:: tsbuild-watch program updates", () => {
describe("unittests:: tsbuild:: watchMode:: program updates", () => {
const project = "sample1";
const enum SubProject {
core = "core",
@@ -113,13 +121,33 @@ namespace ts.tscWatch {
}
}
const core = subProjectFiles(SubProject.core, /*anotherModuleAndSomeDecl*/ true);
const logic = subProjectFiles(SubProject.logic);
const tests = subProjectFiles(SubProject.tests);
const ui = subProjectFiles(SubProject.ui);
const allFiles: ReadonlyArray<File> = [libFile, ...core, ...logic, ...tests, ...ui];
const testProjectExpectedWatchedFiles = [core[0], core[1], core[2]!, ...logic, ...tests].map(f => f.path.toLowerCase()); // tslint:disable-line no-unnecessary-type-assertion (TODO: type assertion should be necessary)
const testProjectExpectedWatchedDirectoriesRecursive = [projectPath(SubProject.core), projectPath(SubProject.logic)];
let core: SubProjectFiles;
let logic: SubProjectFiles;
let tests: SubProjectFiles;
let ui: SubProjectFiles;
let allFiles: ReadonlyArray<File>;
let testProjectExpectedWatchedFiles: string[];
let testProjectExpectedWatchedDirectoriesRecursive: string[];
before(() => {
core = subProjectFiles(SubProject.core, /*anotherModuleAndSomeDecl*/ true);
logic = subProjectFiles(SubProject.logic);
tests = subProjectFiles(SubProject.tests);
ui = subProjectFiles(SubProject.ui);
allFiles = [libFile, ...core, ...logic, ...tests, ...ui];
testProjectExpectedWatchedFiles = [core[0], core[1], core[2]!, ...logic, ...tests].map(f => f.path.toLowerCase()); // tslint:disable-line no-unnecessary-type-assertion (TODO: type assertion should be necessary)
testProjectExpectedWatchedDirectoriesRecursive = [projectPath(SubProject.core), projectPath(SubProject.logic)];
});
after(() => {
core = undefined!;
logic = undefined!;
tests = undefined!;
ui = undefined!;
allFiles = undefined!;
testProjectExpectedWatchedFiles = undefined!;
testProjectExpectedWatchedDirectoriesRecursive = undefined!;
});
function createSolutionInWatchMode(allFiles: ReadonlyArray<File>, defaultOptions?: BuildOptions, disableConsoleClears?: boolean) {
const host = createTsBuildWatchSystem(allFiles, { currentDirectory: projectsLocation });
@@ -172,9 +200,9 @@ namespace ts.tscWatch {
content: `export const newFileConst = 30;`
};
function verifyProjectChanges(allFiles: ReadonlyArray<File>) {
function verifyProjectChanges(allFilesGetter: () => ReadonlyArray<File>) {
function createSolutionInWatchModeToVerifyChanges(additionalFiles?: ReadonlyArray<[SubProject, string]>) {
const host = createSolutionInWatchMode(allFiles);
const host = createSolutionInWatchMode(allFilesGetter());
return { host, verifyChangeWithFile, verifyChangeAfterTimeout, verifyWatches };
function verifyChangeWithFile(fileName: string, content: string, local?: boolean) {
@@ -277,19 +305,21 @@ export class someClass2 { }`);
}
describe("with simple project reference graph", () => {
verifyProjectChanges(allFiles);
verifyProjectChanges(() => allFiles);
});
describe("with circular project reference", () => {
const [coreTsconfig, ...otherCoreFiles] = core;
const circularCoreConfig: File = {
path: coreTsconfig.path,
content: JSON.stringify({
compilerOptions: { composite: true, declaration: true },
references: [{ path: "../tests", circular: true }]
})
};
verifyProjectChanges([libFile, circularCoreConfig, ...otherCoreFiles, ...logic, ...tests]);
verifyProjectChanges(() => {
const [coreTsconfig, ...otherCoreFiles] = core;
const circularCoreConfig: File = {
path: coreTsconfig.path,
content: JSON.stringify({
compilerOptions: { composite: true, declaration: true },
references: [{ path: "../tests", circular: true }]
})
};
return [libFile, circularCoreConfig, ...otherCoreFiles, ...logic, ...tests];
});
});
});
@@ -681,9 +711,9 @@ let x: string = 10;`);
const coreIndexDts = projectFileName(SubProject.core, "index.d.ts");
const coreAnotherModuleDts = projectFileName(SubProject.core, "anotherModule.d.ts");
const logicIndexDts = projectFileName(SubProject.logic, "index.d.ts");
const expectedWatchedFiles = [core[0], logic[0], ...tests, libFile].map(f => f.path).concat([coreIndexDts, coreAnotherModuleDts, logicIndexDts].map(f => f.toLowerCase()));
const expectedWatchedFiles = () => [core[0], logic[0], ...tests, libFile].map(f => f.path).concat([coreIndexDts, coreAnotherModuleDts, logicIndexDts].map(f => f.toLowerCase()));
const expectedWatchedDirectoriesRecursive = projectSystem.getTypeRootsFromLocation(projectPath(SubProject.tests));
const expectedProgramFiles = [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, logicIndexDts];
const expectedProgramFiles = () => [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, logicIndexDts];
function createSolutionAndWatchMode() {
return createSolutionAndWatchModeOfProject(allFiles, projectsLocation, `${project}/${SubProject.tests}`, tests[0].path, getOutputFileStamps);
@@ -694,12 +724,12 @@ let x: string = 10;`);
}
function verifyWatches(host: TsBuildWatchSystem, withTsserver?: boolean) {
verifyWatchesOfProject(host, withTsserver ? expectedWatchedFiles.filter(f => f !== tests[1].path.toLowerCase()) : expectedWatchedFiles, expectedWatchedDirectoriesRecursive);
verifyWatchesOfProject(host, withTsserver ? expectedWatchedFiles().filter(f => f !== tests[1].path.toLowerCase()) : expectedWatchedFiles(), expectedWatchedDirectoriesRecursive);
}
function verifyScenario(
edit: (host: TsBuildWatchSystem, solutionBuilder: SolutionBuilder<EmitAndSemanticDiagnosticsBuilderProgram>) => void,
expectedFilesAfterEdit: ReadonlyArray<string>
expectedFilesAfterEdit: () => ReadonlyArray<string>
) {
it("with tsc-watch", () => {
const { host, solutionBuilder, watch } = createSolutionAndWatchMode();
@@ -708,7 +738,7 @@ let x: string = 10;`);
host.checkTimeoutQueueLengthAndRun(1);
checkOutputErrorsIncremental(host, emptyArray);
checkProgramActualFiles(watch(), expectedFilesAfterEdit);
checkProgramActualFiles(watch(), expectedFilesAfterEdit());
});
@@ -718,7 +748,7 @@ let x: string = 10;`);
edit(host, solutionBuilder);
host.checkTimeoutQueueLengthAndRun(2);
checkProjectActualFiles(service, tests[0].path, [tests[0].path, ...expectedFilesAfterEdit]);
checkProjectActualFiles(service, tests[0].path, [tests[0].path, ...expectedFilesAfterEdit()]);
});
}
@@ -729,7 +759,7 @@ let x: string = 10;`);
verifyDependencies(watch, coreIndexDts, [coreIndexDts]);
verifyDependencies(watch, coreAnotherModuleDts, [coreAnotherModuleDts]);
verifyDependencies(watch, logicIndexDts, [logicIndexDts, coreAnotherModuleDts]);
verifyDependencies(watch, tests[1].path, expectedProgramFiles.filter(f => f !== libFile.path));
verifyDependencies(watch, tests[1].path, expectedProgramFiles().filter(f => f !== libFile.path));
});
it("with tsserver", () => {
@@ -769,7 +799,7 @@ export function gfoo() {
}));
solutionBuilder.invalidateProject(logic[0].path.toLowerCase() as ResolvedConfigFilePath, ConfigFileProgramReloadLevel.Full);
solutionBuilder.buildNextInvalidatedProject();
}, [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, projectFilePath(SubProject.logic, "decls/index.d.ts")]);
}, () => [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, projectFilePath(SubProject.logic, "decls/index.d.ts")]);
});
});
@@ -9,7 +9,7 @@ namespace ts.tscWatch {
};
const files = [file1, libFile];
const environmentVariables = createMap<string>();
environmentVariables.set("TSC_WATCHFILE", "DynamicPriorityPolling");
environmentVariables.set("TSC_WATCHFILE", TestFSWithWatch.Tsc_WatchFile.DynamicPolling);
const host = createWatchedSystem(files, { environmentVariables });
const watch = createWatchOfFilesAndCompilerOptions([file1.path], host);
@@ -139,7 +139,7 @@ namespace ts.projectSystem {
assert.isTrue(false, `should not find file '${imported.path}'`);
}
catch (e) {
assert.isTrue(e.message.indexOf(`Could not find sourceFile: '${imported.path}' in ["${root.path}"].`) === 0, `Actual: ${e.message}`);
assert.isTrue(e.message.indexOf(`Could not find source file: '${imported.path}'.`) === 0, `Actual: ${e.message}`);
}
const f2Lookups = getLocationsForModuleLookup("f2");
callsTrackingHost.verifyCalledOnEachEntryNTimes(CalledMapsWithSingleArg.fileExists, f2Lookups, 1);
@@ -503,6 +503,112 @@ namespace ts.projectSystem {
});
});
describe("for changes in declaration files", () => {
function testDTS(dtsFileContents: string, tsFileContents: string, opts: CompilerOptions, expectDTSEmit: boolean) {
const dtsFile = {
path: "/a/runtime/a.d.ts",
content: dtsFileContents
};
const f2 = {
path: "/a/b.ts",
content: tsFileContents
};
const config = {
path: "/a/tsconfig.json",
content: JSON.stringify({
compilerOptions: opts,
compileOnSave: true
})
};
const host = createServerHost([dtsFile, f2, config]);
const session = projectSystem.createSession(host);
session.executeCommand(<protocol.OpenRequest>{
seq: 1,
type: "request",
command: "open",
arguments: { file: dtsFile.path }
});
const projectService = session.getProjectService();
checkNumberOfProjects(projectService, { configuredProjects: 1 });
const project = projectService.configuredProjects.get(config.path)!;
checkProjectRootFiles(project, [dtsFile.path, f2.path]);
session.executeCommand(<protocol.OpenRequest>{
seq: 2,
type: "request",
command: "open",
arguments: { file: f2.path }
});
checkNumberOfProjects(session.getProjectService(), { configuredProjects: 1 });
const { response } = session.executeCommand(<protocol.CompileOnSaveAffectedFileListRequest>{
seq: 3,
type: "request",
command: "compileOnSaveAffectedFileList",
arguments: { file: dtsFile.path }
});
if (expectDTSEmit) {
assert.equal((response as protocol.CompileOnSaveAffectedFileListSingleProject[]).length, 1, "expected output from 1 project");
assert.equal((response as protocol.CompileOnSaveAffectedFileListSingleProject[])[0].fileNames.length, 2, "expected to affect 2 files");
}
else {
assert.equal((response as protocol.CompileOnSaveAffectedFileListSingleProject[]).length, 0, "expected no output");
}
const { response: response2 } = session.executeCommand(<protocol.CompileOnSaveAffectedFileListRequest>{
seq: 4,
type: "request",
command: "compileOnSaveAffectedFileList",
arguments: { file: f2.path }
});
assert.equal((response2 as protocol.CompileOnSaveAffectedFileListSingleProject[]).length, 1, "expected output from 1 project");
}
it("should return empty array if change is made in a global declaration file", () => {
testDTS(
/*dtsFileContents*/ "declare const x: string;",
/*tsFileContents*/ "var y = 1;",
/*opts*/ {},
/*expectDTSEmit*/ false
);
});
it("should return empty array if change is made in a module declaration file", () => {
testDTS(
/*dtsFileContents*/ "export const x: string;",
/*tsFileContents*/ "import { x } from './runtime/a;",
/*opts*/ {},
/*expectDTSEmit*/ false
);
});
it("should return results if change is made in a global declaration file with declaration emit", () => {
testDTS(
/*dtsFileContents*/ "declare const x: string;",
/*tsFileContents*/ "var y = 1;",
/*opts*/ { declaration: true },
/*expectDTSEmit*/ true
);
});
it("should return results if change is made in a global declaration file with composite enabled", () => {
testDTS(
/*dtsFileContents*/ "declare const x: string;",
/*tsFileContents*/ "var y = 1;",
/*opts*/ { composite: true },
/*expectDTSEmit*/ true
);
});
it("should return results if change is made in a global declaration file with decorator emit enabled", () => {
testDTS(
/*dtsFileContents*/ "declare const x: string;",
/*tsFileContents*/ "var y = 1;",
/*opts*/ { experimentalDecorators: true, emitDecoratorMetadata: true },
/*expectDTSEmit*/ true
);
});
});
describe("tsserverProjectSystem emit with outFile or out setting", () => {
function test(opts: CompilerOptions, expectedUsesOutFile: boolean) {
const f1 = {
@@ -866,12 +866,12 @@ namespace ts.projectSystem {
const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
host.runQueuedTimeoutCallbacks();
// Since there is no file open from configFile it would be closed
checkNumberOfConfiguredProjects(projectService, 0);
checkNumberOfInferredProjects(projectService, 1);
// Since file1 refers to config file as the default project, it needs to be kept alive
checkNumberOfProjects(projectService, { inferredProjects: 1, configuredProjects: 1 });
const inferredProject = projectService.inferredProjects[0];
assert.isTrue(inferredProject.containsFile(<server.NormalizedPath>file1.path));
assert.isFalse(projectService.configuredProjects.get(configFile.path)!.containsFile(<server.NormalizedPath>file1.path));
});
it("should be able to handle @types if input file list is empty", () => {
@@ -898,8 +898,8 @@ namespace ts.projectSystem {
const projectService = createProjectService(host);
projectService.openClientFile(f.path);
// Since no file from the configured project is open, it would be closed immediately
projectService.checkNumberOfProjects({ configuredProjects: 0, inferredProjects: 1 });
// Since f refers to config file as the default project, it needs to be kept alive
projectService.checkNumberOfProjects({ configuredProjects: 1, inferredProjects: 1 });
});
it("should tolerate invalid include files that start in subDirectory", () => {
@@ -924,8 +924,8 @@ namespace ts.projectSystem {
const projectService = createProjectService(host);
projectService.openClientFile(f.path);
// Since no file from the configured project is open, it would be closed immediately
projectService.checkNumberOfProjects({ configuredProjects: 0, inferredProjects: 1 });
// Since f refers to config file as the default project, it needs to be kept alive
projectService.checkNumberOfProjects({ configuredProjects: 1, inferredProjects: 1 });
});
it("Changed module resolution reflected when specifying files list", () => {
@@ -1,11 +1,4 @@
namespace ts.projectSystem {
interface DocumentSpanFromSubstring {
file: File;
text: string;
options?: SpanFromSubstringOptions;
contextText?: string;
contextOptions?: SpanFromSubstringOptions;
}
function documentSpanFromSubstring({ file, text, contextText, options, contextOptions }: DocumentSpanFromSubstring): DocumentSpan {
const contextSpan = contextText !== undefined ? documentSpanFromSubstring({ file, text: contextText, options: contextOptions }) : undefined;
return {
@@ -19,19 +12,6 @@ namespace ts.projectSystem {
return documentSpanFromSubstring(input);
}
interface MakeReferenceItem extends DocumentSpanFromSubstring {
isDefinition: boolean;
lineText: string;
}
function makeReferenceItem({ isDefinition, lineText, ...rest }: MakeReferenceItem): protocol.ReferencesResponseItem {
return {
...protocolFileSpanWithContextFromSubstring(rest),
isDefinition,
isWriteAccess: isDefinition,
lineText,
};
}
interface MakeReferenceEntry extends DocumentSpanFromSubstring {
isDefinition: boolean;
}
@@ -0,0 +1,185 @@
namespace ts.projectSystem {
describe("unittests:: tsserver:: getExportReferences", () => {
const exportVariable = "export const value = 0;";
const exportArrayDestructured = "export const [valueA, valueB] = [0, 1];";
const exportObjectDestructured = "export const { valueC, valueD: renamedD } = { valueC: 0, valueD: 1 };";
const exportNestedObject = "export const { nest: [valueE, { valueF }] } = { nest: [0, { valueF: 1 }] };";
const mainTs: File = {
path: "/main.ts",
content: 'import { value, valueA, valueB, valueC, renamedD, valueE, valueF } from "./mod";',
};
const modTs: File = {
path: "/mod.ts",
content: `${exportVariable}
${exportArrayDestructured}
${exportObjectDestructured}
${exportNestedObject}
`,
};
const tsconfig: File = {
path: "/tsconfig.json",
content: "{}",
};
function makeSampleSession() {
const host = createServerHost([mainTs, modTs, tsconfig]);
const session = createSession(host);
openFilesForSession([mainTs, modTs], session);
return session;
}
const referenceMainTs = (mainTs: File, text: string): protocol.ReferencesResponseItem =>
makeReferenceItem({
file: mainTs,
isDefinition: true,
lineText: mainTs.content,
contextText: mainTs.content,
text,
});
const referenceModTs = (
texts: { text: string; lineText: string; contextText?: string },
override: Partial<MakeReferenceItem> = {},
): protocol.ReferencesResponseItem =>
makeReferenceItem({
file: modTs,
isDefinition: true,
...texts,
...override,
});
it("should get const variable declaration references", () => {
const session = makeSampleSession();
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(
session,
protocol.CommandTypes.References,
protocolFileLocationFromSubstring(modTs, "value"),
);
const expectResponse = {
refs: [
referenceModTs({ text: "value", lineText: exportVariable, contextText: exportVariable }),
referenceMainTs(mainTs, "value"),
],
symbolDisplayString: "const value: 0",
symbolName: "value",
symbolStartOffset: protocolLocationFromSubstring(modTs.content, "value").offset,
};
assert.deepEqual(response, expectResponse);
});
it("should get array destructuring declaration references", () => {
const session = makeSampleSession();
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(
session,
protocol.CommandTypes.References,
protocolFileLocationFromSubstring(modTs, "valueA"),
);
const expectResponse = {
refs: [
referenceModTs({
text: "valueA",
lineText: exportArrayDestructured,
contextText: exportArrayDestructured,
}),
referenceMainTs(mainTs, "valueA"),
],
symbolDisplayString: "const valueA: number",
symbolName: "valueA",
symbolStartOffset: protocolLocationFromSubstring(modTs.content, "valueA").offset,
};
assert.deepEqual(response, expectResponse);
});
it("should get object destructuring declaration references", () => {
const session = makeSampleSession();
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(
session,
protocol.CommandTypes.References,
protocolFileLocationFromSubstring(modTs, "valueC"),
);
const expectResponse = {
refs: [
referenceModTs({
text: "valueC",
lineText: exportObjectDestructured,
contextText: exportObjectDestructured,
}),
referenceMainTs(mainTs, "valueC"),
referenceModTs(
{ text: "valueC", lineText: exportObjectDestructured, contextText: "valueC: 0" },
{ options: { index: 1 } },
),
],
symbolDisplayString: "const valueC: number",
symbolName: "valueC",
symbolStartOffset: protocolLocationFromSubstring(modTs.content, "valueC").offset,
};
assert.deepEqual(response, expectResponse);
});
it("should get object declaration references that renames destructured property", () => {
const session = makeSampleSession();
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(
session,
protocol.CommandTypes.References,
protocolFileLocationFromSubstring(modTs, "renamedD"),
);
const expectResponse = {
refs: [
referenceModTs({
text: "renamedD",
lineText: exportObjectDestructured,
contextText: exportObjectDestructured,
}),
referenceMainTs(mainTs, "renamedD"),
],
symbolDisplayString: "const renamedD: number",
symbolName: "renamedD",
symbolStartOffset: protocolLocationFromSubstring(modTs.content, "renamedD").offset,
};
assert.deepEqual(response, expectResponse);
});
it("should get nested object declaration references", () => {
const session = makeSampleSession();
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(
session,
protocol.CommandTypes.References,
protocolFileLocationFromSubstring(modTs, "valueF"),
);
const expectResponse = {
refs: [
referenceModTs({
text: "valueF",
lineText: exportNestedObject,
contextText: exportNestedObject,
}),
referenceMainTs(mainTs, "valueF"),
referenceModTs(
{
text: "valueF",
lineText: exportNestedObject,
contextText: "valueF: 1",
},
{ options: { index: 1 } },
),
],
symbolDisplayString: "const valueF: number",
symbolName: "valueF",
symbolStartOffset: protocolLocationFromSubstring(modTs.content, "valueF").offset,
};
assert.deepEqual(response, expectResponse);
});
});
}
@@ -519,6 +519,8 @@ namespace ts.projectSystem {
file: File;
text: string;
options?: SpanFromSubstringOptions;
contextText?: string;
contextOptions?: SpanFromSubstringOptions;
}
export function protocolFileSpanFromSubstring({ file, text, options }: DocumentSpanFromSubstring): protocol.FileSpan {
return { file: file.path, ...protocolTextSpanFromSubstring(file.content, text, options) };
@@ -727,4 +729,18 @@ namespace ts.projectSystem {
assert.strictEqual(outputs.length, index + 1, JSON.stringify(outputs));
}
}
export interface MakeReferenceItem extends DocumentSpanFromSubstring {
isDefinition: boolean;
lineText: string;
}
export function makeReferenceItem({ isDefinition, lineText, ...rest }: MakeReferenceItem): protocol.ReferencesResponseItem {
return {
...protocolFileSpanWithContextFromSubstring(rest),
isDefinition,
isWriteAccess: isDefinition,
lineText,
};
}
}
@@ -345,5 +345,92 @@ namespace ts.projectSystem {
it("inferred projects per project root with case insensitive system", () => {
verifyProjectRootWithCaseSensitivity(/*useCaseSensitiveFileNames*/ false);
});
it("should still retain configured project created while opening the file", () => {
const projectRoot = "/user/username/projects/project";
const appFile: File = {
path: `${projectRoot}/app.ts`,
content: `const app = 20;`
};
const config: File = {
path: `${projectRoot}/tsconfig.json`,
content: "{}"
};
const jsFile1: File = {
path: `${projectRoot}/jsFile1.js`,
content: `const jsFile1 = 10;`
};
const jsFile2: File = {
path: `${projectRoot}/jsFile2.js`,
content: `const jsFile2 = 10;`
};
const host = createServerHost([appFile, libFile, config, jsFile1, jsFile2]);
const projectService = createProjectService(host);
const originalSet = projectService.configuredProjects.set;
const originalDelete = projectService.configuredProjects.delete;
const configuredCreated = createMap<true>();
const configuredRemoved = createMap<true>();
projectService.configuredProjects.set = (key, value) => {
assert.isFalse(configuredCreated.has(key));
configuredCreated.set(key, true);
return originalSet.call(projectService.configuredProjects, key, value);
};
projectService.configuredProjects.delete = key => {
assert.isFalse(configuredRemoved.has(key));
configuredRemoved.set(key, true);
return originalDelete.call(projectService.configuredProjects, key);
};
// Do not remove config project when opening jsFile that is not present as part of config project
projectService.openClientFile(jsFile1.path);
checkNumberOfProjects(projectService, { inferredProjects: 1, configuredProjects: 1 });
checkProjectActualFiles(projectService.inferredProjects[0], [jsFile1.path, libFile.path]);
const project = projectService.configuredProjects.get(config.path)!;
checkProjectActualFiles(project, [appFile.path, config.path, libFile.path]);
checkConfiguredProjectCreatedAndNotDeleted();
// Do not remove config project when opening jsFile that is not present as part of config project
projectService.closeClientFile(jsFile1.path);
checkNumberOfProjects(projectService, { inferredProjects: 1, configuredProjects: 1 });
projectService.openClientFile(jsFile2.path);
checkNumberOfProjects(projectService, { inferredProjects: 1, configuredProjects: 1 });
checkProjectActualFiles(projectService.inferredProjects[0], [jsFile2.path, libFile.path]);
checkProjectActualFiles(project, [appFile.path, config.path, libFile.path]);
checkConfiguredProjectNotCreatedAndNotDeleted();
// Do not remove config project when opening jsFile that is not present as part of config project
projectService.openClientFile(jsFile1.path);
checkNumberOfProjects(projectService, { inferredProjects: 2, configuredProjects: 1 });
checkProjectActualFiles(projectService.inferredProjects[0], [jsFile2.path, libFile.path]);
checkProjectActualFiles(projectService.inferredProjects[1], [jsFile1.path, libFile.path]);
checkProjectActualFiles(project, [appFile.path, config.path, libFile.path]);
checkConfiguredProjectNotCreatedAndNotDeleted();
// When opening file that doesnt fall back to the config file, we remove the config project
projectService.openClientFile(libFile.path);
checkNumberOfProjects(projectService, { inferredProjects: 2 });
checkProjectActualFiles(projectService.inferredProjects[0], [jsFile2.path, libFile.path]);
checkProjectActualFiles(projectService.inferredProjects[1], [jsFile1.path, libFile.path]);
checkConfiguredProjectNotCreatedButDeleted();
function checkConfiguredProjectCreatedAndNotDeleted() {
assert.equal(configuredCreated.size, 1);
assert.isTrue(configuredCreated.has(config.path));
assert.equal(configuredRemoved.size, 0);
configuredCreated.clear();
}
function checkConfiguredProjectNotCreatedAndNotDeleted() {
assert.equal(configuredCreated.size, 0);
assert.equal(configuredRemoved.size, 0);
}
function checkConfiguredProjectNotCreatedButDeleted() {
assert.equal(configuredCreated.size, 0);
assert.equal(configuredRemoved.size, 1);
assert.isTrue(configuredRemoved.has(config.path));
configuredRemoved.clear();
}
});
});
}
+31 -4
View File
@@ -634,13 +634,17 @@ namespace ts.projectSystem {
path: "/a/main.js",
content: "var y = 1"
};
const f3 = {
path: "/main.js",
content: "var y = 1"
};
const config = {
path: "/a/tsconfig.json",
content: JSON.stringify({
compilerOptions: { allowJs: true }
})
};
const host = createServerHost([f1, f2, config]);
const host = createServerHost([f1, f2, f3, config]);
const projectService = createProjectService(host);
projectService.setHostConfiguration({
extraFileExtensions: [
@@ -652,13 +656,19 @@ namespace ts.projectSystem {
projectService.checkNumberOfProjects({ configuredProjects: 1 });
checkProjectActualFiles(configuredProjectAt(projectService, 0), [f1.path, config.path]);
// Should close configured project with next file open
// Since f2 refers to config file as the default project, it needs to be kept alive
projectService.closeClientFile(f1.path);
projectService.openClientFile(f2.path);
projectService.checkNumberOfProjects({ inferredProjects: 1, configuredProjects: 1 });
assert.isDefined(projectService.configuredProjects.get(config.path));
checkProjectActualFiles(projectService.inferredProjects[0], [f2.path]);
// Should close configured project with next file open
projectService.closeClientFile(f2.path);
projectService.openClientFile(f3.path);
projectService.checkNumberOfProjects({ inferredProjects: 1 });
assert.isUndefined(projectService.configuredProjects.get(config.path));
checkProjectActualFiles(projectService.inferredProjects[0], [f2.path]);
checkProjectActualFiles(projectService.inferredProjects[0], [f3.path]);
});
it("tsconfig script block support", () => {
@@ -1467,5 +1477,22 @@ var x = 10;`
openFilesForSession([{ file, projectRootPath }], session);
}
});
it("assert when removing project", () => {
const host = createServerHost([commonFile1, commonFile2, libFile]);
const service = createProjectService(host);
service.openClientFile(commonFile1.path);
const project = service.inferredProjects[0];
checkProjectActualFiles(project, [commonFile1.path, libFile.path]);
// Intentionally create scriptinfo and attach it to project
const info = service.getOrCreateScriptInfoForNormalizedPath(commonFile2.path as server.NormalizedPath, /*openedByClient*/ false)!;
info.attachToProject(project);
try {
service.applyChangesInOpenFiles(/*openFiles*/ undefined, /*changedFiles*/ undefined, [commonFile1.path]);
}
catch (e) {
assert.isTrue(e.message.indexOf("Debug Failure. False expression: Found script Info still attached to project") === 0);
}
});
});
}
@@ -1,6 +1,6 @@
namespace ts.projectSystem {
import validatePackageName = JsTyping.validatePackageName;
import PackageNameValidationResult = JsTyping.PackageNameValidationResult;
import NameValidationResult = JsTyping.NameValidationResult;
interface InstallerParams {
globalTypingsCacheLocation?: string;
@@ -948,7 +948,8 @@ namespace ts.projectSystem {
path: "/a/b/app.js",
content: `
import * as fs from "fs";
import * as commander from "commander";`
import * as commander from "commander";
import * as component from "@ember/component";`
};
const cachePath = "/a/cache";
const node = {
@@ -959,14 +960,19 @@ namespace ts.projectSystem {
path: cachePath + "/node_modules/@types/commander/index.d.ts",
content: "export let y: string"
};
const emberComponentDirectory = "ember__component";
const emberComponent = {
path: `${cachePath}/node_modules/@types/${emberComponentDirectory}/index.d.ts`,
content: "export let x: number"
};
const host = createServerHost([file]);
const installer = new (class extends Installer {
constructor() {
super(host, { globalTypingsCacheLocation: cachePath, typesRegistry: createTypesRegistry("node", "commander") });
}
installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction) {
const installedTypings = ["@types/node", "@types/commander"];
const typingFiles = [node, commander];
const installedTypings = ["@types/node", "@types/commander", `@types/${emberComponentDirectory}`];
const typingFiles = [node, commander, emberComponent];
executeCommand(this, host, installedTypings, typingFiles, cb);
}
})();
@@ -980,9 +986,10 @@ namespace ts.projectSystem {
assert.isTrue(host.fileExists(node.path), "typings for 'node' should be created");
assert.isTrue(host.fileExists(commander.path), "typings for 'commander' should be created");
assert.isTrue(host.fileExists(emberComponent.path), "typings for 'commander' should be created");
host.checkTimeoutQueueLengthAndRun(2);
checkProjectActualFiles(service.inferredProjects[0], [file.path, node.path, commander.path]);
checkProjectActualFiles(service.inferredProjects[0], [file.path, node.path, commander.path, emberComponent.path]);
});
it("should redo resolution that resolved to '.js' file after typings are installed", () => {
@@ -1263,21 +1270,44 @@ namespace ts.projectSystem {
for (let i = 0; i < 8; i++) {
packageName += packageName;
}
assert.equal(validatePackageName(packageName), PackageNameValidationResult.NameTooLong);
assert.equal(validatePackageName(packageName), NameValidationResult.NameTooLong);
});
it("name cannot start with dot", () => {
assert.equal(validatePackageName(".foo"), PackageNameValidationResult.NameStartsWithDot);
it("package name cannot start with dot", () => {
assert.equal(validatePackageName(".foo"), NameValidationResult.NameStartsWithDot);
});
it("name cannot start with underscore", () => {
assert.equal(validatePackageName("_foo"), PackageNameValidationResult.NameStartsWithUnderscore);
it("package name cannot start with underscore", () => {
assert.equal(validatePackageName("_foo"), NameValidationResult.NameStartsWithUnderscore);
});
it("scoped packages not supported", () => {
assert.equal(validatePackageName("@scope/bar"), PackageNameValidationResult.ScopedPackagesNotSupported);
it("package non URI safe characters are not supported", () => {
assert.equal(validatePackageName(" scope "), NameValidationResult.NameContainsNonURISafeCharacters);
assert.equal(validatePackageName("; say Hello from TypeScript! #"), NameValidationResult.NameContainsNonURISafeCharacters);
assert.equal(validatePackageName("a/b/c"), NameValidationResult.NameContainsNonURISafeCharacters);
});
it("non URI safe characters are not supported", () => {
assert.equal(validatePackageName(" scope "), PackageNameValidationResult.NameContainsNonURISafeCharacters);
assert.equal(validatePackageName("; say Hello from TypeScript! #"), PackageNameValidationResult.NameContainsNonURISafeCharacters);
assert.equal(validatePackageName("a/b/c"), PackageNameValidationResult.NameContainsNonURISafeCharacters);
it("scoped package name is supported", () => {
assert.equal(validatePackageName("@scope/bar"), NameValidationResult.Ok);
});
it("scoped name in scoped package name cannot start with dot", () => {
assert.deepEqual(validatePackageName("@.scope/bar"), { name: ".scope", isScopeName: true, result: NameValidationResult.NameStartsWithDot });
assert.deepEqual(validatePackageName("@.scope/.bar"), { name: ".scope", isScopeName: true, result: NameValidationResult.NameStartsWithDot });
});
it("scope name in scoped package name cannot start with underscore", () => {
assert.deepEqual(validatePackageName("@_scope/bar"), { name: "_scope", isScopeName: true, result: NameValidationResult.NameStartsWithUnderscore });
assert.deepEqual(validatePackageName("@_scope/_bar"), { name: "_scope", isScopeName: true, result: NameValidationResult.NameStartsWithUnderscore });
});
it("scope name in scoped package name with non URI safe characters are not supported", () => {
assert.deepEqual(validatePackageName("@ scope /bar"), { name: " scope ", isScopeName: true, result: NameValidationResult.NameContainsNonURISafeCharacters });
assert.deepEqual(validatePackageName("@; say Hello from TypeScript! #/bar"), { name: "; say Hello from TypeScript! #", isScopeName: true, result: NameValidationResult.NameContainsNonURISafeCharacters });
assert.deepEqual(validatePackageName("@ scope / bar "), { name: " scope ", isScopeName: true, result: NameValidationResult.NameContainsNonURISafeCharacters });
});
it("package name in scoped package name cannot start with dot", () => {
assert.deepEqual(validatePackageName("@scope/.bar"), { name: ".bar", isScopeName: false, result: NameValidationResult.NameStartsWithDot });
});
it("package name in scoped package name cannot start with underscore", () => {
assert.deepEqual(validatePackageName("@scope/_bar"), { name: "_bar", isScopeName: false, result: NameValidationResult.NameStartsWithUnderscore });
});
it("package name in scoped package name with non URI safe characters are not supported", () => {
assert.deepEqual(validatePackageName("@scope/ bar "), { name: " bar ", isScopeName: false, result: NameValidationResult.NameContainsNonURISafeCharacters });
assert.deepEqual(validatePackageName("@scope/; say Hello from TypeScript! #"), { name: "; say Hello from TypeScript! #", isScopeName: false, result: NameValidationResult.NameContainsNonURISafeCharacters });
});
});
@@ -1309,7 +1339,7 @@ namespace ts.projectSystem {
projectService.openClientFile(f1.path);
installer.checkPendingCommands(/*expectedCount*/ 0);
assert.isTrue(messages.indexOf("Package name '; say Hello from TypeScript! #' contains non URI safe characters") > 0, "should find package with invalid name");
assert.isTrue(messages.indexOf("'; say Hello from TypeScript! #':: Package name '; say Hello from TypeScript! #' contains non URI safe characters") > 0, "should find package with invalid name");
});
});
+21 -1
View File
@@ -180,6 +180,18 @@ namespace ts.server {
}
msg(s: string, type: Msg = Msg.Err) {
switch (type) {
case Msg.Info:
perfLogger.logInfoEvent(s);
break;
case Msg.Perf:
perfLogger.logPerfEvent(s);
break;
default: // Msg.Err
perfLogger.logErrEvent(s);
break;
}
if (!this.canWrite) return;
s = `[${nowString()}] ${s}\n`;
@@ -248,7 +260,7 @@ namespace ts.server {
isKnownTypesPackageName(name: string): boolean {
// We want to avoid looking this up in the registry as that is expensive. So first check that it's actually an NPM package.
const validationResult = JsTyping.validatePackageName(name);
if (validationResult !== JsTyping.PackageNameValidationResult.Ok) {
if (validationResult !== JsTyping.NameValidationResult.Ok) {
return false;
}
@@ -970,4 +982,12 @@ namespace ts.server {
if (ts.sys.tryEnableSourceMapsForHost && /^development$/i.test(ts.sys.getEnvironmentVariable("NODE_ENV"))) {
ts.sys.tryEnableSourceMapsForHost();
}
// Overwrites the current console messages to instead write to
// the log. This is so that language service plugins which use
// console.log don't break the message passing between tsserver
// and the client
console.log = (...args) => logger.msg(args.length === 1 ? args[0] : args.join(", "), Msg.Info);
console.warn = (...args) => logger.msg(args.length === 1 ? args[0] : args.join(", "), Msg.Err);
console.error = (...args) => logger.msg(args.length === 1 ? args[0] : args.join(", "), Msg.Err);
}
+15 -14
View File
@@ -268,27 +268,28 @@ namespace ts.server.typingsInstaller {
}
private filterTypings(typingsToInstall: ReadonlyArray<string>): ReadonlyArray<string> {
return typingsToInstall.filter(typing => {
if (this.missingTypingsSet.get(typing)) {
if (this.log.isEnabled()) this.log.writeLine(`'${typing}' is in missingTypingsSet - skipping...`);
return false;
return mapDefined(typingsToInstall, typing => {
const typingKey = mangleScopedPackageName(typing);
if (this.missingTypingsSet.get(typingKey)) {
if (this.log.isEnabled()) this.log.writeLine(`'${typing}':: '${typingKey}' is in missingTypingsSet - skipping...`);
return undefined;
}
const validationResult = JsTyping.validatePackageName(typing);
if (validationResult !== JsTyping.PackageNameValidationResult.Ok) {
if (validationResult !== JsTyping.NameValidationResult.Ok) {
// add typing name to missing set so we won't process it again
this.missingTypingsSet.set(typing, true);
this.missingTypingsSet.set(typingKey, true);
if (this.log.isEnabled()) this.log.writeLine(JsTyping.renderPackageNameValidationFailure(validationResult, typing));
return false;
return undefined;
}
if (!this.typesRegistry.has(typing)) {
if (this.log.isEnabled()) this.log.writeLine(`Entry for package '${typing}' does not exist in local types registry - skipping...`);
return false;
if (!this.typesRegistry.has(typingKey)) {
if (this.log.isEnabled()) this.log.writeLine(`'${typing}':: Entry for package '${typingKey}' does not exist in local types registry - skipping...`);
return undefined;
}
if (this.packageNameToTypingLocation.get(typing) && JsTyping.isTypingUpToDate(this.packageNameToTypingLocation.get(typing)!, this.typesRegistry.get(typing)!)) {
if (this.log.isEnabled()) this.log.writeLine(`'${typing}' already has an up-to-date typing - skipping...`);
return false;
if (this.packageNameToTypingLocation.get(typingKey) && JsTyping.isTypingUpToDate(this.packageNameToTypingLocation.get(typingKey)!, this.typesRegistry.get(typingKey)!)) {
if (this.log.isEnabled()) this.log.writeLine(`'${typing}':: '${typingKey}' already has an up-to-date typing - skipping...`);
return undefined;
}
return true;
return typingKey;
});
}
+4 -3
View File
@@ -4,15 +4,16 @@ for (var v of ['a', 'b', 'c']) {
}
//// [ES5For-of33.js]
var __values = (this && this.__values) || function (o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
return {
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var e_1, _a;
try {
+1 -1
View File
@@ -1,2 +1,2 @@
//// [ES5For-of33.js.map]
{"version":3,"file":"ES5For-of33.js","sourceRoot":"","sources":["ES5For-of33.ts"],"names":[],"mappings":";;;;;;;;;;;;IAAA,KAAc,IAAA,KAAA,SAAA,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA,gBAAA,4BAAE;QAA1B,IAAI,CAAC,WAAA;QACN,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;KAClB"}
{"version":3,"file":"ES5For-of33.js","sourceRoot":"","sources":["ES5For-of33.ts"],"names":[],"mappings":";;;;;;;;;;;;;IAAA,KAAc,IAAA,KAAA,SAAA,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA,gBAAA,4BAAE;QAA1B,IAAI,CAAC,WAAA;QACN,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;KAClB"}
@@ -8,15 +8,16 @@ sources: ES5For-of33.ts
emittedFile:tests/cases/conformance/statements/for-ofStatements/ES5For-of33.js
sourceFile:ES5For-of33.ts
-------------------------------------------------------------------
>>>var __values = (this && this.__values) || function (o) {
>>> var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
>>>var __values = (this && this.__values) || function(o) {
>>> var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
>>> if (m) return m.call(o);
>>> return {
>>> if (o && typeof o.length === "number") return {
>>> next: function () {
>>> if (o && i >= o.length) o = void 0;
>>> return { value: o && o[i++], done: !o };
>>> }
>>> };
>>> throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
>>>};
>>>var e_1, _a;
>>>try {
@@ -51,21 +52,21 @@ sourceFile:ES5For-of33.ts
13>
14>
15> )
1 >Emitted(13, 5) Source(1, 1) + SourceIndex(0)
2 >Emitted(13, 10) Source(1, 15) + SourceIndex(0)
3 >Emitted(13, 14) Source(1, 15) + SourceIndex(0)
4 >Emitted(13, 19) Source(1, 15) + SourceIndex(0)
5 >Emitted(13, 28) Source(1, 15) + SourceIndex(0)
6 >Emitted(13, 29) Source(1, 16) + SourceIndex(0)
7 >Emitted(13, 32) Source(1, 19) + SourceIndex(0)
8 >Emitted(13, 34) Source(1, 21) + SourceIndex(0)
9 >Emitted(13, 37) Source(1, 24) + SourceIndex(0)
10>Emitted(13, 39) Source(1, 26) + SourceIndex(0)
11>Emitted(13, 42) Source(1, 29) + SourceIndex(0)
12>Emitted(13, 43) Source(1, 30) + SourceIndex(0)
13>Emitted(13, 44) Source(1, 30) + SourceIndex(0)
14>Emitted(13, 60) Source(1, 30) + SourceIndex(0)
15>Emitted(13, 88) Source(1, 32) + SourceIndex(0)
1 >Emitted(14, 5) Source(1, 1) + SourceIndex(0)
2 >Emitted(14, 10) Source(1, 15) + SourceIndex(0)
3 >Emitted(14, 14) Source(1, 15) + SourceIndex(0)
4 >Emitted(14, 19) Source(1, 15) + SourceIndex(0)
5 >Emitted(14, 28) Source(1, 15) + SourceIndex(0)
6 >Emitted(14, 29) Source(1, 16) + SourceIndex(0)
7 >Emitted(14, 32) Source(1, 19) + SourceIndex(0)
8 >Emitted(14, 34) Source(1, 21) + SourceIndex(0)
9 >Emitted(14, 37) Source(1, 24) + SourceIndex(0)
10>Emitted(14, 39) Source(1, 26) + SourceIndex(0)
11>Emitted(14, 42) Source(1, 29) + SourceIndex(0)
12>Emitted(14, 43) Source(1, 30) + SourceIndex(0)
13>Emitted(14, 44) Source(1, 30) + SourceIndex(0)
14>Emitted(14, 60) Source(1, 30) + SourceIndex(0)
15>Emitted(14, 88) Source(1, 32) + SourceIndex(0)
---
>>> var v = _c.value;
1 >^^^^^^^^
@@ -76,10 +77,10 @@ sourceFile:ES5For-of33.ts
2 > var
3 > v
4 >
1 >Emitted(14, 9) Source(1, 6) + SourceIndex(0)
2 >Emitted(14, 13) Source(1, 10) + SourceIndex(0)
3 >Emitted(14, 14) Source(1, 11) + SourceIndex(0)
4 >Emitted(14, 25) Source(1, 11) + SourceIndex(0)
1 >Emitted(15, 9) Source(1, 6) + SourceIndex(0)
2 >Emitted(15, 13) Source(1, 10) + SourceIndex(0)
3 >Emitted(15, 14) Source(1, 11) + SourceIndex(0)
4 >Emitted(15, 25) Source(1, 11) + SourceIndex(0)
---
>>> console.log(v);
1 >^^^^^^^^
@@ -99,20 +100,20 @@ sourceFile:ES5For-of33.ts
6 > v
7 > )
8 > ;
1 >Emitted(15, 9) Source(2, 5) + SourceIndex(0)
2 >Emitted(15, 16) Source(2, 12) + SourceIndex(0)
3 >Emitted(15, 17) Source(2, 13) + SourceIndex(0)
4 >Emitted(15, 20) Source(2, 16) + SourceIndex(0)
5 >Emitted(15, 21) Source(2, 17) + SourceIndex(0)
6 >Emitted(15, 22) Source(2, 18) + SourceIndex(0)
7 >Emitted(15, 23) Source(2, 19) + SourceIndex(0)
8 >Emitted(15, 24) Source(2, 20) + SourceIndex(0)
1 >Emitted(16, 9) Source(2, 5) + SourceIndex(0)
2 >Emitted(16, 16) Source(2, 12) + SourceIndex(0)
3 >Emitted(16, 17) Source(2, 13) + SourceIndex(0)
4 >Emitted(16, 20) Source(2, 16) + SourceIndex(0)
5 >Emitted(16, 21) Source(2, 17) + SourceIndex(0)
6 >Emitted(16, 22) Source(2, 18) + SourceIndex(0)
7 >Emitted(16, 23) Source(2, 19) + SourceIndex(0)
8 >Emitted(16, 24) Source(2, 20) + SourceIndex(0)
---
>>> }
1 >^^^^^
1 >
>}
1 >Emitted(16, 6) Source(3, 2) + SourceIndex(0)
1 >Emitted(17, 6) Source(3, 2) + SourceIndex(0)
---
>>>}
>>>catch (e_1_1) { e_1 = { error: e_1_1 }; }
+4 -3
View File
@@ -7,15 +7,16 @@ for (foo().x of ['a', 'b', 'c']) {
}
//// [ES5For-of34.js]
var __values = (this && this.__values) || function (o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
return {
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var e_1, _a;
function foo() {
+1 -1
View File
@@ -1,2 +1,2 @@
//// [ES5For-of34.js.map]
{"version":3,"file":"ES5For-of34.js","sourceRoot":"","sources":["ES5For-of34.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,SAAS,GAAG;IACR,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;AACpB,CAAC;;IACD,KAAgB,IAAA,KAAA,SAAA,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA,gBAAA,4BAAE;QAA5B,GAAG,EAAE,CAAC,CAAC,WAAA;QACR,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC;KACnB"}
{"version":3,"file":"ES5For-of34.js","sourceRoot":"","sources":["ES5For-of34.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,SAAS,GAAG;IACR,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;AACpB,CAAC;;IACD,KAAgB,IAAA,KAAA,SAAA,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA,gBAAA,4BAAE;QAA5B,GAAG,EAAE,CAAC,CAAC,WAAA;QACR,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC;KACnB"}
@@ -8,15 +8,16 @@ sources: ES5For-of34.ts
emittedFile:tests/cases/conformance/statements/for-ofStatements/ES5For-of34.js
sourceFile:ES5For-of34.ts
-------------------------------------------------------------------
>>>var __values = (this && this.__values) || function (o) {
>>> var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
>>>var __values = (this && this.__values) || function(o) {
>>> var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
>>> if (m) return m.call(o);
>>> return {
>>> if (o && typeof o.length === "number") return {
>>> next: function () {
>>> if (o && i >= o.length) o = void 0;
>>> return { value: o && o[i++], done: !o };
>>> }
>>> };
>>> throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
>>>};
>>>var e_1, _a;
>>>function foo() {
@@ -27,9 +28,9 @@ sourceFile:ES5For-of34.ts
1 >
2 >function
3 > foo
1 >Emitted(12, 1) Source(1, 1) + SourceIndex(0)
2 >Emitted(12, 10) Source(1, 10) + SourceIndex(0)
3 >Emitted(12, 13) Source(1, 13) + SourceIndex(0)
1 >Emitted(13, 1) Source(1, 1) + SourceIndex(0)
2 >Emitted(13, 10) Source(1, 10) + SourceIndex(0)
3 >Emitted(13, 13) Source(1, 13) + SourceIndex(0)
---
>>> return { x: 0 };
1->^^^^
@@ -49,14 +50,14 @@ sourceFile:ES5For-of34.ts
6 > 0
7 > }
8 > ;
1->Emitted(13, 5) Source(2, 5) + SourceIndex(0)
2 >Emitted(13, 12) Source(2, 12) + SourceIndex(0)
3 >Emitted(13, 14) Source(2, 14) + SourceIndex(0)
4 >Emitted(13, 15) Source(2, 15) + SourceIndex(0)
5 >Emitted(13, 17) Source(2, 17) + SourceIndex(0)
6 >Emitted(13, 18) Source(2, 18) + SourceIndex(0)
7 >Emitted(13, 20) Source(2, 20) + SourceIndex(0)
8 >Emitted(13, 21) Source(2, 21) + SourceIndex(0)
1->Emitted(14, 5) Source(2, 5) + SourceIndex(0)
2 >Emitted(14, 12) Source(2, 12) + SourceIndex(0)
3 >Emitted(14, 14) Source(2, 14) + SourceIndex(0)
4 >Emitted(14, 15) Source(2, 15) + SourceIndex(0)
5 >Emitted(14, 17) Source(2, 17) + SourceIndex(0)
6 >Emitted(14, 18) Source(2, 18) + SourceIndex(0)
7 >Emitted(14, 20) Source(2, 20) + SourceIndex(0)
8 >Emitted(14, 21) Source(2, 21) + SourceIndex(0)
---
>>>}
1 >
@@ -65,8 +66,8 @@ sourceFile:ES5For-of34.ts
1 >
>
2 >}
1 >Emitted(14, 1) Source(3, 1) + SourceIndex(0)
2 >Emitted(14, 2) Source(3, 2) + SourceIndex(0)
1 >Emitted(15, 1) Source(3, 1) + SourceIndex(0)
2 >Emitted(15, 2) Source(3, 2) + SourceIndex(0)
---
>>>try {
>>> for (var _b = __values(['a', 'b', 'c']), _c = _b.next(); !_c.done; _c = _b.next()) {
@@ -101,21 +102,21 @@ sourceFile:ES5For-of34.ts
13>
14>
15> )
1->Emitted(16, 5) Source(4, 1) + SourceIndex(0)
2 >Emitted(16, 10) Source(4, 17) + SourceIndex(0)
3 >Emitted(16, 14) Source(4, 17) + SourceIndex(0)
4 >Emitted(16, 19) Source(4, 17) + SourceIndex(0)
5 >Emitted(16, 28) Source(4, 17) + SourceIndex(0)
6 >Emitted(16, 29) Source(4, 18) + SourceIndex(0)
7 >Emitted(16, 32) Source(4, 21) + SourceIndex(0)
8 >Emitted(16, 34) Source(4, 23) + SourceIndex(0)
9 >Emitted(16, 37) Source(4, 26) + SourceIndex(0)
10>Emitted(16, 39) Source(4, 28) + SourceIndex(0)
11>Emitted(16, 42) Source(4, 31) + SourceIndex(0)
12>Emitted(16, 43) Source(4, 32) + SourceIndex(0)
13>Emitted(16, 44) Source(4, 32) + SourceIndex(0)
14>Emitted(16, 60) Source(4, 32) + SourceIndex(0)
15>Emitted(16, 88) Source(4, 34) + SourceIndex(0)
1->Emitted(17, 5) Source(4, 1) + SourceIndex(0)
2 >Emitted(17, 10) Source(4, 17) + SourceIndex(0)
3 >Emitted(17, 14) Source(4, 17) + SourceIndex(0)
4 >Emitted(17, 19) Source(4, 17) + SourceIndex(0)
5 >Emitted(17, 28) Source(4, 17) + SourceIndex(0)
6 >Emitted(17, 29) Source(4, 18) + SourceIndex(0)
7 >Emitted(17, 32) Source(4, 21) + SourceIndex(0)
8 >Emitted(17, 34) Source(4, 23) + SourceIndex(0)
9 >Emitted(17, 37) Source(4, 26) + SourceIndex(0)
10>Emitted(17, 39) Source(4, 28) + SourceIndex(0)
11>Emitted(17, 42) Source(4, 31) + SourceIndex(0)
12>Emitted(17, 43) Source(4, 32) + SourceIndex(0)
13>Emitted(17, 44) Source(4, 32) + SourceIndex(0)
14>Emitted(17, 60) Source(4, 32) + SourceIndex(0)
15>Emitted(17, 88) Source(4, 34) + SourceIndex(0)
---
>>> foo().x = _c.value;
1 >^^^^^^^^
@@ -130,12 +131,12 @@ sourceFile:ES5For-of34.ts
4 > .
5 > x
6 >
1 >Emitted(17, 9) Source(4, 6) + SourceIndex(0)
2 >Emitted(17, 12) Source(4, 9) + SourceIndex(0)
3 >Emitted(17, 14) Source(4, 11) + SourceIndex(0)
4 >Emitted(17, 15) Source(4, 12) + SourceIndex(0)
5 >Emitted(17, 16) Source(4, 13) + SourceIndex(0)
6 >Emitted(17, 27) Source(4, 13) + SourceIndex(0)
1 >Emitted(18, 9) Source(4, 6) + SourceIndex(0)
2 >Emitted(18, 12) Source(4, 9) + SourceIndex(0)
3 >Emitted(18, 14) Source(4, 11) + SourceIndex(0)
4 >Emitted(18, 15) Source(4, 12) + SourceIndex(0)
5 >Emitted(18, 16) Source(4, 13) + SourceIndex(0)
6 >Emitted(18, 27) Source(4, 13) + SourceIndex(0)
---
>>> var p = foo().x;
1 >^^^^^^^^
@@ -157,21 +158,21 @@ sourceFile:ES5For-of34.ts
7 > .
8 > x
9 > ;
1 >Emitted(18, 9) Source(5, 5) + SourceIndex(0)
2 >Emitted(18, 13) Source(5, 9) + SourceIndex(0)
3 >Emitted(18, 14) Source(5, 10) + SourceIndex(0)
4 >Emitted(18, 17) Source(5, 13) + SourceIndex(0)
5 >Emitted(18, 20) Source(5, 16) + SourceIndex(0)
6 >Emitted(18, 22) Source(5, 18) + SourceIndex(0)
7 >Emitted(18, 23) Source(5, 19) + SourceIndex(0)
8 >Emitted(18, 24) Source(5, 20) + SourceIndex(0)
9 >Emitted(18, 25) Source(5, 21) + SourceIndex(0)
1 >Emitted(19, 9) Source(5, 5) + SourceIndex(0)
2 >Emitted(19, 13) Source(5, 9) + SourceIndex(0)
3 >Emitted(19, 14) Source(5, 10) + SourceIndex(0)
4 >Emitted(19, 17) Source(5, 13) + SourceIndex(0)
5 >Emitted(19, 20) Source(5, 16) + SourceIndex(0)
6 >Emitted(19, 22) Source(5, 18) + SourceIndex(0)
7 >Emitted(19, 23) Source(5, 19) + SourceIndex(0)
8 >Emitted(19, 24) Source(5, 20) + SourceIndex(0)
9 >Emitted(19, 25) Source(5, 21) + SourceIndex(0)
---
>>> }
1 >^^^^^
1 >
>}
1 >Emitted(19, 6) Source(6, 2) + SourceIndex(0)
1 >Emitted(20, 6) Source(6, 2) + SourceIndex(0)
---
>>>}
>>>catch (e_1_1) { e_1 = { error: e_1_1 }; }
+4 -3
View File
@@ -5,15 +5,16 @@ for (const {x: a = 0, y: b = 1} of [2, 3]) {
}
//// [ES5For-of35.js]
var __values = (this && this.__values) || function (o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
return {
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var e_1, _a;
try {
+1 -1
View File
@@ -1,2 +1,2 @@
//// [ES5For-of35.js.map]
{"version":3,"file":"ES5For-of35.js","sourceRoot":"","sources":["ES5For-of35.ts"],"names":[],"mappings":";;;;;;;;;;;;IAAA,KAAmC,IAAA,KAAA,SAAA,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA,gBAAA,4BAAE;QAAhC,IAAA,aAAoB,EAAnB,SAAQ,EAAR,0BAAQ,EAAE,SAAQ,EAAR,0BAAQ;QAC1B,CAAC,CAAC;QACF,CAAC,CAAC;KACL"}
{"version":3,"file":"ES5For-of35.js","sourceRoot":"","sources":["ES5For-of35.ts"],"names":[],"mappings":";;;;;;;;;;;;;IAAA,KAAmC,IAAA,KAAA,SAAA,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA,gBAAA,4BAAE;QAAhC,IAAA,aAAoB,EAAnB,SAAQ,EAAR,0BAAQ,EAAE,SAAQ,EAAR,0BAAQ;QAC1B,CAAC,CAAC;QACF,CAAC,CAAC;KACL"}
@@ -8,15 +8,16 @@ sources: ES5For-of35.ts
emittedFile:tests/cases/conformance/statements/for-ofStatements/ES5For-of35.js
sourceFile:ES5For-of35.ts
-------------------------------------------------------------------
>>>var __values = (this && this.__values) || function (o) {
>>> var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
>>>var __values = (this && this.__values) || function(o) {
>>> var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
>>> if (m) return m.call(o);
>>> return {
>>> if (o && typeof o.length === "number") return {
>>> next: function () {
>>> if (o && i >= o.length) o = void 0;
>>> return { value: o && o[i++], done: !o };
>>> }
>>> };
>>> throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
>>>};
>>>var e_1, _a;
>>>try {
@@ -48,19 +49,19 @@ sourceFile:ES5For-of35.ts
11>
12>
13> )
1 >Emitted(13, 5) Source(1, 1) + SourceIndex(0)
2 >Emitted(13, 10) Source(1, 36) + SourceIndex(0)
3 >Emitted(13, 14) Source(1, 36) + SourceIndex(0)
4 >Emitted(13, 19) Source(1, 36) + SourceIndex(0)
5 >Emitted(13, 28) Source(1, 36) + SourceIndex(0)
6 >Emitted(13, 29) Source(1, 37) + SourceIndex(0)
7 >Emitted(13, 30) Source(1, 38) + SourceIndex(0)
8 >Emitted(13, 32) Source(1, 40) + SourceIndex(0)
9 >Emitted(13, 33) Source(1, 41) + SourceIndex(0)
10>Emitted(13, 34) Source(1, 42) + SourceIndex(0)
11>Emitted(13, 35) Source(1, 42) + SourceIndex(0)
12>Emitted(13, 51) Source(1, 42) + SourceIndex(0)
13>Emitted(13, 79) Source(1, 44) + SourceIndex(0)
1 >Emitted(14, 5) Source(1, 1) + SourceIndex(0)
2 >Emitted(14, 10) Source(1, 36) + SourceIndex(0)
3 >Emitted(14, 14) Source(1, 36) + SourceIndex(0)
4 >Emitted(14, 19) Source(1, 36) + SourceIndex(0)
5 >Emitted(14, 28) Source(1, 36) + SourceIndex(0)
6 >Emitted(14, 29) Source(1, 37) + SourceIndex(0)
7 >Emitted(14, 30) Source(1, 38) + SourceIndex(0)
8 >Emitted(14, 32) Source(1, 40) + SourceIndex(0)
9 >Emitted(14, 33) Source(1, 41) + SourceIndex(0)
10>Emitted(14, 34) Source(1, 42) + SourceIndex(0)
11>Emitted(14, 35) Source(1, 42) + SourceIndex(0)
12>Emitted(14, 51) Source(1, 42) + SourceIndex(0)
13>Emitted(14, 79) Source(1, 44) + SourceIndex(0)
---
>>> var _d = _c.value, _e = _d.x, a = _e === void 0 ? 0 : _e, _f = _d.y, b = _f === void 0 ? 1 : _f;
1->^^^^^^^^
@@ -85,17 +86,17 @@ sourceFile:ES5For-of35.ts
9 > y: b = 1
10>
11> y: b = 1
1->Emitted(14, 9) Source(1, 12) + SourceIndex(0)
2 >Emitted(14, 13) Source(1, 12) + SourceIndex(0)
3 >Emitted(14, 26) Source(1, 32) + SourceIndex(0)
4 >Emitted(14, 28) Source(1, 13) + SourceIndex(0)
5 >Emitted(14, 37) Source(1, 21) + SourceIndex(0)
6 >Emitted(14, 39) Source(1, 13) + SourceIndex(0)
7 >Emitted(14, 65) Source(1, 21) + SourceIndex(0)
8 >Emitted(14, 67) Source(1, 23) + SourceIndex(0)
9 >Emitted(14, 76) Source(1, 31) + SourceIndex(0)
10>Emitted(14, 78) Source(1, 23) + SourceIndex(0)
11>Emitted(14, 104) Source(1, 31) + SourceIndex(0)
1->Emitted(15, 9) Source(1, 12) + SourceIndex(0)
2 >Emitted(15, 13) Source(1, 12) + SourceIndex(0)
3 >Emitted(15, 26) Source(1, 32) + SourceIndex(0)
4 >Emitted(15, 28) Source(1, 13) + SourceIndex(0)
5 >Emitted(15, 37) Source(1, 21) + SourceIndex(0)
6 >Emitted(15, 39) Source(1, 13) + SourceIndex(0)
7 >Emitted(15, 65) Source(1, 21) + SourceIndex(0)
8 >Emitted(15, 67) Source(1, 23) + SourceIndex(0)
9 >Emitted(15, 76) Source(1, 31) + SourceIndex(0)
10>Emitted(15, 78) Source(1, 23) + SourceIndex(0)
11>Emitted(15, 104) Source(1, 31) + SourceIndex(0)
---
>>> a;
1 >^^^^^^^^
@@ -106,9 +107,9 @@ sourceFile:ES5For-of35.ts
>
2 > a
3 > ;
1 >Emitted(15, 9) Source(2, 5) + SourceIndex(0)
2 >Emitted(15, 10) Source(2, 6) + SourceIndex(0)
3 >Emitted(15, 11) Source(2, 7) + SourceIndex(0)
1 >Emitted(16, 9) Source(2, 5) + SourceIndex(0)
2 >Emitted(16, 10) Source(2, 6) + SourceIndex(0)
3 >Emitted(16, 11) Source(2, 7) + SourceIndex(0)
---
>>> b;
1->^^^^^^^^
@@ -118,15 +119,15 @@ sourceFile:ES5For-of35.ts
>
2 > b
3 > ;
1->Emitted(16, 9) Source(3, 5) + SourceIndex(0)
2 >Emitted(16, 10) Source(3, 6) + SourceIndex(0)
3 >Emitted(16, 11) Source(3, 7) + SourceIndex(0)
1->Emitted(17, 9) Source(3, 5) + SourceIndex(0)
2 >Emitted(17, 10) Source(3, 6) + SourceIndex(0)
3 >Emitted(17, 11) Source(3, 7) + SourceIndex(0)
---
>>> }
1 >^^^^^
1 >
>}
1 >Emitted(17, 6) Source(4, 2) + SourceIndex(0)
1 >Emitted(18, 6) Source(4, 2) + SourceIndex(0)
---
>>>}
>>>catch (e_1_1) { e_1 = { error: e_1_1 }; }

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