mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into codefix_add_missing_new_operator
This commit is contained in:
@@ -32,8 +32,10 @@ What shortcomings exist with current approaches?
|
||||
## Checklist
|
||||
|
||||
My suggestion meets these guidelines:
|
||||
* [ ] This wouldn't be a breaking change in existing TypeScript / JavaScript code
|
||||
|
||||
* [ ] This wouldn't be a breaking change in existing TypeScript/JavaScript code
|
||||
* [ ] This wouldn't change the runtime behavior of existing JavaScript code
|
||||
* [ ] This could be implemented without emitting different JS based on the types of the expressions
|
||||
* [ ] This isn't a runtime feature (e.g. new expression-level syntax)
|
||||
* [ ] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
|
||||
* [ ] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).
|
||||
|
||||
|
||||
+3
-3
@@ -137,10 +137,10 @@ You can specify which browser to use for debugging. Currently Chrome and IE are
|
||||
jake runtests-browser tests=2dArrays browser=chrome
|
||||
```
|
||||
|
||||
You can debug with VS Code or Node instead with `jake runtests debug=true`:
|
||||
You can debug with VS Code or Node instead with `jake runtests inspect=true`:
|
||||
|
||||
```Shell
|
||||
jake runtests tests=2dArrays debug=true
|
||||
jake runtests tests=2dArrays inspect=true
|
||||
```
|
||||
|
||||
## Adding a Test
|
||||
@@ -153,7 +153,7 @@ The supported names and values are the same as those supported in the compiler i
|
||||
They are useful for tests relating to modules.
|
||||
See below for examples.
|
||||
|
||||
**Note** that if you have a test corresponding to a specific spec compliance item, you can place it in `tests\cases\conformance` in an appropriately-named subfolder.
|
||||
**Note** that if you have a test corresponding to a specific spec compliance item, you can place it in `tests\cases\conformance` in an appropriately-named subfolder.
|
||||
**Note** that filenames here must be distinct from all other compiler testcase names, so you may have to work a bit to find a unique name if it's something common.
|
||||
|
||||
### Tests for multiple files
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ const exec = require("./scripts/build/exec");
|
||||
const browserify = require("./scripts/build/browserify");
|
||||
const prepend = require("./scripts/build/prepend");
|
||||
const { removeSourceMaps } = require("./scripts/build/sourcemaps");
|
||||
const { CancellationTokenSource, CancelError, delay, Semaphore } = require("prex");
|
||||
const { CancellationTokenSource, CancelError, delay, Semaphore } = require("prex");
|
||||
const { libraryTargets, generateLibs } = require("./scripts/build/lib");
|
||||
const { runConsoleTests, cleanTestDirs, writeTestConfigFile, refBaseline, localBaseline, refRwcBaseline, localRwcBaseline } = require("./scripts/build/tests");
|
||||
|
||||
|
||||
+2
-3
@@ -147,14 +147,14 @@ task(TaskNames.local, [
|
||||
task("default", [TaskNames.local]);
|
||||
|
||||
const RunTestsPrereqs = [TaskNames.lib, Paths.servicesDefinitionFile, Paths.typescriptDefinitionFile, Paths.tsserverLibraryDefinitionFile];
|
||||
desc("Runs all the tests in parallel using the built run.js file. Optional arguments are: t[ests]=category1|category2|... d[ebug]=true.");
|
||||
desc("Runs all the tests in parallel using the built run.js file. Optional arguments are: t[ests]=category1|category2|... i[nspect]=true.");
|
||||
task(TaskNames.runtestsParallel, RunTestsPrereqs, function () {
|
||||
tsbuild([ConfigFileFor.runjs], true, () => {
|
||||
runConsoleTests("min", /*parallel*/ true);
|
||||
});
|
||||
}, { async: true });
|
||||
|
||||
desc("Runs all the tests in parallel using the built run.js file. Optional arguments are: t[ests]=category1|category2|... d[ebug]=true.");
|
||||
desc("Runs all the tests in parallel using the built run.js file. Optional arguments are: t[ests]=category1|category2|... i[nspect]=true.");
|
||||
task(TaskNames.runtests, RunTestsPrereqs, function () {
|
||||
tsbuild([ConfigFileFor.runjs], true, () => {
|
||||
runConsoleTests('mocha-fivemat-progress-reporter', /*runInParallel*/ false);
|
||||
@@ -520,7 +520,6 @@ function runConsoleTests(defaultReporter, runInParallel) {
|
||||
}
|
||||
|
||||
let testTimeout = process.env.timeout || defaultTestTimeout;
|
||||
const debug = process.env.debug || process.env["debug-brk"] || process.env.d;
|
||||
const inspect = process.env.inspect || process.env["inspect-brk"] || process.env.i;
|
||||
const runners = process.env.runners || process.env.runner || process.env.ru;
|
||||
const tests = process.env.test || process.env.tests || process.env.t;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// @ts-check
|
||||
const path = require("path");
|
||||
const child_process = require("child_process");
|
||||
const fs = require("fs");
|
||||
const tsc = require("gulp-typescript");
|
||||
const Vinyl = require("vinyl");
|
||||
const { Duplex, Readable } = require("stream");
|
||||
@@ -42,7 +43,10 @@ function createProject(tsConfigFileName, settings, options) {
|
||||
getVinyl(path) { return inputs.get(path); },
|
||||
getSourceFile(fileName) { return sourceFiles.get(fileName); },
|
||||
createSourceFile(fileName, text, languageVersion) {
|
||||
if (text === undefined) throw new Error("File not cached.");
|
||||
if (text === undefined) {
|
||||
text = fs.readFileSync(fileName, "utf8");
|
||||
}
|
||||
|
||||
/** @type {protocol.SourceFile} */
|
||||
let file;
|
||||
if (options.parse) {
|
||||
|
||||
@@ -2418,7 +2418,7 @@ namespace ts {
|
||||
const flags = exportAssignmentIsAlias(node)
|
||||
? SymbolFlags.Alias // An export= with an EntityNameExpression or a ClassExpression exports all meanings of that identifier or class
|
||||
: SymbolFlags.Property | SymbolFlags.ExportValue | SymbolFlags.ValueModule;
|
||||
declareSymbol(file.symbol.exports!, file.symbol, node, flags, SymbolFlags.None);
|
||||
declareSymbol(file.symbol.exports!, file.symbol, node, flags | SymbolFlags.Assignment, SymbolFlags.None);
|
||||
}
|
||||
|
||||
function bindThisPropertyAssignment(node: BinaryExpression | PropertyAccessExpression) {
|
||||
@@ -2921,7 +2921,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isExportsOrModuleExportsOrAlias(sourceFile: SourceFile, node: Expression): boolean {
|
||||
return isExportsIdentifier(node) ||
|
||||
isModuleExportsPropertyAccessExpression(node) ||
|
||||
@@ -3702,6 +3701,10 @@ namespace ts {
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.BigIntLiteral:
|
||||
transformFlags |= TransformFlags.AssertESNext;
|
||||
break;
|
||||
|
||||
case SyntaxKind.ForOfStatement:
|
||||
// This node is either ES2015 syntax or ES2017 syntax (if it is a for-await-of).
|
||||
if ((<ForOfStatement>node).awaitModifier) {
|
||||
@@ -3718,6 +3721,7 @@ namespace ts {
|
||||
|
||||
case SyntaxKind.AnyKeyword:
|
||||
case SyntaxKind.NumberKeyword:
|
||||
case SyntaxKind.BigIntKeyword:
|
||||
case SyntaxKind.NeverKeyword:
|
||||
case SyntaxKind.ObjectKeyword:
|
||||
case SyntaxKind.StringKeyword:
|
||||
@@ -3893,7 +3897,6 @@ namespace ts {
|
||||
* For performance reasons, `computeTransformFlagsForNode` uses local constant values rather
|
||||
* than calling this function.
|
||||
*/
|
||||
/* @internal */
|
||||
export function getTransformFlagsSubtreeExclusions(kind: SyntaxKind) {
|
||||
if (kind >= SyntaxKind.FirstTypeNode && kind <= SyntaxKind.LastTypeNode) {
|
||||
return TransformFlags.TypeExcludes;
|
||||
@@ -3926,6 +3929,7 @@ namespace ts {
|
||||
return TransformFlags.MethodOrAccessorExcludes;
|
||||
case SyntaxKind.AnyKeyword:
|
||||
case SyntaxKind.NumberKeyword:
|
||||
case SyntaxKind.BigIntKeyword:
|
||||
case SyntaxKind.NeverKeyword:
|
||||
case SyntaxKind.StringKeyword:
|
||||
case SyntaxKind.ObjectKeyword:
|
||||
|
||||
+38
-5
@@ -201,12 +201,13 @@ namespace ts {
|
||||
}
|
||||
|
||||
Debug.assert(!!state.currentAffectedFilesExportedModulesMap);
|
||||
const seenFileAndExportsOfFile = createMap<true>();
|
||||
// Go through exported modules from cache first
|
||||
// If exported modules has path, all files referencing file exported from are affected
|
||||
if (forEachEntry(state.currentAffectedFilesExportedModulesMap!, (exportedModules, exportedFromPath) =>
|
||||
exportedModules &&
|
||||
exportedModules.has(affectedFile.path) &&
|
||||
removeSemanticDiagnosticsOfFilesReferencingPath(state, exportedFromPath as Path)
|
||||
removeSemanticDiagnosticsOfFilesReferencingPath(state, exportedFromPath as Path, seenFileAndExportsOfFile)
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
@@ -215,7 +216,7 @@ namespace ts {
|
||||
forEachEntry(state.exportedModulesMap, (exportedModules, exportedFromPath) =>
|
||||
!state.currentAffectedFilesExportedModulesMap!.has(exportedFromPath) && // If we already iterated this through cache, ignore it
|
||||
exportedModules.has(affectedFile.path) &&
|
||||
removeSemanticDiagnosticsOfFilesReferencingPath(state, exportedFromPath as Path)
|
||||
removeSemanticDiagnosticsOfFilesReferencingPath(state, exportedFromPath as Path, seenFileAndExportsOfFile)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -223,9 +224,41 @@ namespace ts {
|
||||
* removes the semantic diagnostics of files referencing referencedPath and
|
||||
* returns true if there are no more semantic diagnostics from old state
|
||||
*/
|
||||
function removeSemanticDiagnosticsOfFilesReferencingPath(state: BuilderProgramState, referencedPath: Path) {
|
||||
function removeSemanticDiagnosticsOfFilesReferencingPath(state: BuilderProgramState, referencedPath: Path, seenFileAndExportsOfFile: Map<true>) {
|
||||
return forEachEntry(state.referencedMap!, (referencesInFile, filePath) =>
|
||||
referencesInFile.has(referencedPath) && removeSemanticDiagnosticsOf(state, filePath as Path)
|
||||
referencesInFile.has(referencedPath) && removeSemanticDiagnosticsOfFileAndExportsOfFile(state, filePath as Path, seenFileAndExportsOfFile)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes semantic diagnostics of file and anything that exports this file
|
||||
*/
|
||||
function removeSemanticDiagnosticsOfFileAndExportsOfFile(state: BuilderProgramState, filePath: Path, seenFileAndExportsOfFile: Map<true>): boolean {
|
||||
if (!addToSeen(seenFileAndExportsOfFile, filePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (removeSemanticDiagnosticsOf(state, filePath)) {
|
||||
// If there are no more diagnostics from old cache, done
|
||||
return true;
|
||||
}
|
||||
|
||||
Debug.assert(!!state.currentAffectedFilesExportedModulesMap);
|
||||
// Go through exported modules from cache first
|
||||
// If exported modules has path, all files referencing file exported from are affected
|
||||
if (forEachEntry(state.currentAffectedFilesExportedModulesMap!, (exportedModules, exportedFromPath) =>
|
||||
exportedModules &&
|
||||
exportedModules.has(filePath) &&
|
||||
removeSemanticDiagnosticsOfFileAndExportsOfFile(state, exportedFromPath as Path, seenFileAndExportsOfFile)
|
||||
)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If exported from path is not from cache and exported modules has path, all files referencing file exported from are affected
|
||||
return !!forEachEntry(state.exportedModulesMap!, (exportedModules, exportedFromPath) =>
|
||||
!state.currentAffectedFilesExportedModulesMap!.has(exportedFromPath) && // If we already iterated this through cache, ignore it
|
||||
exportedModules.has(filePath) &&
|
||||
removeSemanticDiagnosticsOfFileAndExportsOfFile(state, exportedFromPath as Path, seenFileAndExportsOfFile)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -417,7 +450,7 @@ namespace ts {
|
||||
assertSourceFileOkWithoutNextAffectedCall(state, targetSourceFile);
|
||||
if (!targetSourceFile) {
|
||||
// Emit and report any errors we ran into.
|
||||
let sourceMaps: SourceMapData[] = [];
|
||||
let sourceMaps: SourceMapEmitResult[] = [];
|
||||
let emitSkipped = false;
|
||||
let diagnostics: Diagnostic[] | undefined;
|
||||
let emittedFiles: string[] = [];
|
||||
|
||||
+487
-255
File diff suppressed because it is too large
Load Diff
@@ -44,7 +44,8 @@ namespace ts {
|
||||
["esnext.array", "lib.esnext.array.d.ts"],
|
||||
["esnext.symbol", "lib.esnext.symbol.d.ts"],
|
||||
["esnext.asynciterable", "lib.esnext.asynciterable.d.ts"],
|
||||
["esnext.intl", "lib.esnext.intl.d.ts"]
|
||||
["esnext.intl", "lib.esnext.intl.d.ts"],
|
||||
["esnext.bigint", "lib.esnext.bigint.d.ts"]
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -104,6 +105,13 @@ namespace ts {
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Print_names_of_generated_files_part_of_the_compilation
|
||||
},
|
||||
{
|
||||
name: "pretty",
|
||||
type: "boolean",
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Stylize_errors_and_messages_using_color_and_context_experimental
|
||||
},
|
||||
|
||||
{
|
||||
name: "traceResolution",
|
||||
@@ -158,11 +166,11 @@ namespace ts {
|
||||
description: Diagnostics.Build_one_or_more_projects_and_their_dependencies_if_out_of_date
|
||||
},
|
||||
{
|
||||
name: "pretty",
|
||||
name: "showConfig",
|
||||
type: "boolean",
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Stylize_errors_and_messages_using_color_and_context_experimental
|
||||
isCommandLineOnly: true,
|
||||
description: Diagnostics.Print_the_final_configuration_instead_of_building
|
||||
},
|
||||
|
||||
// Basic
|
||||
@@ -576,6 +584,12 @@ namespace ts {
|
||||
category: Diagnostics.Experimental_Options,
|
||||
description: Diagnostics.Enables_experimental_support_for_emitting_type_metadata_for_decorators
|
||||
},
|
||||
{
|
||||
name: "experimentalBigInt",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Experimental_Options,
|
||||
description: Diagnostics.Enables_experimental_support_for_ESNext_BigInt_literals
|
||||
},
|
||||
|
||||
// Advanced
|
||||
{
|
||||
@@ -763,7 +777,7 @@ namespace ts {
|
||||
{
|
||||
name: "maxNodeModuleJsDepth",
|
||||
type: "number",
|
||||
// TODO: GH#27108 affectsModuleResolution: true,
|
||||
affectsModuleResolution: true,
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.The_maximum_dependency_depth_to_search_under_node_modules_and_load_JavaScript_files
|
||||
},
|
||||
@@ -1146,7 +1160,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function printHelp(optionsList: CommandLineOption[], syntaxPrefix = "") {
|
||||
export function printHelp(optionsList: ReadonlyArray<CommandLineOption>, syntaxPrefix = "") {
|
||||
const output: string[] = [];
|
||||
|
||||
// We want to align our "syntax" and "examples" commands to a certain margin.
|
||||
@@ -1653,6 +1667,137 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an uncommented, complete tsconfig for use with "--showConfig"
|
||||
* @param configParseResult options to be generated into tsconfig.json
|
||||
* @param configFileName name of the parsed config file - output paths will be generated relative to this
|
||||
* @param host provides current directory and case sensitivity services
|
||||
*/
|
||||
/** @internal */
|
||||
export function convertToTSConfig(configParseResult: ParsedCommandLine, configFileName: string, host: { getCurrentDirectory(): string, useCaseSensitiveFileNames: boolean }): object {
|
||||
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
|
||||
const files = map(
|
||||
filter(
|
||||
configParseResult.fileNames,
|
||||
!configParseResult.configFileSpecs ? _ => false : matchesSpecs(
|
||||
configFileName,
|
||||
configParseResult.configFileSpecs.validatedIncludeSpecs,
|
||||
configParseResult.configFileSpecs.validatedExcludeSpecs
|
||||
)
|
||||
),
|
||||
f => getRelativePathFromFile(getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), f, getCanonicalFileName)
|
||||
);
|
||||
const optionMap = serializeCompilerOptions(configParseResult.options, { configFilePath: getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), useCaseSensitiveFileNames: host.useCaseSensitiveFileNames });
|
||||
const config = {
|
||||
compilerOptions: {
|
||||
...arrayFrom(optionMap.entries()).reduce((prev, cur) => ({ ...prev, [cur[0]]: cur[1] }), {}),
|
||||
showConfig: undefined,
|
||||
configFile: undefined,
|
||||
configFilePath: undefined,
|
||||
help: undefined,
|
||||
init: undefined,
|
||||
listFiles: undefined,
|
||||
listEmittedFiles: undefined,
|
||||
project: undefined,
|
||||
},
|
||||
references: map(configParseResult.projectReferences, r => ({ ...r, path: 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
|
||||
};
|
||||
return config;
|
||||
}
|
||||
|
||||
function filterSameAsDefaultInclude(specs: ReadonlyArray<string> | undefined) {
|
||||
if (!length(specs)) return undefined;
|
||||
if (length(specs) !== 1) return specs;
|
||||
if (specs![0] === "**/*") return undefined;
|
||||
return specs;
|
||||
}
|
||||
|
||||
function matchesSpecs(path: string, includeSpecs: ReadonlyArray<string> | undefined, excludeSpecs: ReadonlyArray<string> | undefined): (path: string) => boolean {
|
||||
if (!includeSpecs) return _ => false;
|
||||
const patterns = getFileMatcherPatterns(path, excludeSpecs, includeSpecs, sys.useCaseSensitiveFileNames, sys.getCurrentDirectory());
|
||||
const excludeRe = patterns.excludePattern && getRegexFromPattern(patterns.excludePattern, sys.useCaseSensitiveFileNames);
|
||||
const includeRe = patterns.includeFilePattern && getRegexFromPattern(patterns.includeFilePattern, sys.useCaseSensitiveFileNames);
|
||||
if (includeRe) {
|
||||
if (excludeRe) {
|
||||
return path => includeRe.test(path) && !excludeRe.test(path);
|
||||
}
|
||||
return path => includeRe.test(path);
|
||||
}
|
||||
if (excludeRe) {
|
||||
return path => !excludeRe.test(path);
|
||||
}
|
||||
return _ => false;
|
||||
}
|
||||
|
||||
function getCustomTypeMapOfCommandLineOption(optionDefinition: CommandLineOption): Map<string | number> | undefined {
|
||||
if (optionDefinition.type === "string" || optionDefinition.type === "number" || optionDefinition.type === "boolean") {
|
||||
// this is of a type CommandLineOptionOfPrimitiveType
|
||||
return undefined;
|
||||
}
|
||||
else if (optionDefinition.type === "list") {
|
||||
return getCustomTypeMapOfCommandLineOption(optionDefinition.element);
|
||||
}
|
||||
else {
|
||||
return (<CommandLineOptionOfCustomType>optionDefinition).type;
|
||||
}
|
||||
}
|
||||
|
||||
function getNameOfCompilerOptionValue(value: CompilerOptionsValue, customTypeMap: Map<string | number>): string | undefined {
|
||||
// There is a typeMap associated with this command-line option so use it to map value back to its name
|
||||
return forEachEntry(customTypeMap, (mapValue, key) => {
|
||||
if (mapValue === value) {
|
||||
return key;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function serializeCompilerOptions(options: CompilerOptions, pathOptions?: { configFilePath: string, useCaseSensitiveFileNames: boolean }): Map<CompilerOptionsValue> {
|
||||
const result = createMap<CompilerOptionsValue>();
|
||||
const optionsNameMap = getOptionNameMap().optionNameMap;
|
||||
const getCanonicalFileName = pathOptions && createGetCanonicalFileName(pathOptions.useCaseSensitiveFileNames);
|
||||
|
||||
for (const name in options) {
|
||||
if (hasProperty(options, name)) {
|
||||
// tsconfig only options cannot be specified via command line,
|
||||
// so we can assume that only types that can appear here string | number | boolean
|
||||
if (optionsNameMap.has(name) && optionsNameMap.get(name)!.category === Diagnostics.Command_line_Options) {
|
||||
continue;
|
||||
}
|
||||
const value = <CompilerOptionsValue>options[name];
|
||||
const optionDefinition = optionsNameMap.get(name.toLowerCase());
|
||||
if (optionDefinition) {
|
||||
const customTypeMap = getCustomTypeMapOfCommandLineOption(optionDefinition);
|
||||
if (!customTypeMap) {
|
||||
// There is no map associated with this compiler option then use the value as-is
|
||||
// This is the case if the value is expect to be string, number, boolean or list of string
|
||||
if (pathOptions && optionDefinition.isFilePath) {
|
||||
result.set(name, getRelativePathFromFile(pathOptions.configFilePath, getNormalizedAbsolutePath(value as string, getDirectoryPath(pathOptions.configFilePath)), getCanonicalFileName!));
|
||||
}
|
||||
else {
|
||||
result.set(name, value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (optionDefinition.type === "list") {
|
||||
result.set(name, (value as ReadonlyArray<string | number>).map(element => getNameOfCompilerOptionValue(element, customTypeMap)!)); // TODO: GH#18217
|
||||
}
|
||||
else {
|
||||
// There is a typeMap associated with this command-line option so use it to map value back to its name
|
||||
result.set(name, getNameOfCompilerOptionValue(value, customTypeMap));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate tsconfig configuration when running command line "--init"
|
||||
* @param options commandlineOptions to be generated into tsconfig.json
|
||||
@@ -1664,63 +1809,6 @@ namespace ts {
|
||||
const compilerOptionsMap = serializeCompilerOptions(compilerOptions);
|
||||
return writeConfigurations();
|
||||
|
||||
function getCustomTypeMapOfCommandLineOption(optionDefinition: CommandLineOption): Map<string | number> | undefined {
|
||||
if (optionDefinition.type === "string" || optionDefinition.type === "number" || optionDefinition.type === "boolean") {
|
||||
// this is of a type CommandLineOptionOfPrimitiveType
|
||||
return undefined;
|
||||
}
|
||||
else if (optionDefinition.type === "list") {
|
||||
return getCustomTypeMapOfCommandLineOption(optionDefinition.element);
|
||||
}
|
||||
else {
|
||||
return (<CommandLineOptionOfCustomType>optionDefinition).type;
|
||||
}
|
||||
}
|
||||
|
||||
function getNameOfCompilerOptionValue(value: CompilerOptionsValue, customTypeMap: Map<string | number>): string | undefined {
|
||||
// There is a typeMap associated with this command-line option so use it to map value back to its name
|
||||
return forEachEntry(customTypeMap, (mapValue, key) => {
|
||||
if (mapValue === value) {
|
||||
return key;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function serializeCompilerOptions(options: CompilerOptions): Map<CompilerOptionsValue> {
|
||||
const result = createMap<CompilerOptionsValue>();
|
||||
const optionsNameMap = getOptionNameMap().optionNameMap;
|
||||
|
||||
for (const name in options) {
|
||||
if (hasProperty(options, name)) {
|
||||
// tsconfig only options cannot be specified via command line,
|
||||
// so we can assume that only types that can appear here string | number | boolean
|
||||
if (optionsNameMap.has(name) && optionsNameMap.get(name)!.category === Diagnostics.Command_line_Options) {
|
||||
continue;
|
||||
}
|
||||
const value = <CompilerOptionsValue>options[name];
|
||||
const optionDefinition = optionsNameMap.get(name.toLowerCase());
|
||||
if (optionDefinition) {
|
||||
const customTypeMap = getCustomTypeMapOfCommandLineOption(optionDefinition);
|
||||
if (!customTypeMap) {
|
||||
// There is no map associated with this compiler option then use the value as-is
|
||||
// This is the case if the value is expect to be string, number, boolean or list of string
|
||||
result.set(name, value);
|
||||
}
|
||||
else {
|
||||
if (optionDefinition.type === "list") {
|
||||
result.set(name, (value as ReadonlyArray<string | number>).map(element => getNameOfCompilerOptionValue(element, customTypeMap)!)); // TODO: GH#18217
|
||||
}
|
||||
else {
|
||||
// There is a typeMap associated with this command-line option so use it to map value back to its name
|
||||
result.set(name, getNameOfCompilerOptionValue(value, customTypeMap));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getDefaultValueForOption(option: CommandLineOption) {
|
||||
switch (option.type) {
|
||||
case "number":
|
||||
|
||||
@@ -1,431 +0,0 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export interface CommentWriter {
|
||||
reset(): void;
|
||||
setSourceFile(sourceFile: SourceFile): void;
|
||||
setWriter(writer: EmitTextWriter | undefined): void;
|
||||
emitNodeWithComments(hint: EmitHint, node: Node | undefined, emitCallback: (hint: EmitHint, node: Node) => void): void;
|
||||
emitBodyWithDetachedComments(node: Node, detachedRange: TextRange, emitCallback: (node: Node) => void): void;
|
||||
emitTrailingCommentsOfPosition(pos: number, prefixSpace?: boolean): void;
|
||||
emitLeadingCommentsOfPosition(pos: number): void;
|
||||
}
|
||||
|
||||
export function createCommentWriter(printerOptions: PrinterOptions, emitPos: ((pos: number) => void) | undefined): CommentWriter {
|
||||
const extendedDiagnostics = printerOptions.extendedDiagnostics;
|
||||
const newLine = getNewLineCharacter(printerOptions);
|
||||
let writer: EmitTextWriter;
|
||||
let containerPos = -1;
|
||||
let containerEnd = -1;
|
||||
let declarationListContainerEnd = -1;
|
||||
let currentSourceFile: SourceFile;
|
||||
let currentText: string;
|
||||
let currentLineMap: ReadonlyArray<number>;
|
||||
let detachedCommentsInfo: { nodePos: number, detachedCommentEndPos: number}[] | undefined;
|
||||
let hasWrittenComment = false;
|
||||
let disabled: boolean = !!printerOptions.removeComments;
|
||||
|
||||
return {
|
||||
reset,
|
||||
setWriter,
|
||||
setSourceFile,
|
||||
emitNodeWithComments,
|
||||
emitBodyWithDetachedComments,
|
||||
emitTrailingCommentsOfPosition,
|
||||
emitLeadingCommentsOfPosition,
|
||||
};
|
||||
|
||||
function emitNodeWithComments(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
|
||||
if (disabled) {
|
||||
emitCallback(hint, node);
|
||||
return;
|
||||
}
|
||||
|
||||
if (node) {
|
||||
hasWrittenComment = false;
|
||||
|
||||
const emitNode = node.emitNode;
|
||||
const emitFlags = emitNode && emitNode.flags || 0;
|
||||
const { pos, end } = emitNode && emitNode.commentRange || node;
|
||||
if ((pos < 0 && end < 0) || (pos === end)) {
|
||||
// Both pos and end are synthesized, so just emit the node without comments.
|
||||
emitNodeWithSynthesizedComments(hint, node, emitNode, emitFlags, emitCallback);
|
||||
}
|
||||
else {
|
||||
if (extendedDiagnostics) {
|
||||
performance.mark("preEmitNodeWithComment");
|
||||
}
|
||||
|
||||
const isEmittedNode = node.kind !== SyntaxKind.NotEmittedStatement;
|
||||
// We have to explicitly check that the node is JsxText because if the compilerOptions.jsx is "preserve" we will not do any transformation.
|
||||
// It is expensive to walk entire tree just to set one kind of node to have no comments.
|
||||
const skipLeadingComments = pos < 0 || (emitFlags & EmitFlags.NoLeadingComments) !== 0 || node.kind === SyntaxKind.JsxText;
|
||||
const skipTrailingComments = end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0 || node.kind === SyntaxKind.JsxText;
|
||||
|
||||
// Emit leading comments if the position is not synthesized and the node
|
||||
// has not opted out from emitting leading comments.
|
||||
if (!skipLeadingComments) {
|
||||
emitLeadingComments(pos, isEmittedNode);
|
||||
}
|
||||
|
||||
// Save current container state on the stack.
|
||||
const savedContainerPos = containerPos;
|
||||
const savedContainerEnd = containerEnd;
|
||||
const savedDeclarationListContainerEnd = declarationListContainerEnd;
|
||||
|
||||
if (!skipLeadingComments || (pos >= 0 && (emitFlags & EmitFlags.NoLeadingComments) !== 0)) {
|
||||
// Advance the container position of comments get emitted or if they've been disabled explicitly using NoLeadingComments.
|
||||
containerPos = pos;
|
||||
}
|
||||
|
||||
if (!skipTrailingComments || (end >= 0 && (emitFlags & EmitFlags.NoTrailingComments) !== 0)) {
|
||||
// As above.
|
||||
containerEnd = end;
|
||||
|
||||
// To avoid invalid comment emit in a down-level binding pattern, we
|
||||
// keep track of the last declaration list container's end
|
||||
if (node.kind === SyntaxKind.VariableDeclarationList) {
|
||||
declarationListContainerEnd = end;
|
||||
}
|
||||
}
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.measure("commentTime", "preEmitNodeWithComment");
|
||||
}
|
||||
|
||||
emitNodeWithSynthesizedComments(hint, node, emitNode, emitFlags, emitCallback);
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.mark("postEmitNodeWithComment");
|
||||
}
|
||||
|
||||
// Restore previous container state.
|
||||
containerPos = savedContainerPos;
|
||||
containerEnd = savedContainerEnd;
|
||||
declarationListContainerEnd = savedDeclarationListContainerEnd;
|
||||
|
||||
// Emit trailing comments if the position is not synthesized and the node
|
||||
// has not opted out from emitting leading comments and is an emitted node.
|
||||
if (!skipTrailingComments && isEmittedNode) {
|
||||
emitTrailingComments(end);
|
||||
}
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.measure("commentTime", "postEmitNodeWithComment");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function emitNodeWithSynthesizedComments(hint: EmitHint, node: Node, emitNode: EmitNode | undefined, emitFlags: EmitFlags, emitCallback: (hint: EmitHint, node: Node) => void) {
|
||||
const leadingComments = emitNode && emitNode.leadingComments;
|
||||
if (some(leadingComments)) {
|
||||
if (extendedDiagnostics) {
|
||||
performance.mark("preEmitNodeWithSynthesizedComments");
|
||||
}
|
||||
|
||||
forEach(leadingComments, emitLeadingSynthesizedComment);
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.measure("commentTime", "preEmitNodeWithSynthesizedComments");
|
||||
}
|
||||
}
|
||||
|
||||
emitNodeWithNestedComments(hint, node, emitFlags, emitCallback);
|
||||
|
||||
const trailingComments = emitNode && emitNode.trailingComments;
|
||||
if (some(trailingComments)) {
|
||||
if (extendedDiagnostics) {
|
||||
performance.mark("postEmitNodeWithSynthesizedComments");
|
||||
}
|
||||
|
||||
forEach(trailingComments, emitTrailingSynthesizedComment);
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.measure("commentTime", "postEmitNodeWithSynthesizedComments");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function emitLeadingSynthesizedComment(comment: SynthesizedComment) {
|
||||
if (comment.kind === SyntaxKind.SingleLineCommentTrivia) {
|
||||
writer.writeLine();
|
||||
}
|
||||
writeSynthesizedComment(comment);
|
||||
if (comment.hasTrailingNewLine || comment.kind === SyntaxKind.SingleLineCommentTrivia) {
|
||||
writer.writeLine();
|
||||
}
|
||||
else {
|
||||
writer.write(" ");
|
||||
}
|
||||
}
|
||||
|
||||
function emitTrailingSynthesizedComment(comment: SynthesizedComment) {
|
||||
if (!writer.isAtStartOfLine()) {
|
||||
writer.write(" ");
|
||||
}
|
||||
writeSynthesizedComment(comment);
|
||||
if (comment.hasTrailingNewLine) {
|
||||
writer.writeLine();
|
||||
}
|
||||
}
|
||||
|
||||
function writeSynthesizedComment(comment: SynthesizedComment) {
|
||||
const text = formatSynthesizedComment(comment);
|
||||
const lineMap = comment.kind === SyntaxKind.MultiLineCommentTrivia ? computeLineStarts(text) : undefined;
|
||||
writeCommentRange(text, lineMap!, writer, 0, text.length, newLine);
|
||||
}
|
||||
|
||||
function formatSynthesizedComment(comment: SynthesizedComment) {
|
||||
return comment.kind === SyntaxKind.MultiLineCommentTrivia
|
||||
? `/*${comment.text}*/`
|
||||
: `//${comment.text}`;
|
||||
}
|
||||
|
||||
function emitNodeWithNestedComments(hint: EmitHint, node: Node, emitFlags: EmitFlags, emitCallback: (hint: EmitHint, node: Node) => void) {
|
||||
if (emitFlags & EmitFlags.NoNestedComments) {
|
||||
disabled = true;
|
||||
emitCallback(hint, node);
|
||||
disabled = false;
|
||||
}
|
||||
else {
|
||||
emitCallback(hint, node);
|
||||
}
|
||||
}
|
||||
|
||||
function emitBodyWithDetachedComments(node: Node, detachedRange: TextRange, emitCallback: (node: Node) => void) {
|
||||
if (extendedDiagnostics) {
|
||||
performance.mark("preEmitBodyWithDetachedComments");
|
||||
}
|
||||
|
||||
const { pos, end } = detachedRange;
|
||||
const emitFlags = getEmitFlags(node);
|
||||
const skipLeadingComments = pos < 0 || (emitFlags & EmitFlags.NoLeadingComments) !== 0;
|
||||
const skipTrailingComments = disabled || end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0;
|
||||
|
||||
if (!skipLeadingComments) {
|
||||
emitDetachedCommentsAndUpdateCommentsInfo(detachedRange);
|
||||
}
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.measure("commentTime", "preEmitBodyWithDetachedComments");
|
||||
}
|
||||
|
||||
if (emitFlags & EmitFlags.NoNestedComments && !disabled) {
|
||||
disabled = true;
|
||||
emitCallback(node);
|
||||
disabled = false;
|
||||
}
|
||||
else {
|
||||
emitCallback(node);
|
||||
}
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.mark("beginEmitBodyWithDetachedComments");
|
||||
}
|
||||
|
||||
if (!skipTrailingComments) {
|
||||
emitLeadingComments(detachedRange.end, /*isEmittedNode*/ true);
|
||||
if (hasWrittenComment && !writer.isAtStartOfLine()) {
|
||||
writer.writeLine();
|
||||
}
|
||||
}
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.measure("commentTime", "beginEmitBodyWithDetachedComments");
|
||||
}
|
||||
}
|
||||
|
||||
function emitLeadingComments(pos: number, isEmittedNode: boolean) {
|
||||
hasWrittenComment = false;
|
||||
|
||||
if (isEmittedNode) {
|
||||
forEachLeadingCommentToEmit(pos, emitLeadingComment);
|
||||
}
|
||||
else if (pos === 0) {
|
||||
// If the node will not be emitted in JS, remove all the comments(normal, pinned and ///) associated with the node,
|
||||
// unless it is a triple slash comment at the top of the file.
|
||||
// For Example:
|
||||
// /// <reference-path ...>
|
||||
// declare var x;
|
||||
// /// <reference-path ...>
|
||||
// interface F {}
|
||||
// The first /// will NOT be removed while the second one will be removed even though both node will not be emitted
|
||||
forEachLeadingCommentToEmit(pos, emitTripleSlashLeadingComment);
|
||||
}
|
||||
}
|
||||
|
||||
function emitTripleSlashLeadingComment(commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) {
|
||||
if (isTripleSlashComment(commentPos, commentEnd)) {
|
||||
emitLeadingComment(commentPos, commentEnd, kind, hasTrailingNewLine, rangePos);
|
||||
}
|
||||
}
|
||||
|
||||
function shouldWriteComment(text: string, pos: number) {
|
||||
if (printerOptions.onlyPrintJsDocStyle) {
|
||||
return (isJSDocLikeText(text, pos) || isPinnedComment(text, pos));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function emitLeadingComment(commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) {
|
||||
if (!shouldWriteComment(currentText, commentPos)) return;
|
||||
if (!hasWrittenComment) {
|
||||
emitNewLineBeforeLeadingCommentOfPosition(currentLineMap, writer, rangePos, commentPos);
|
||||
hasWrittenComment = true;
|
||||
}
|
||||
|
||||
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
|
||||
if (emitPos) emitPos(commentPos);
|
||||
writeCommentRange(currentText, currentLineMap, writer, commentPos, commentEnd, newLine);
|
||||
if (emitPos) emitPos(commentEnd);
|
||||
|
||||
if (hasTrailingNewLine) {
|
||||
writer.writeLine();
|
||||
}
|
||||
else if (kind === SyntaxKind.MultiLineCommentTrivia) {
|
||||
writer.write(" ");
|
||||
}
|
||||
}
|
||||
|
||||
function emitLeadingCommentsOfPosition(pos: number) {
|
||||
if (disabled || pos === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
emitLeadingComments(pos, /*isEmittedNode*/ true);
|
||||
}
|
||||
|
||||
function emitTrailingComments(pos: number) {
|
||||
forEachTrailingCommentToEmit(pos, emitTrailingComment);
|
||||
}
|
||||
|
||||
function emitTrailingComment(commentPos: number, commentEnd: number, _kind: SyntaxKind, hasTrailingNewLine: boolean) {
|
||||
if (!shouldWriteComment(currentText, commentPos)) return;
|
||||
// trailing comments are emitted at space/*trailing comment1 */space/*trailing comment2*/
|
||||
if (!writer.isAtStartOfLine()) {
|
||||
writer.write(" ");
|
||||
}
|
||||
|
||||
if (emitPos) emitPos(commentPos);
|
||||
writeCommentRange(currentText, currentLineMap, writer, commentPos, commentEnd, newLine);
|
||||
if (emitPos) emitPos(commentEnd);
|
||||
|
||||
if (hasTrailingNewLine) {
|
||||
writer.writeLine();
|
||||
}
|
||||
}
|
||||
|
||||
function emitTrailingCommentsOfPosition(pos: number, prefixSpace?: boolean) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.mark("beforeEmitTrailingCommentsOfPosition");
|
||||
}
|
||||
|
||||
forEachTrailingCommentToEmit(pos, prefixSpace ? emitTrailingComment : emitTrailingCommentOfPosition);
|
||||
|
||||
if (extendedDiagnostics) {
|
||||
performance.measure("commentTime", "beforeEmitTrailingCommentsOfPosition");
|
||||
}
|
||||
}
|
||||
|
||||
function emitTrailingCommentOfPosition(commentPos: number, commentEnd: number, _kind: SyntaxKind, hasTrailingNewLine: boolean) {
|
||||
// trailing comments of a position are emitted at /*trailing comment1 */space/*trailing comment*/space
|
||||
|
||||
if (emitPos) emitPos(commentPos);
|
||||
writeCommentRange(currentText, currentLineMap, writer, commentPos, commentEnd, newLine);
|
||||
if (emitPos) emitPos(commentEnd);
|
||||
|
||||
if (hasTrailingNewLine) {
|
||||
writer.writeLine();
|
||||
}
|
||||
else {
|
||||
writer.write(" ");
|
||||
}
|
||||
}
|
||||
|
||||
function forEachLeadingCommentToEmit(pos: number, cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) => void) {
|
||||
// Emit the leading comments only if the container's pos doesn't match because the container should take care of emitting these comments
|
||||
if (containerPos === -1 || pos !== containerPos) {
|
||||
if (hasDetachedComments(pos)) {
|
||||
forEachLeadingCommentWithoutDetachedComments(cb);
|
||||
}
|
||||
else {
|
||||
forEachLeadingCommentRange(currentText, pos, cb, /*state*/ pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function forEachTrailingCommentToEmit(end: number, cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean) => void) {
|
||||
// Emit the trailing comments only if the container's end doesn't match because the container should take care of emitting these comments
|
||||
if (containerEnd === -1 || (end !== containerEnd && end !== declarationListContainerEnd)) {
|
||||
forEachTrailingCommentRange(currentText, end, cb);
|
||||
}
|
||||
}
|
||||
|
||||
function reset() {
|
||||
currentSourceFile = undefined!;
|
||||
currentText = undefined!;
|
||||
currentLineMap = undefined!;
|
||||
detachedCommentsInfo = undefined;
|
||||
}
|
||||
|
||||
function setWriter(output: EmitTextWriter): void {
|
||||
writer = output;
|
||||
}
|
||||
|
||||
function setSourceFile(sourceFile: SourceFile) {
|
||||
currentSourceFile = sourceFile;
|
||||
currentText = currentSourceFile.text;
|
||||
currentLineMap = getLineStarts(currentSourceFile);
|
||||
detachedCommentsInfo = undefined;
|
||||
}
|
||||
|
||||
function hasDetachedComments(pos: number) {
|
||||
return detachedCommentsInfo !== undefined && last(detachedCommentsInfo).nodePos === pos;
|
||||
}
|
||||
|
||||
function forEachLeadingCommentWithoutDetachedComments(cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) => void) {
|
||||
// get the leading comments from detachedPos
|
||||
const pos = last(detachedCommentsInfo!).detachedCommentEndPos;
|
||||
if (detachedCommentsInfo!.length - 1) {
|
||||
detachedCommentsInfo!.pop();
|
||||
}
|
||||
else {
|
||||
detachedCommentsInfo = undefined;
|
||||
}
|
||||
|
||||
forEachLeadingCommentRange(currentText, pos, cb, /*state*/ pos);
|
||||
}
|
||||
|
||||
function emitDetachedCommentsAndUpdateCommentsInfo(range: TextRange) {
|
||||
const currentDetachedCommentInfo = emitDetachedComments(currentText, currentLineMap, writer, writeComment, range, newLine, disabled);
|
||||
if (currentDetachedCommentInfo) {
|
||||
if (detachedCommentsInfo) {
|
||||
detachedCommentsInfo.push(currentDetachedCommentInfo);
|
||||
}
|
||||
else {
|
||||
detachedCommentsInfo = [currentDetachedCommentInfo];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeComment(text: string, lineMap: number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) {
|
||||
if (!shouldWriteComment(currentText, commentPos)) return;
|
||||
if (emitPos) emitPos(commentPos);
|
||||
writeCommentRange(text, lineMap, writer, commentPos, commentEnd, newLine);
|
||||
if (emitPos) emitPos(commentEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given comment is a triple-slash
|
||||
*
|
||||
* @return true if the comment is a triple-slash comment else false
|
||||
*/
|
||||
function isTripleSlashComment(commentPos: number, commentEnd: number) {
|
||||
return isRecognizedTripleSlashComment(currentText, commentPos, commentEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
+49
-16
@@ -16,6 +16,10 @@ namespace ts {
|
||||
[index: string]: T;
|
||||
}
|
||||
|
||||
export interface SortedReadonlyArray<T> extends ReadonlyArray<T> {
|
||||
" __sortedArrayBrand": any;
|
||||
}
|
||||
|
||||
export interface SortedArray<T> extends Array<T> {
|
||||
" __sortedArrayBrand": any;
|
||||
}
|
||||
@@ -511,12 +515,27 @@ namespace ts {
|
||||
* @param array The array to map.
|
||||
* @param mapfn The callback used to map the result into one or more values.
|
||||
*/
|
||||
export function flatMap<T, U>(array: ReadonlyArray<T>, mapfn: (x: T, i: number) => U | ReadonlyArray<U> | undefined): U[];
|
||||
export function flatMap<T, U>(array: ReadonlyArray<T> | undefined, mapfn: (x: T, i: number) => U | ReadonlyArray<U> | undefined): U[] | undefined;
|
||||
export function flatMap<T, U>(array: ReadonlyArray<T> | undefined, mapfn: (x: T, i: number) => U | ReadonlyArray<U> | undefined): U[] | undefined {
|
||||
export function flatMap<T, U>(array: ReadonlyArray<T> | undefined, mapfn: (x: T, i: number) => U | ReadonlyArray<U> | undefined): ReadonlyArray<U> {
|
||||
let result: U[] | undefined;
|
||||
if (array) {
|
||||
result = [];
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const v = mapfn(array[i], i);
|
||||
if (v) {
|
||||
if (isArray(v)) {
|
||||
result = addRange(result, v);
|
||||
}
|
||||
else {
|
||||
result = append(result, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result || emptyArray;
|
||||
}
|
||||
|
||||
export function flatMapToMutable<T, U>(array: ReadonlyArray<T> | undefined, mapfn: (x: T, i: number) => U | ReadonlyArray<U> | undefined): U[] {
|
||||
const result: U[] = [];
|
||||
if (array) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const v = mapfn(array[i], i);
|
||||
if (v) {
|
||||
@@ -800,8 +819,8 @@ namespace ts {
|
||||
/**
|
||||
* Deduplicates an array that has already been sorted.
|
||||
*/
|
||||
function deduplicateSorted<T>(array: ReadonlyArray<T>, comparer: EqualityComparer<T> | Comparer<T>): T[] {
|
||||
if (array.length === 0) return [];
|
||||
function deduplicateSorted<T>(array: SortedReadonlyArray<T>, comparer: EqualityComparer<T> | Comparer<T>): SortedReadonlyArray<T> {
|
||||
if (array.length === 0) return emptyArray as any as SortedReadonlyArray<T>;
|
||||
|
||||
let last = array[0];
|
||||
const deduplicated: T[] = [last];
|
||||
@@ -823,7 +842,7 @@ namespace ts {
|
||||
deduplicated.push(last = next);
|
||||
}
|
||||
|
||||
return deduplicated;
|
||||
return deduplicated as any as SortedReadonlyArray<T>;
|
||||
}
|
||||
|
||||
export function insertSorted<T>(array: SortedArray<T>, insert: T, compare: Comparer<T>): void {
|
||||
@@ -838,8 +857,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function sortAndDeduplicate<T>(array: ReadonlyArray<T>, comparer: Comparer<T>, equalityComparer?: EqualityComparer<T>) {
|
||||
return deduplicateSorted(sort(array, comparer), equalityComparer || comparer);
|
||||
export function sortAndDeduplicate<T>(array: ReadonlyArray<string>): SortedReadonlyArray<string>;
|
||||
export function sortAndDeduplicate<T>(array: ReadonlyArray<T>, comparer: Comparer<T>, equalityComparer?: EqualityComparer<T>): SortedReadonlyArray<T>;
|
||||
export function sortAndDeduplicate<T>(array: ReadonlyArray<T>, comparer?: Comparer<T>, equalityComparer?: EqualityComparer<T>): SortedReadonlyArray<T> {
|
||||
return deduplicateSorted(sort(array, comparer), equalityComparer || comparer || compareStringsCaseSensitive as any as Comparer<T>);
|
||||
}
|
||||
|
||||
export function arrayIsEqualTo<T>(array1: ReadonlyArray<T> | undefined, array2: ReadonlyArray<T> | undefined, equalityComparer: (a: T, b: T, index: number) => boolean = equateValues): boolean {
|
||||
@@ -1020,8 +1041,8 @@ namespace ts {
|
||||
/**
|
||||
* Returns a new sorted array.
|
||||
*/
|
||||
export function sort<T>(array: ReadonlyArray<T>, comparer: Comparer<T>): T[] {
|
||||
return array.slice().sort(comparer);
|
||||
export function sort<T>(array: ReadonlyArray<T>, comparer?: Comparer<T>): SortedReadonlyArray<T> {
|
||||
return (array.length === 0 ? array : array.slice().sort(comparer)) as SortedReadonlyArray<T>;
|
||||
}
|
||||
|
||||
export function arrayIterator<T>(array: ReadonlyArray<T>): Iterator<T> {
|
||||
@@ -1040,10 +1061,10 @@ namespace ts {
|
||||
/**
|
||||
* Stable sort of an array. Elements equal to each other maintain their relative position in the array.
|
||||
*/
|
||||
export function stableSort<T>(array: ReadonlyArray<T>, comparer: Comparer<T>) {
|
||||
export function stableSort<T>(array: ReadonlyArray<T>, comparer: Comparer<T>): SortedReadonlyArray<T> {
|
||||
const indices = array.map((_, i) => i);
|
||||
stableSortIndices(array, indices, comparer);
|
||||
return indices.map(i => array[i]);
|
||||
return indices.map(i => array[i]) as SortedArray<T> as SortedReadonlyArray<T>;
|
||||
}
|
||||
|
||||
export function rangeEquals<T>(array1: ReadonlyArray<T>, array2: ReadonlyArray<T>, pos: number, end: number) {
|
||||
@@ -1135,13 +1156,26 @@ namespace ts {
|
||||
* @param offset An offset into `array` at which to start the search.
|
||||
*/
|
||||
export function binarySearch<T, U>(array: ReadonlyArray<T>, value: T, keySelector: (v: T) => U, keyComparer: Comparer<U>, offset?: number): number {
|
||||
if (!array || array.length === 0) {
|
||||
return binarySearchKey(array, keySelector(value), keySelector, keyComparer, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a binary search, finding the index at which an object with `key` occurs in `array`.
|
||||
* If no such index is found, returns the 2's-complement of first index at which
|
||||
* `array[index]` exceeds `key`.
|
||||
* @param array A sorted array whose first element must be no larger than number
|
||||
* @param key The key to be searched for in the array.
|
||||
* @param keySelector A callback used to select the search key from each element of `array`.
|
||||
* @param keyComparer A callback used to compare two keys in a sorted array.
|
||||
* @param offset An offset into `array` at which to start the search.
|
||||
*/
|
||||
export function binarySearchKey<T, U>(array: ReadonlyArray<T>, key: U, keySelector: (v: T) => U, keyComparer: Comparer<U>, offset?: number): number {
|
||||
if (!some(array)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
let low = offset || 0;
|
||||
let high = array.length - 1;
|
||||
const key = keySelector(value);
|
||||
while (low <= high) {
|
||||
const middle = low + ((high - low) >> 1);
|
||||
const midKey = keySelector(array[middle]);
|
||||
@@ -2031,7 +2065,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** Represents a "prefix*suffix" pattern. */
|
||||
/* @internal */
|
||||
export interface Pattern {
|
||||
prefix: string;
|
||||
suffix: string;
|
||||
|
||||
@@ -1007,6 +1007,14 @@
|
||||
"category": "Error",
|
||||
"code": 1349
|
||||
},
|
||||
"Print the final configuration instead of building.": {
|
||||
"category": "Message",
|
||||
"code": 1350
|
||||
},
|
||||
"Experimental support for BigInt is a feature that is subject to change in a future release. Set the 'experimentalBigInt' option to remove this warning.": {
|
||||
"category": "Error",
|
||||
"code": 1351
|
||||
},
|
||||
|
||||
"Duplicate identifier '{0}'.": {
|
||||
"category": "Error",
|
||||
@@ -1232,7 +1240,7 @@
|
||||
"category": "Error",
|
||||
"code": 2355
|
||||
},
|
||||
"An arithmetic operand must be of type 'any', 'number' or an enum type.": {
|
||||
"An arithmetic operand must be of type 'any', 'number', 'bigint' or an enum type.": {
|
||||
"category": "Error",
|
||||
"code": 2356
|
||||
},
|
||||
@@ -1256,11 +1264,11 @@
|
||||
"category": "Error",
|
||||
"code": 2361
|
||||
},
|
||||
"The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.": {
|
||||
"The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.": {
|
||||
"category": "Error",
|
||||
"code": 2362
|
||||
},
|
||||
"The right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.": {
|
||||
"The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.": {
|
||||
"category": "Error",
|
||||
"code": 2363
|
||||
},
|
||||
@@ -2088,15 +2096,15 @@
|
||||
"category": "Error",
|
||||
"code": 2577
|
||||
},
|
||||
"Cannot find name '{0}'. Do you need to install type definitions for node? Try `npm i @types/node`.": {
|
||||
"Cannot find name '{0}'. Do you need to install type definitions for node? Try `npm i @types/node` and then add `node` to the types field in your tsconfig.": {
|
||||
"category": "Error",
|
||||
"code": 2580
|
||||
},
|
||||
"Cannot find name '{0}'. Do you need to install type definitions for jQuery? Try `npm i @types/jquery`.": {
|
||||
"Cannot find name '{0}'. Do you need to install type definitions for jQuery? Try `npm i @types/jquery` and then add `jquery` to the types field in your tsconfig.": {
|
||||
"category": "Error",
|
||||
"code": 2581
|
||||
},
|
||||
"Cannot find name '{0}'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha`.": {
|
||||
"Cannot find name '{0}'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig.": {
|
||||
"category": "Error",
|
||||
"code": 2582
|
||||
},
|
||||
@@ -2489,6 +2497,22 @@
|
||||
"category": "Error",
|
||||
"code": 2734
|
||||
},
|
||||
"Did you mean for '{0}' to be constrained to type 'new (...args: any[]) => {1}'?": {
|
||||
"category": "Error",
|
||||
"code": 2735
|
||||
},
|
||||
"Operator '{0}' cannot be applied to type '{1}'.": {
|
||||
"category": "Error",
|
||||
"code": 2736
|
||||
},
|
||||
"BigInt literals are not available when targetting lower than ESNext.": {
|
||||
"category": "Error",
|
||||
"code": 2737
|
||||
},
|
||||
"An outer value of 'this' is shadowed by this container.": {
|
||||
"category": "Message",
|
||||
"code": 2738
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
@@ -3767,6 +3791,14 @@
|
||||
"category": "Message",
|
||||
"code": 6215
|
||||
},
|
||||
"Found 1 error.": {
|
||||
"category": "Message",
|
||||
"code": 6216
|
||||
},
|
||||
"Found {0} errors.": {
|
||||
"category": "Message",
|
||||
"code": 6217
|
||||
},
|
||||
|
||||
"Projects to reference": {
|
||||
"category": "Message",
|
||||
@@ -3889,6 +3921,10 @@
|
||||
"category": "Error",
|
||||
"code": 6370
|
||||
},
|
||||
"Enables experimental support for ESNext BigInt literals.": {
|
||||
"category": "Message",
|
||||
"code": 6371
|
||||
},
|
||||
|
||||
"The expected type comes from property '{0}' which is declared here on type '{1}'": {
|
||||
"category": "Message",
|
||||
@@ -4041,6 +4077,39 @@
|
||||
"category": "Error",
|
||||
"code": 7042
|
||||
},
|
||||
"Variable '{0}' implicitly has an '{1}' type, but a better type may be inferred from usage.": {
|
||||
"category": "Suggestion",
|
||||
"code": 7043
|
||||
},
|
||||
"Parameter '{0}' implicitly has an '{1}' type, but a better type may be inferred from usage.": {
|
||||
"category": "Suggestion",
|
||||
"code": 7044
|
||||
},
|
||||
"Member '{0}' implicitly has an '{1}' type, but a better type may be inferred from usage.": {
|
||||
"category": "Suggestion",
|
||||
"code": 7045
|
||||
},
|
||||
"Variable '{0}' implicitly has type '{1}' in some locations, but a better type may be inferred from usage.": {
|
||||
"category": "Suggestion",
|
||||
"code": 7046
|
||||
},
|
||||
"Rest parameter '{0}' implicitly has an 'any[]' type, but a better type may be inferred from usage.": {
|
||||
"category": "Suggestion",
|
||||
"code": 7047
|
||||
},
|
||||
"Property '{0}' implicitly has type 'any', but a better type for its get accessor may be inferred from usage.": {
|
||||
"category": "Suggestion",
|
||||
"code": 7048
|
||||
},
|
||||
"Property '{0}' implicitly has type 'any', but a better type for its set accessor may be inferred from usage.": {
|
||||
"category": "Suggestion",
|
||||
"code": 7049
|
||||
},
|
||||
"'{0}' implicitly has an '{1}' return type, but a better type may be inferred from usage.": {
|
||||
"category": "Suggestion",
|
||||
"code": 7050
|
||||
},
|
||||
|
||||
"You cannot rename this element.": {
|
||||
"category": "Error",
|
||||
"code": 8000
|
||||
@@ -4687,12 +4756,20 @@
|
||||
"category": "Message",
|
||||
"code": 95068
|
||||
},
|
||||
"Add missing 'new' operator to call": {
|
||||
"Add 'unknown' conversion for non-overlapping types": {
|
||||
"category": "Message",
|
||||
"code": 95069
|
||||
},
|
||||
"Add missing 'new' operator to all calls": {
|
||||
"Add 'unknown' to all conversions of non-overlapping types": {
|
||||
"category": "Message",
|
||||
"code": 95070
|
||||
},
|
||||
"Add missing 'new' operator to call": {
|
||||
"category": "Message",
|
||||
"code": 95071
|
||||
},
|
||||
"Add missing 'new' operator to all calls": {
|
||||
"category": "Message",
|
||||
"code": 95072
|
||||
}
|
||||
}
|
||||
|
||||
+763
-217
File diff suppressed because it is too large
Load Diff
+13
-4
@@ -68,13 +68,16 @@ namespace ts {
|
||||
/* @internal */ export function createLiteral(value: string | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | Identifier, isSingleQuote: boolean): StringLiteral; // tslint:disable-line unified-signatures
|
||||
/** If a node is passed, creates a string literal whose source text is read from a source node during emit. */
|
||||
export function createLiteral(value: string | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | Identifier): StringLiteral;
|
||||
export function createLiteral(value: number): NumericLiteral;
|
||||
export function createLiteral(value: number | PseudoBigInt): NumericLiteral;
|
||||
export function createLiteral(value: boolean): BooleanLiteral;
|
||||
export function createLiteral(value: string | number | boolean): PrimaryExpression;
|
||||
export function createLiteral(value: string | number | boolean | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | Identifier, isSingleQuote?: boolean): PrimaryExpression {
|
||||
export function createLiteral(value: string | number | PseudoBigInt | boolean): PrimaryExpression;
|
||||
export function createLiteral(value: string | number | PseudoBigInt | boolean | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | Identifier, isSingleQuote?: boolean): PrimaryExpression {
|
||||
if (typeof value === "number") {
|
||||
return createNumericLiteral(value + "");
|
||||
}
|
||||
if (typeof value === "object" && "base10Value" in value) { // PseudoBigInt
|
||||
return createBigIntLiteral(pseudoBigIntToString(value) + "n");
|
||||
}
|
||||
if (typeof value === "boolean") {
|
||||
return value ? createTrue() : createFalse();
|
||||
}
|
||||
@@ -93,6 +96,12 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createBigIntLiteral(value: string): BigIntLiteral {
|
||||
const node = <BigIntLiteral>createSynthesizedNode(SyntaxKind.BigIntLiteral);
|
||||
node.text = value;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createStringLiteral(text: string): StringLiteral {
|
||||
const node = <StringLiteral>createSynthesizedNode(SyntaxKind.StringLiteral);
|
||||
node.text = text;
|
||||
@@ -2216,7 +2225,6 @@ namespace ts {
|
||||
/* @internal */
|
||||
function createJSDocTag<T extends JSDocTag>(kind: T["kind"], tagName: string): T {
|
||||
const node = createSynthesizedNode(kind) as T;
|
||||
node.atToken = createToken(SyntaxKind.AtToken);
|
||||
node.tagName = createIdentifier(tagName);
|
||||
return node;
|
||||
}
|
||||
@@ -3467,6 +3475,7 @@ namespace ts {
|
||||
return cacheIdentifiers;
|
||||
case SyntaxKind.ThisKeyword:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.BigIntLiteral:
|
||||
case SyntaxKind.StringLiteral:
|
||||
return false;
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
|
||||
@@ -730,6 +730,9 @@ namespace ts {
|
||||
function tryLoadModuleUsingOptionalResolutionSettings(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
|
||||
state: ModuleResolutionState): Resolved | undefined {
|
||||
|
||||
const resolved = tryLoadModuleUsingPathsIfEligible(extensions, moduleName, loader, state);
|
||||
if (resolved) return resolved.value;
|
||||
|
||||
if (!isExternalModuleNameRelative(moduleName)) {
|
||||
return tryLoadModuleUsingBaseUrl(extensions, moduleName, loader, state);
|
||||
}
|
||||
@@ -738,6 +741,17 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function tryLoadModuleUsingPathsIfEligible(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState) {
|
||||
const { baseUrl, paths } = state.compilerOptions;
|
||||
if (baseUrl && paths && !pathIsRelative(moduleName)) {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, baseUrl, moduleName);
|
||||
trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName);
|
||||
}
|
||||
return tryLoadModuleUsingPaths(extensions, moduleName, baseUrl, paths, loader, /*onlyRecordFailures*/ false, state);
|
||||
}
|
||||
}
|
||||
|
||||
function tryLoadModuleUsingRootDirs(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
|
||||
state: ModuleResolutionState): Resolved | undefined {
|
||||
|
||||
@@ -816,22 +830,13 @@ namespace ts {
|
||||
}
|
||||
|
||||
function tryLoadModuleUsingBaseUrl(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState): Resolved | undefined {
|
||||
const { baseUrl, paths } = state.compilerOptions;
|
||||
const { baseUrl } = state.compilerOptions;
|
||||
if (!baseUrl) {
|
||||
return undefined;
|
||||
}
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, baseUrl, moduleName);
|
||||
}
|
||||
if (paths) {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName);
|
||||
}
|
||||
const resolved = tryLoadModuleUsingPaths(extensions, moduleName, baseUrl, paths, loader, /*onlyRecordFailures*/ false, state);
|
||||
if (resolved) {
|
||||
return resolved.value;
|
||||
}
|
||||
}
|
||||
const candidate = normalizePath(combinePaths(baseUrl, moduleName));
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Resolving_module_name_0_relative_to_base_url_1_2, moduleName, baseUrl, candidate);
|
||||
|
||||
+52
-61
@@ -2247,8 +2247,7 @@ namespace ts {
|
||||
|
||||
function parseLiteralLikeNode(kind: SyntaxKind): LiteralExpression | LiteralLikeNode {
|
||||
const node = <LiteralExpression>createNode(kind);
|
||||
const text = scanner.getTokenValue();
|
||||
node.text = text;
|
||||
node.text = scanner.getTokenValue();
|
||||
|
||||
if (scanner.hasExtendedUnicodeEscape()) {
|
||||
node.hasExtendedUnicodeEscape = true;
|
||||
@@ -2892,8 +2891,9 @@ namespace ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function nextTokenIsNumericLiteral() {
|
||||
return nextToken() === SyntaxKind.NumericLiteral;
|
||||
function nextTokenIsNumericOrBigIntLiteral() {
|
||||
nextToken();
|
||||
return token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral;
|
||||
}
|
||||
|
||||
function parseNonArrayType(): TypeNode {
|
||||
@@ -2902,6 +2902,7 @@ namespace ts {
|
||||
case SyntaxKind.UnknownKeyword:
|
||||
case SyntaxKind.StringKeyword:
|
||||
case SyntaxKind.NumberKeyword:
|
||||
case SyntaxKind.BigIntKeyword:
|
||||
case SyntaxKind.SymbolKeyword:
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
case SyntaxKind.UndefinedKeyword:
|
||||
@@ -2922,11 +2923,12 @@ namespace ts {
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.BigIntLiteral:
|
||||
case SyntaxKind.TrueKeyword:
|
||||
case SyntaxKind.FalseKeyword:
|
||||
return parseLiteralTypeNode();
|
||||
case SyntaxKind.MinusToken:
|
||||
return lookAhead(nextTokenIsNumericLiteral) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference();
|
||||
return lookAhead(nextTokenIsNumericOrBigIntLiteral) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference();
|
||||
case SyntaxKind.VoidKeyword:
|
||||
case SyntaxKind.NullKeyword:
|
||||
return parseTokenNode<TypeNode>();
|
||||
@@ -2960,6 +2962,7 @@ namespace ts {
|
||||
case SyntaxKind.UnknownKeyword:
|
||||
case SyntaxKind.StringKeyword:
|
||||
case SyntaxKind.NumberKeyword:
|
||||
case SyntaxKind.BigIntKeyword:
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
case SyntaxKind.SymbolKeyword:
|
||||
case SyntaxKind.UniqueKeyword:
|
||||
@@ -2977,6 +2980,7 @@ namespace ts {
|
||||
case SyntaxKind.NewKeyword:
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.BigIntLiteral:
|
||||
case SyntaxKind.TrueKeyword:
|
||||
case SyntaxKind.FalseKeyword:
|
||||
case SyntaxKind.ObjectKeyword:
|
||||
@@ -2990,7 +2994,7 @@ namespace ts {
|
||||
case SyntaxKind.FunctionKeyword:
|
||||
return !inStartOfParameter;
|
||||
case SyntaxKind.MinusToken:
|
||||
return !inStartOfParameter && lookAhead(nextTokenIsNumericLiteral);
|
||||
return !inStartOfParameter && lookAhead(nextTokenIsNumericOrBigIntLiteral);
|
||||
case SyntaxKind.OpenParenToken:
|
||||
// Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier,
|
||||
// or something that starts a type. We don't want to consider things like '(1)' a type.
|
||||
@@ -3215,6 +3219,7 @@ namespace ts {
|
||||
case SyntaxKind.TrueKeyword:
|
||||
case SyntaxKind.FalseKeyword:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.BigIntLiteral:
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.TemplateHead:
|
||||
@@ -4624,6 +4629,7 @@ namespace ts {
|
||||
function parsePrimaryExpression(): PrimaryExpression {
|
||||
switch (token()) {
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.BigIntLiteral:
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
return parseLiteralNode();
|
||||
@@ -5139,7 +5145,7 @@ namespace ts {
|
||||
|
||||
function nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine() {
|
||||
nextToken();
|
||||
return (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.StringLiteral) && !scanner.hasPrecedingLineBreak();
|
||||
return (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral || token() === SyntaxKind.StringLiteral) && !scanner.hasPrecedingLineBreak();
|
||||
}
|
||||
|
||||
function isDeclaration(): boolean {
|
||||
@@ -6542,8 +6548,7 @@ namespace ts {
|
||||
|
||||
function parseTag(indent: number) {
|
||||
Debug.assert(token() === SyntaxKind.AtToken);
|
||||
const atToken = <AtToken>createNode(SyntaxKind.AtToken, scanner.getTokenPos());
|
||||
atToken.end = scanner.getTextPos();
|
||||
const start = scanner.getTokenPos();
|
||||
nextJSDocToken();
|
||||
|
||||
const tagName = parseJSDocIdentifierName(/*message*/ undefined);
|
||||
@@ -6553,40 +6558,40 @@ namespace ts {
|
||||
switch (tagName.escapedText) {
|
||||
case "augments":
|
||||
case "extends":
|
||||
tag = parseAugmentsTag(atToken, tagName);
|
||||
tag = parseAugmentsTag(start, tagName);
|
||||
break;
|
||||
case "class":
|
||||
case "constructor":
|
||||
tag = parseClassTag(atToken, tagName);
|
||||
tag = parseClassTag(start, tagName);
|
||||
break;
|
||||
case "this":
|
||||
tag = parseThisTag(atToken, tagName);
|
||||
tag = parseThisTag(start, tagName);
|
||||
break;
|
||||
case "enum":
|
||||
tag = parseEnumTag(atToken, tagName);
|
||||
tag = parseEnumTag(start, tagName);
|
||||
break;
|
||||
case "arg":
|
||||
case "argument":
|
||||
case "param":
|
||||
return parseParameterOrPropertyTag(atToken, tagName, PropertyLikeParse.Parameter, indent);
|
||||
return parseParameterOrPropertyTag(start, tagName, PropertyLikeParse.Parameter, indent);
|
||||
case "return":
|
||||
case "returns":
|
||||
tag = parseReturnTag(atToken, tagName);
|
||||
tag = parseReturnTag(start, tagName);
|
||||
break;
|
||||
case "template":
|
||||
tag = parseTemplateTag(atToken, tagName);
|
||||
tag = parseTemplateTag(start, tagName);
|
||||
break;
|
||||
case "type":
|
||||
tag = parseTypeTag(atToken, tagName);
|
||||
tag = parseTypeTag(start, tagName);
|
||||
break;
|
||||
case "typedef":
|
||||
tag = parseTypedefTag(atToken, tagName, indent);
|
||||
tag = parseTypedefTag(start, tagName, indent);
|
||||
break;
|
||||
case "callback":
|
||||
tag = parseCallbackTag(atToken, tagName, indent);
|
||||
tag = parseCallbackTag(start, tagName, indent);
|
||||
break;
|
||||
default:
|
||||
tag = parseUnknownTag(atToken, tagName);
|
||||
tag = parseUnknownTag(start, tagName);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -6669,9 +6674,8 @@ namespace ts {
|
||||
return comments.length === 0 ? undefined : comments.join("");
|
||||
}
|
||||
|
||||
function parseUnknownTag(atToken: AtToken, tagName: Identifier) {
|
||||
const result = <JSDocTag>createNode(SyntaxKind.JSDocTag, atToken.pos);
|
||||
result.atToken = atToken;
|
||||
function parseUnknownTag(start: number, tagName: Identifier) {
|
||||
const result = <JSDocTag>createNode(SyntaxKind.JSDocTag, start);
|
||||
result.tagName = tagName;
|
||||
return finishNode(result);
|
||||
}
|
||||
@@ -6728,7 +6732,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function parseParameterOrPropertyTag(atToken: AtToken, tagName: Identifier, target: PropertyLikeParse, indent: number): JSDocParameterTag | JSDocPropertyTag {
|
||||
function parseParameterOrPropertyTag(start: number, tagName: Identifier, target: PropertyLikeParse, indent: number): JSDocParameterTag | JSDocPropertyTag {
|
||||
let typeExpression = tryParseTypeExpression();
|
||||
let isNameFirst = !typeExpression;
|
||||
skipWhitespaceOrAsterisk();
|
||||
@@ -6741,15 +6745,14 @@ namespace ts {
|
||||
}
|
||||
|
||||
const result = target === PropertyLikeParse.Property ?
|
||||
<JSDocPropertyTag>createNode(SyntaxKind.JSDocPropertyTag, atToken.pos) :
|
||||
<JSDocParameterTag>createNode(SyntaxKind.JSDocParameterTag, atToken.pos);
|
||||
const comment = parseTagComments(indent + scanner.getStartPos() - atToken.pos);
|
||||
<JSDocPropertyTag>createNode(SyntaxKind.JSDocPropertyTag, start) :
|
||||
<JSDocParameterTag>createNode(SyntaxKind.JSDocParameterTag, start);
|
||||
const comment = parseTagComments(indent + scanner.getStartPos() - start);
|
||||
const nestedTypeLiteral = target !== PropertyLikeParse.CallbackParameter && parseNestedTypeLiteral(typeExpression, name, target, indent);
|
||||
if (nestedTypeLiteral) {
|
||||
typeExpression = nestedTypeLiteral;
|
||||
isNameFirst = true;
|
||||
}
|
||||
result.atToken = atToken;
|
||||
result.tagName = tagName;
|
||||
result.typeExpression = typeExpression;
|
||||
result.name = name;
|
||||
@@ -6783,33 +6786,30 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function parseReturnTag(atToken: AtToken, tagName: Identifier): JSDocReturnTag {
|
||||
function parseReturnTag(start: number, tagName: Identifier): JSDocReturnTag {
|
||||
if (forEach(tags, t => t.kind === SyntaxKind.JSDocReturnTag)) {
|
||||
parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText);
|
||||
}
|
||||
|
||||
const result = <JSDocReturnTag>createNode(SyntaxKind.JSDocReturnTag, atToken.pos);
|
||||
result.atToken = atToken;
|
||||
const result = <JSDocReturnTag>createNode(SyntaxKind.JSDocReturnTag, start);
|
||||
result.tagName = tagName;
|
||||
result.typeExpression = tryParseTypeExpression();
|
||||
return finishNode(result);
|
||||
}
|
||||
|
||||
function parseTypeTag(atToken: AtToken, tagName: Identifier): JSDocTypeTag {
|
||||
function parseTypeTag(start: number, tagName: Identifier): JSDocTypeTag {
|
||||
if (forEach(tags, t => t.kind === SyntaxKind.JSDocTypeTag)) {
|
||||
parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText);
|
||||
}
|
||||
|
||||
const result = <JSDocTypeTag>createNode(SyntaxKind.JSDocTypeTag, atToken.pos);
|
||||
result.atToken = atToken;
|
||||
const result = <JSDocTypeTag>createNode(SyntaxKind.JSDocTypeTag, start);
|
||||
result.tagName = tagName;
|
||||
result.typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);
|
||||
return finishNode(result);
|
||||
}
|
||||
|
||||
function parseAugmentsTag(atToken: AtToken, tagName: Identifier): JSDocAugmentsTag {
|
||||
const result = <JSDocAugmentsTag>createNode(SyntaxKind.JSDocAugmentsTag, atToken.pos);
|
||||
result.atToken = atToken;
|
||||
function parseAugmentsTag(start: number, tagName: Identifier): JSDocAugmentsTag {
|
||||
const result = <JSDocAugmentsTag>createNode(SyntaxKind.JSDocAugmentsTag, start);
|
||||
result.tagName = tagName;
|
||||
result.class = parseExpressionWithTypeArgumentsForAugments();
|
||||
return finishNode(result);
|
||||
@@ -6838,37 +6838,33 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
function parseClassTag(atToken: AtToken, tagName: Identifier): JSDocClassTag {
|
||||
const tag = <JSDocClassTag>createNode(SyntaxKind.JSDocClassTag, atToken.pos);
|
||||
tag.atToken = atToken;
|
||||
function parseClassTag(start: number, tagName: Identifier): JSDocClassTag {
|
||||
const tag = <JSDocClassTag>createNode(SyntaxKind.JSDocClassTag, start);
|
||||
tag.tagName = tagName;
|
||||
return finishNode(tag);
|
||||
}
|
||||
|
||||
function parseThisTag(atToken: AtToken, tagName: Identifier): JSDocThisTag {
|
||||
const tag = <JSDocThisTag>createNode(SyntaxKind.JSDocThisTag, atToken.pos);
|
||||
tag.atToken = atToken;
|
||||
function parseThisTag(start: number, tagName: Identifier): JSDocThisTag {
|
||||
const tag = <JSDocThisTag>createNode(SyntaxKind.JSDocThisTag, start);
|
||||
tag.tagName = tagName;
|
||||
tag.typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);
|
||||
skipWhitespace();
|
||||
return finishNode(tag);
|
||||
}
|
||||
|
||||
function parseEnumTag(atToken: AtToken, tagName: Identifier): JSDocEnumTag {
|
||||
const tag = <JSDocEnumTag>createNode(SyntaxKind.JSDocEnumTag, atToken.pos);
|
||||
tag.atToken = atToken;
|
||||
function parseEnumTag(start: number, tagName: Identifier): JSDocEnumTag {
|
||||
const tag = <JSDocEnumTag>createNode(SyntaxKind.JSDocEnumTag, start);
|
||||
tag.tagName = tagName;
|
||||
tag.typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);
|
||||
skipWhitespace();
|
||||
return finishNode(tag);
|
||||
}
|
||||
|
||||
function parseTypedefTag(atToken: AtToken, tagName: Identifier, indent: number): JSDocTypedefTag {
|
||||
function parseTypedefTag(start: number, tagName: Identifier, indent: number): JSDocTypedefTag {
|
||||
const typeExpression = tryParseTypeExpression();
|
||||
skipWhitespaceOrAsterisk();
|
||||
|
||||
const typedefTag = <JSDocTypedefTag>createNode(SyntaxKind.JSDocTypedefTag, atToken.pos);
|
||||
typedefTag.atToken = atToken;
|
||||
const typedefTag = <JSDocTypedefTag>createNode(SyntaxKind.JSDocTypedefTag, start);
|
||||
typedefTag.tagName = tagName;
|
||||
typedefTag.fullName = parseJSDocTypeNameWithNamespace();
|
||||
typedefTag.name = getJSDocTypeAliasName(typedefTag.fullName);
|
||||
@@ -6881,7 +6877,6 @@ namespace ts {
|
||||
let child: JSDocTypeTag | JSDocPropertyTag | false;
|
||||
let jsdocTypeLiteral: JSDocTypeLiteral | undefined;
|
||||
let childTypeTag: JSDocTypeTag | undefined;
|
||||
const start = atToken.pos;
|
||||
while (child = tryParse(() => parseChildPropertyTag(indent))) {
|
||||
if (!jsdocTypeLiteral) {
|
||||
jsdocTypeLiteral = <JSDocTypeLiteral>createNode(SyntaxKind.JSDocTypeLiteral, start);
|
||||
@@ -6935,9 +6930,8 @@ namespace ts {
|
||||
return typeNameOrNamespaceName;
|
||||
}
|
||||
|
||||
function parseCallbackTag(atToken: AtToken, tagName: Identifier, indent: number): JSDocCallbackTag {
|
||||
const callbackTag = createNode(SyntaxKind.JSDocCallbackTag, atToken.pos) as JSDocCallbackTag;
|
||||
callbackTag.atToken = atToken;
|
||||
function parseCallbackTag(start: number, tagName: Identifier, indent: number): JSDocCallbackTag {
|
||||
const callbackTag = createNode(SyntaxKind.JSDocCallbackTag, start) as JSDocCallbackTag;
|
||||
callbackTag.tagName = tagName;
|
||||
callbackTag.fullName = parseJSDocTypeNameWithNamespace();
|
||||
callbackTag.name = getJSDocTypeAliasName(callbackTag.fullName);
|
||||
@@ -6945,7 +6939,6 @@ namespace ts {
|
||||
callbackTag.comment = parseTagComments(indent);
|
||||
|
||||
let child: JSDocParameterTag | false;
|
||||
const start = scanner.getStartPos();
|
||||
const jsdocSignature = createNode(SyntaxKind.JSDocSignature, start) as JSDocSignature;
|
||||
jsdocSignature.parameters = [];
|
||||
while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter, indent) as JSDocParameterTag)) {
|
||||
@@ -7033,8 +7026,7 @@ namespace ts {
|
||||
|
||||
function tryParseChildTag(target: PropertyLikeParse, indent: number): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
|
||||
Debug.assert(token() === SyntaxKind.AtToken);
|
||||
const atToken = <AtToken>createNode(SyntaxKind.AtToken);
|
||||
atToken.end = scanner.getTextPos();
|
||||
const start = scanner.getStartPos();
|
||||
nextJSDocToken();
|
||||
|
||||
const tagName = parseJSDocIdentifierName();
|
||||
@@ -7042,7 +7034,7 @@ namespace ts {
|
||||
let t: PropertyLikeParse;
|
||||
switch (tagName.escapedText) {
|
||||
case "type":
|
||||
return target === PropertyLikeParse.Property && parseTypeTag(atToken, tagName);
|
||||
return target === PropertyLikeParse.Property && parseTypeTag(start, tagName);
|
||||
case "prop":
|
||||
case "property":
|
||||
t = PropertyLikeParse.Property;
|
||||
@@ -7058,10 +7050,10 @@ namespace ts {
|
||||
if (!(target & t)) {
|
||||
return false;
|
||||
}
|
||||
return parseParameterOrPropertyTag(atToken, tagName, target, indent);
|
||||
return parseParameterOrPropertyTag(start, tagName, target, indent);
|
||||
}
|
||||
|
||||
function parseTemplateTag(atToken: AtToken, tagName: Identifier): JSDocTemplateTag {
|
||||
function parseTemplateTag(start: number, tagName: Identifier): JSDocTemplateTag {
|
||||
// the template tag looks like '@template {Constraint} T,U,V'
|
||||
let constraint: JSDocTypeExpression | undefined;
|
||||
if (token() === SyntaxKind.OpenBraceToken) {
|
||||
@@ -7079,8 +7071,7 @@ namespace ts {
|
||||
typeParameters.push(typeParameter);
|
||||
} while (parseOptionalJsdoc(SyntaxKind.CommaToken));
|
||||
|
||||
const result = <JSDocTemplateTag>createNode(SyntaxKind.JSDocTemplateTag, atToken.pos);
|
||||
result.atToken = atToken;
|
||||
const result = <JSDocTemplateTag>createNode(SyntaxKind.JSDocTemplateTag, start);
|
||||
result.tagName = tagName;
|
||||
result.constraint = constraint;
|
||||
result.typeParameters = createNodeArray(typeParameters, typeParametersPos);
|
||||
|
||||
@@ -19,6 +19,41 @@ namespace ts.performance {
|
||||
let marks: Map<number>;
|
||||
let measures: Map<number>;
|
||||
|
||||
export interface Timer {
|
||||
enter(): void;
|
||||
exit(): void;
|
||||
}
|
||||
|
||||
export function createTimerIf(condition: boolean, measureName: string, startMarkName: string, endMarkName: string) {
|
||||
return condition ? createTimer(measureName, startMarkName, endMarkName) : nullTimer;
|
||||
}
|
||||
|
||||
export function createTimer(measureName: string, startMarkName: string, endMarkName: string): Timer {
|
||||
let enterCount = 0;
|
||||
return {
|
||||
enter,
|
||||
exit
|
||||
};
|
||||
|
||||
function enter() {
|
||||
if (++enterCount === 1) {
|
||||
mark(startMarkName);
|
||||
}
|
||||
}
|
||||
|
||||
function exit() {
|
||||
if (--enterCount === 0) {
|
||||
mark(endMarkName);
|
||||
measure(measureName, startMarkName, endMarkName);
|
||||
}
|
||||
else if (enterCount < 0) {
|
||||
Debug.fail("enter/exit count does not match.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const nullTimer: Timer = { enter: noop, exit: noop };
|
||||
|
||||
/**
|
||||
* Marks a performance event.
|
||||
*
|
||||
|
||||
+22
-16
@@ -198,7 +198,7 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[] {
|
||||
export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic> {
|
||||
const diagnostics = [
|
||||
...program.getConfigFileParsingDiagnostics(),
|
||||
...program.getOptionsDiagnostics(cancellationToken),
|
||||
@@ -694,12 +694,14 @@ namespace ts {
|
||||
if (!resolvedProjectReferences) {
|
||||
resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile);
|
||||
}
|
||||
for (const parsedRef of resolvedProjectReferences) {
|
||||
if (parsedRef) {
|
||||
const out = parsedRef.commandLine.options.outFile || parsedRef.commandLine.options.out;
|
||||
if (out) {
|
||||
const dtsOutfile = changeExtension(out, ".d.ts");
|
||||
processSourceFile(dtsOutfile, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
|
||||
if (rootNames.length) {
|
||||
for (const parsedRef of resolvedProjectReferences) {
|
||||
if (parsedRef) {
|
||||
const out = parsedRef.commandLine.options.outFile || parsedRef.commandLine.options.out;
|
||||
if (out) {
|
||||
const dtsOutfile = changeExtension(out, ".d.ts");
|
||||
processSourceFile(dtsOutfile, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -708,7 +710,7 @@ namespace ts {
|
||||
forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false));
|
||||
|
||||
// load type declarations specified via 'types' argument or implicitly from types/ and node_modules/@types folders
|
||||
const typeReferences: string[] = getAutomaticTypeDirectiveNames(options, host);
|
||||
const typeReferences: string[] = rootNames.length ? getAutomaticTypeDirectiveNames(options, host) : emptyArray;
|
||||
|
||||
if (typeReferences.length) {
|
||||
// This containingFilename needs to match with the one used in managed-side
|
||||
@@ -724,7 +726,7 @@ namespace ts {
|
||||
// - The '--noLib' flag is used.
|
||||
// - A 'no-default-lib' reference comment is encountered in
|
||||
// processing the root files.
|
||||
if (!skipDefaultLib) {
|
||||
if (rootNames.length && !skipDefaultLib) {
|
||||
// If '--lib' is not specified, include default library file according to '--target'
|
||||
// otherwise, using options specified in '--lib' instead of '--target' default library file
|
||||
const defaultLibraryFileName = getDefaultLibraryFileName();
|
||||
@@ -1817,7 +1819,7 @@ namespace ts {
|
||||
return sourceFile.isDeclarationFile ? [] : getDeclarationDiagnosticsWorker(sourceFile, cancellationToken);
|
||||
}
|
||||
|
||||
function getOptionsDiagnostics(): Diagnostic[] {
|
||||
function getOptionsDiagnostics(): SortedReadonlyArray<Diagnostic> {
|
||||
return sortAndDeduplicateDiagnostics(concatenate(
|
||||
fileProcessingDiagnostics.getGlobalDiagnostics(),
|
||||
concatenate(
|
||||
@@ -1838,8 +1840,8 @@ namespace ts {
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
function getGlobalDiagnostics(): Diagnostic[] {
|
||||
return sortAndDeduplicateDiagnostics(getDiagnosticsProducingTypeChecker().getGlobalDiagnostics().slice());
|
||||
function getGlobalDiagnostics(): SortedReadonlyArray<Diagnostic> {
|
||||
return rootNames.length ? sortAndDeduplicateDiagnostics(getDiagnosticsProducingTypeChecker().getGlobalDiagnostics().slice()) : emptyArray as any as SortedReadonlyArray<Diagnostic>;
|
||||
}
|
||||
|
||||
function getConfigFileParsingDiagnostics(): ReadonlyArray<Diagnostic> {
|
||||
@@ -2667,13 +2669,13 @@ namespace ts {
|
||||
const languageVersion = options.target || ScriptTarget.ES3;
|
||||
const outFile = options.outFile || options.out;
|
||||
|
||||
const firstNonAmbientExternalModuleSourceFile = forEach(files, f => isExternalModule(f) && !f.isDeclarationFile ? f : undefined);
|
||||
const firstNonAmbientExternalModuleSourceFile = find(files, f => isExternalModule(f) && !f.isDeclarationFile);
|
||||
if (options.isolatedModules) {
|
||||
if (options.module === ModuleKind.None && languageVersion < ScriptTarget.ES2015) {
|
||||
createDiagnosticForOptionName(Diagnostics.Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher, "isolatedModules", "target");
|
||||
}
|
||||
|
||||
const firstNonExternalModuleSourceFile = forEach(files, f => !isExternalModule(f) && !f.isDeclarationFile ? f : undefined);
|
||||
const firstNonExternalModuleSourceFile = find(files, f => !isExternalModule(f) && !f.isDeclarationFile && f.scriptKind !== ScriptKind.JSON);
|
||||
if (firstNonExternalModuleSourceFile) {
|
||||
const span = getErrorSpanForNode(firstNonExternalModuleSourceFile, firstNonExternalModuleSourceFile);
|
||||
programDiagnostics.add(createFileDiagnostic(firstNonExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_namespaces_when_the_isolatedModules_flag_is_provided));
|
||||
@@ -2716,7 +2718,7 @@ namespace ts {
|
||||
const dir = getCommonSourceDirectory();
|
||||
|
||||
// If we failed to find a good common directory, but outDir is specified and at least one of our files is on a windows drive/URL/other resource, add a failure
|
||||
if (options.outDir && dir === "" && forEach(files, file => getRootLength(file.fileName) > 1)) {
|
||||
if (options.outDir && dir === "" && files.some(file => getRootLength(file.fileName) > 1)) {
|
||||
createDiagnosticForOptionName(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files, "outDir");
|
||||
}
|
||||
}
|
||||
@@ -2806,7 +2808,11 @@ namespace ts {
|
||||
}
|
||||
const options = resolvedRef.commandLine.options;
|
||||
if (!options.composite) {
|
||||
createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.path);
|
||||
// ok to not have composite if the current program is container only
|
||||
const inputs = parent ? parent.commandLine.fileNames : rootNames;
|
||||
if (inputs.length) {
|
||||
createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.path);
|
||||
}
|
||||
}
|
||||
if (ref.prepend) {
|
||||
const out = options.outFile || options.out;
|
||||
|
||||
@@ -71,6 +71,10 @@ namespace ts {
|
||||
nonRecursive?: boolean;
|
||||
}
|
||||
|
||||
export function isPathInNodeModulesStartingWithDot(path: Path) {
|
||||
return stringContains(path, "/node_modules/.");
|
||||
}
|
||||
|
||||
export const maxNumberOfFilesToIterateForInvalidation = 256;
|
||||
|
||||
type GetResolutionWithResolvedFileName<T extends ResolutionWithFailedLookupLocations = ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName = ResolutionWithResolvedFileName> =
|
||||
@@ -79,7 +83,7 @@ namespace ts {
|
||||
export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootDirForResolution: string | undefined, logChangesWhenResolvingModule: boolean): ResolutionCache {
|
||||
let filesWithChangedSetOfUnresolvedImports: Path[] | undefined;
|
||||
let filesWithInvalidatedResolutions: Map<true> | undefined;
|
||||
let filesWithInvalidatedNonRelativeUnresolvedImports: Map<ReadonlyArray<string>> | undefined;
|
||||
let filesWithInvalidatedNonRelativeUnresolvedImports: ReadonlyMap<ReadonlyArray<string>> | undefined;
|
||||
let allFilesHaveInvalidatedResolution = false;
|
||||
const nonRelativeExternalModuleResolutions = createMultiMap<ResolutionWithFailedLookupLocations>();
|
||||
|
||||
@@ -241,14 +245,15 @@ namespace ts {
|
||||
}
|
||||
|
||||
function resolveNamesWithLocalCache<T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName>(
|
||||
names: string[],
|
||||
names: ReadonlyArray<string>,
|
||||
containingFile: string,
|
||||
redirectedReference: ResolvedProjectReference | undefined,
|
||||
cache: Map<Map<T>>,
|
||||
perDirectoryCacheWithRedirects: CacheWithRedirects<Map<T>>,
|
||||
loader: (name: string, containingFile: string, options: CompilerOptions, host: ModuleResolutionHost, redirectedReference?: ResolvedProjectReference) => T,
|
||||
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>,
|
||||
reusedNames: string[] | undefined,
|
||||
shouldRetryResolution: (t: T) => boolean,
|
||||
reusedNames: ReadonlyArray<string> | undefined,
|
||||
logChanges: boolean): (R | undefined)[] {
|
||||
|
||||
const path = resolutionHost.toPath(containingFile);
|
||||
@@ -260,7 +265,7 @@ namespace ts {
|
||||
perDirectoryResolution = createMap();
|
||||
perDirectoryCache.set(dirPath, perDirectoryResolution);
|
||||
}
|
||||
const resolvedModules: R[] = [];
|
||||
const resolvedModules: (R | undefined)[] = [];
|
||||
const compilerOptions = resolutionHost.getCompilationSettings();
|
||||
const hasInvalidatedNonRelativeUnresolvedImport = logChanges && isFileWithInvalidatedNonRelativeUnresolvedImports(path);
|
||||
|
||||
@@ -278,7 +283,7 @@ namespace ts {
|
||||
if (!seenNamesInFile.has(name) &&
|
||||
allFilesHaveInvalidatedResolution || unmatchedRedirects || !resolution || resolution.isInvalidated ||
|
||||
// If the name is unresolved import that was invalidated, recalculate
|
||||
(hasInvalidatedNonRelativeUnresolvedImport && !isExternalModuleNameRelative(name) && !getResolutionWithResolvedFileName(resolution))) {
|
||||
(hasInvalidatedNonRelativeUnresolvedImport && !isExternalModuleNameRelative(name) && shouldRetryResolution(resolution))) {
|
||||
const existingResolution = resolution;
|
||||
const resolutionInDirectory = perDirectoryResolution.get(name);
|
||||
if (resolutionInDirectory) {
|
||||
@@ -302,7 +307,7 @@ namespace ts {
|
||||
}
|
||||
Debug.assert(resolution !== undefined && !resolution.isInvalidated);
|
||||
seenNamesInFile.set(name, true);
|
||||
resolvedModules.push(getResolutionWithResolvedFileName(resolution)!); // TODO: GH#18217
|
||||
resolvedModules.push(getResolutionWithResolvedFileName(resolution));
|
||||
}
|
||||
|
||||
// Stop watching and remove the unused name
|
||||
@@ -339,6 +344,7 @@ namespace ts {
|
||||
typeDirectiveNames, containingFile, redirectedReference,
|
||||
resolvedTypeReferenceDirectives, perDirectoryResolvedTypeReferenceDirectives,
|
||||
resolveTypeReferenceDirective, getResolvedTypeReferenceDirective,
|
||||
/*shouldRetryResolution*/ resolution => resolution.resolvedTypeReferenceDirective === undefined,
|
||||
/*reusedNames*/ undefined, /*logChanges*/ false
|
||||
);
|
||||
}
|
||||
@@ -348,6 +354,7 @@ namespace ts {
|
||||
moduleNames, containingFile, redirectedReference,
|
||||
resolvedModuleNames, perDirectoryResolvedModuleNames,
|
||||
resolveModuleName, getResolvedModule,
|
||||
/*shouldRetryResolution*/ resolution => !resolution.resolvedModule || !resolutionExtensionIsTSOrJson(resolution.resolvedModule.extension),
|
||||
reusedNames, logChangesWhenResolvingModule
|
||||
);
|
||||
}
|
||||
@@ -675,7 +682,7 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
function setFilesWithInvalidatedNonRelativeUnresolvedImports(filesMap: Map<ReadonlyArray<string>>) {
|
||||
function setFilesWithInvalidatedNonRelativeUnresolvedImports(filesMap: ReadonlyMap<ReadonlyArray<string>>) {
|
||||
Debug.assert(filesWithInvalidatedNonRelativeUnresolvedImports === filesMap || filesWithInvalidatedNonRelativeUnresolvedImports === undefined);
|
||||
filesWithInvalidatedNonRelativeUnresolvedImports = filesMap;
|
||||
}
|
||||
@@ -688,6 +695,9 @@ namespace ts {
|
||||
isChangedFailedLookupLocation = location => isInDirectoryPath(fileOrDirectoryPath, resolutionHost.toPath(location));
|
||||
}
|
||||
else {
|
||||
// If something to do with folder/file starting with "." in node_modules folder, skip it
|
||||
if (isPathInNodeModulesStartingWithDot(fileOrDirectoryPath)) return false;
|
||||
|
||||
// Some file or directory in the watching directory is created
|
||||
// Return early if it does not have any of the watching extension or not the custom failed lookup path
|
||||
const dirOfFileOrDirectory = getDirectoryPath(fileOrDirectoryPath);
|
||||
|
||||
+79
-58
@@ -64,6 +64,7 @@ namespace ts {
|
||||
abstract: SyntaxKind.AbstractKeyword,
|
||||
any: SyntaxKind.AnyKeyword,
|
||||
as: SyntaxKind.AsKeyword,
|
||||
bigint: SyntaxKind.BigIntKeyword,
|
||||
boolean: SyntaxKind.BooleanKeyword,
|
||||
break: SyntaxKind.BreakKeyword,
|
||||
case: SyntaxKind.CaseKeyword,
|
||||
@@ -919,7 +920,7 @@ namespace ts {
|
||||
return result + text.substring(start, pos);
|
||||
}
|
||||
|
||||
function scanNumber(): string {
|
||||
function scanNumber(): {type: SyntaxKind, value: string} {
|
||||
const start = pos;
|
||||
const mainFragment = scanNumberFragment();
|
||||
let decimalFragment: string | undefined;
|
||||
@@ -943,18 +944,29 @@ namespace ts {
|
||||
end = pos;
|
||||
}
|
||||
}
|
||||
let result: string;
|
||||
if (tokenFlags & TokenFlags.ContainsSeparator) {
|
||||
let result = mainFragment;
|
||||
result = mainFragment;
|
||||
if (decimalFragment) {
|
||||
result += "." + decimalFragment;
|
||||
}
|
||||
if (scientificFragment) {
|
||||
result += scientificFragment;
|
||||
}
|
||||
return "" + +result;
|
||||
}
|
||||
else {
|
||||
return "" + +(text.substring(start, end)); // No need to use all the fragments; no _ removal needed
|
||||
result = text.substring(start, end); // No need to use all the fragments; no _ removal needed
|
||||
}
|
||||
if (decimalFragment !== undefined || tokenFlags & TokenFlags.Scientific) {
|
||||
return {
|
||||
type: SyntaxKind.NumericLiteral,
|
||||
value: "" + +result // if value is not an integer, it can be safely coerced to a number
|
||||
};
|
||||
}
|
||||
else {
|
||||
tokenValue = result;
|
||||
const type = checkBigIntSuffix(); // if value is an integer, check whether it is a bigint
|
||||
return { type, value: tokenValue };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -971,24 +983,24 @@ namespace ts {
|
||||
* returning -1 if the given number is unavailable.
|
||||
*/
|
||||
function scanExactNumberOfHexDigits(count: number, canHaveSeparators: boolean): number {
|
||||
return scanHexDigits(/*minCount*/ count, /*scanAsManyAsPossible*/ false, canHaveSeparators);
|
||||
const valueString = scanHexDigits(/*minCount*/ count, /*scanAsManyAsPossible*/ false, canHaveSeparators);
|
||||
return valueString ? parseInt(valueString, 16) : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans as many hexadecimal digits as are available in the text,
|
||||
* returning -1 if the given number of digits was unavailable.
|
||||
* returning "" if the given number of digits was unavailable.
|
||||
*/
|
||||
function scanMinimumNumberOfHexDigits(count: number, canHaveSeparators: boolean): number {
|
||||
function scanMinimumNumberOfHexDigits(count: number, canHaveSeparators: boolean): string {
|
||||
return scanHexDigits(/*minCount*/ count, /*scanAsManyAsPossible*/ true, canHaveSeparators);
|
||||
}
|
||||
|
||||
function scanHexDigits(minCount: number, scanAsManyAsPossible: boolean, canHaveSeparators: boolean): number {
|
||||
let digits = 0;
|
||||
let value = 0;
|
||||
function scanHexDigits(minCount: number, scanAsManyAsPossible: boolean, canHaveSeparators: boolean): string {
|
||||
let valueChars: number[] = [];
|
||||
let allowSeparator = false;
|
||||
let isPreviousTokenSeparator = false;
|
||||
while (digits < minCount || scanAsManyAsPossible) {
|
||||
const ch = text.charCodeAt(pos);
|
||||
while (valueChars.length < minCount || scanAsManyAsPossible) {
|
||||
let ch = text.charCodeAt(pos);
|
||||
if (canHaveSeparators && ch === CharacterCodes._) {
|
||||
tokenFlags |= TokenFlags.ContainsSeparator;
|
||||
if (allowSeparator) {
|
||||
@@ -1005,29 +1017,25 @@ namespace ts {
|
||||
continue;
|
||||
}
|
||||
allowSeparator = canHaveSeparators;
|
||||
if (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) {
|
||||
value = value * 16 + ch - CharacterCodes._0;
|
||||
if (ch >= CharacterCodes.A && ch <= CharacterCodes.F) {
|
||||
ch += CharacterCodes.a - CharacterCodes.A; // standardize hex literals to lowercase
|
||||
}
|
||||
else if (ch >= CharacterCodes.A && ch <= CharacterCodes.F) {
|
||||
value = value * 16 + ch - CharacterCodes.A + 10;
|
||||
}
|
||||
else if (ch >= CharacterCodes.a && ch <= CharacterCodes.f) {
|
||||
value = value * 16 + ch - CharacterCodes.a + 10;
|
||||
}
|
||||
else {
|
||||
else if (!((ch >= CharacterCodes._0 && ch <= CharacterCodes._9) ||
|
||||
(ch >= CharacterCodes.a && ch <= CharacterCodes.f)
|
||||
)) {
|
||||
break;
|
||||
}
|
||||
valueChars.push(ch);
|
||||
pos++;
|
||||
digits++;
|
||||
isPreviousTokenSeparator = false;
|
||||
}
|
||||
if (digits < minCount) {
|
||||
value = -1;
|
||||
if (valueChars.length < minCount) {
|
||||
valueChars = [];
|
||||
}
|
||||
if (text.charCodeAt(pos - 1) === CharacterCodes._) {
|
||||
error(Diagnostics.Numeric_separators_are_not_allowed_here, pos - 1, 1);
|
||||
}
|
||||
return value;
|
||||
return String.fromCharCode(...valueChars);
|
||||
}
|
||||
|
||||
function scanString(jsxAttributeString = false): string {
|
||||
@@ -1207,7 +1215,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function scanExtendedUnicodeEscape(): string {
|
||||
const escapedValue = scanMinimumNumberOfHexDigits(1, /*canHaveSeparators*/ false);
|
||||
const escapedValueString = scanMinimumNumberOfHexDigits(1, /*canHaveSeparators*/ false);
|
||||
const escapedValue = escapedValueString ? parseInt(escapedValueString, 16) : -1;
|
||||
let isInvalidExtendedEscape = false;
|
||||
|
||||
// Validate the value of the digit
|
||||
@@ -1309,13 +1318,10 @@ namespace ts {
|
||||
return token = SyntaxKind.Identifier;
|
||||
}
|
||||
|
||||
function scanBinaryOrOctalDigits(base: number): number {
|
||||
Debug.assert(base === 2 || base === 8, "Expected either base 2 or base 8");
|
||||
|
||||
let value = 0;
|
||||
function scanBinaryOrOctalDigits(base: 2 | 8): string {
|
||||
let value = "";
|
||||
// For counting number of digits; Valid binaryIntegerLiteral must have at least one binary digit following B or b.
|
||||
// Similarly valid octalIntegerLiteral must have at least one octal digit following o or O.
|
||||
let numberOfDigits = 0;
|
||||
let separatorAllowed = false;
|
||||
let isPreviousTokenSeparator = false;
|
||||
while (true) {
|
||||
@@ -1337,27 +1343,42 @@ namespace ts {
|
||||
continue;
|
||||
}
|
||||
separatorAllowed = true;
|
||||
const valueOfCh = ch - CharacterCodes._0;
|
||||
if (!isDigit(ch) || valueOfCh >= base) {
|
||||
if (!isDigit(ch) || ch - CharacterCodes._0 >= base) {
|
||||
break;
|
||||
}
|
||||
value = value * base + valueOfCh;
|
||||
value += text[pos];
|
||||
pos++;
|
||||
numberOfDigits++;
|
||||
isPreviousTokenSeparator = false;
|
||||
}
|
||||
// Invalid binaryIntegerLiteral or octalIntegerLiteral
|
||||
if (numberOfDigits === 0) {
|
||||
return -1;
|
||||
}
|
||||
if (text.charCodeAt(pos - 1) === CharacterCodes._) {
|
||||
// Literal ends with underscore - not allowed
|
||||
error(Diagnostics.Numeric_separators_are_not_allowed_here, pos - 1, 1);
|
||||
return value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function checkBigIntSuffix(): SyntaxKind {
|
||||
if (text.charCodeAt(pos) === CharacterCodes.n) {
|
||||
tokenValue += "n";
|
||||
// Use base 10 instead of base 2 or base 8 for shorter literals
|
||||
if (tokenFlags & TokenFlags.BinaryOrOctalSpecifier) {
|
||||
tokenValue = parsePseudoBigInt(tokenValue) + "n";
|
||||
}
|
||||
pos++;
|
||||
return SyntaxKind.BigIntLiteral;
|
||||
}
|
||||
else { // not a bigint, so can convert to number in simplified form
|
||||
// Number() may not support 0b or 0o, so use parseInt() instead
|
||||
const numericValue = tokenFlags & TokenFlags.BinarySpecifier
|
||||
? parseInt(tokenValue.slice(2), 2) // skip "0b"
|
||||
: tokenFlags & TokenFlags.OctalSpecifier
|
||||
? parseInt(tokenValue.slice(2), 8) // skip "0o"
|
||||
: +tokenValue;
|
||||
tokenValue = "" + numericValue;
|
||||
return SyntaxKind.NumericLiteral;
|
||||
}
|
||||
}
|
||||
|
||||
function scan(): SyntaxKind {
|
||||
startPos = pos;
|
||||
tokenFlags = 0;
|
||||
@@ -1506,7 +1527,7 @@ namespace ts {
|
||||
return token = SyntaxKind.MinusToken;
|
||||
case CharacterCodes.dot:
|
||||
if (isDigit(text.charCodeAt(pos + 1))) {
|
||||
tokenValue = scanNumber();
|
||||
tokenValue = scanNumber().value;
|
||||
return token = SyntaxKind.NumericLiteral;
|
||||
}
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.dot && text.charCodeAt(pos + 2) === CharacterCodes.dot) {
|
||||
@@ -1582,36 +1603,36 @@ namespace ts {
|
||||
case CharacterCodes._0:
|
||||
if (pos + 2 < end && (text.charCodeAt(pos + 1) === CharacterCodes.X || text.charCodeAt(pos + 1) === CharacterCodes.x)) {
|
||||
pos += 2;
|
||||
let value = scanMinimumNumberOfHexDigits(1, /*canHaveSeparators*/ true);
|
||||
if (value < 0) {
|
||||
tokenValue = scanMinimumNumberOfHexDigits(1, /*canHaveSeparators*/ true);
|
||||
if (!tokenValue) {
|
||||
error(Diagnostics.Hexadecimal_digit_expected);
|
||||
value = 0;
|
||||
tokenValue = "0";
|
||||
}
|
||||
tokenValue = "" + value;
|
||||
tokenValue = "0x" + tokenValue;
|
||||
tokenFlags |= TokenFlags.HexSpecifier;
|
||||
return token = SyntaxKind.NumericLiteral;
|
||||
return token = checkBigIntSuffix();
|
||||
}
|
||||
else if (pos + 2 < end && (text.charCodeAt(pos + 1) === CharacterCodes.B || text.charCodeAt(pos + 1) === CharacterCodes.b)) {
|
||||
pos += 2;
|
||||
let value = scanBinaryOrOctalDigits(/* base */ 2);
|
||||
if (value < 0) {
|
||||
tokenValue = scanBinaryOrOctalDigits(/* base */ 2);
|
||||
if (!tokenValue) {
|
||||
error(Diagnostics.Binary_digit_expected);
|
||||
value = 0;
|
||||
tokenValue = "0";
|
||||
}
|
||||
tokenValue = "" + value;
|
||||
tokenValue = "0b" + tokenValue;
|
||||
tokenFlags |= TokenFlags.BinarySpecifier;
|
||||
return token = SyntaxKind.NumericLiteral;
|
||||
return token = checkBigIntSuffix();
|
||||
}
|
||||
else if (pos + 2 < end && (text.charCodeAt(pos + 1) === CharacterCodes.O || text.charCodeAt(pos + 1) === CharacterCodes.o)) {
|
||||
pos += 2;
|
||||
let value = scanBinaryOrOctalDigits(/* base */ 8);
|
||||
if (value < 0) {
|
||||
tokenValue = scanBinaryOrOctalDigits(/* base */ 8);
|
||||
if (!tokenValue) {
|
||||
error(Diagnostics.Octal_digit_expected);
|
||||
value = 0;
|
||||
tokenValue = "0";
|
||||
}
|
||||
tokenValue = "" + value;
|
||||
tokenValue = "0o" + tokenValue;
|
||||
tokenFlags |= TokenFlags.OctalSpecifier;
|
||||
return token = SyntaxKind.NumericLiteral;
|
||||
return token = checkBigIntSuffix();
|
||||
}
|
||||
// Try to parse as an octal
|
||||
if (pos + 1 < end && isOctalDigit(text.charCodeAt(pos + 1))) {
|
||||
@@ -1632,8 +1653,8 @@ namespace ts {
|
||||
case CharacterCodes._7:
|
||||
case CharacterCodes._8:
|
||||
case CharacterCodes._9:
|
||||
tokenValue = scanNumber();
|
||||
return token = SyntaxKind.NumericLiteral;
|
||||
({ type: token, value: tokenValue } = scanNumber());
|
||||
return token;
|
||||
case CharacterCodes.colon:
|
||||
pos++;
|
||||
return token = SyntaxKind.ColonToken;
|
||||
|
||||
+642
-546
File diff suppressed because it is too large
Load Diff
@@ -1,377 +0,0 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export interface SourceFileLikeCache {
|
||||
get(path: Path): SourceFileLike | undefined;
|
||||
}
|
||||
|
||||
export function createSourceFileLikeCache(host: { readFile?: (path: string) => string | undefined, fileExists?: (path: string) => boolean }): SourceFileLikeCache {
|
||||
const cached = createMap<SourceFileLike>();
|
||||
return {
|
||||
get(path: Path) {
|
||||
if (cached.has(path)) {
|
||||
return cached.get(path);
|
||||
}
|
||||
if (!host.fileExists || !host.readFile || !host.fileExists(path)) return;
|
||||
// And failing that, check the disk
|
||||
const text = host.readFile(path)!; // TODO: GH#18217
|
||||
const file = {
|
||||
text,
|
||||
lineMap: undefined,
|
||||
getLineAndCharacterOfPosition(pos: number) {
|
||||
return computeLineAndCharacterOfPosition(getLineStarts(this), pos);
|
||||
}
|
||||
} as SourceFileLike;
|
||||
cached.set(path, file);
|
||||
return file;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
namespace ts.sourcemaps {
|
||||
export interface SourceMapData {
|
||||
version?: number;
|
||||
file?: string;
|
||||
sourceRoot?: string;
|
||||
sources: string[];
|
||||
sourcesContent?: (string | null)[];
|
||||
names?: string[];
|
||||
mappings: string;
|
||||
}
|
||||
|
||||
export interface SourceMappableLocation {
|
||||
fileName: string;
|
||||
position: number;
|
||||
}
|
||||
|
||||
export interface SourceMapper {
|
||||
getOriginalPosition(input: SourceMappableLocation): SourceMappableLocation;
|
||||
getGeneratedPosition(input: SourceMappableLocation): SourceMappableLocation;
|
||||
}
|
||||
|
||||
export const identitySourceMapper = { getOriginalPosition: identity, getGeneratedPosition: identity };
|
||||
|
||||
export interface SourceMapDecodeHost {
|
||||
readFile(path: string): string | undefined;
|
||||
fileExists(path: string): boolean;
|
||||
getCanonicalFileName(path: string): string;
|
||||
log(text: string): void;
|
||||
}
|
||||
|
||||
export function decode(host: SourceMapDecodeHost, mapPath: string, map: SourceMapData, program?: Program, fallbackCache = createSourceFileLikeCache(host)): SourceMapper {
|
||||
const currentDirectory = getDirectoryPath(mapPath);
|
||||
const sourceRoot = map.sourceRoot ? getNormalizedAbsolutePath(map.sourceRoot, currentDirectory) : currentDirectory;
|
||||
let decodedMappings: ProcessedSourceMapPosition[];
|
||||
let generatedOrderedMappings: ProcessedSourceMapPosition[];
|
||||
let sourceOrderedMappings: ProcessedSourceMapPosition[];
|
||||
|
||||
return {
|
||||
getOriginalPosition,
|
||||
getGeneratedPosition
|
||||
};
|
||||
|
||||
function getGeneratedPosition(loc: SourceMappableLocation): SourceMappableLocation {
|
||||
const maps = getSourceOrderedMappings();
|
||||
if (!length(maps)) return loc;
|
||||
let targetIndex = binarySearch(maps, { sourcePath: loc.fileName, sourcePosition: loc.position }, identity, compareProcessedPositionSourcePositions);
|
||||
if (targetIndex < 0 && maps.length > 0) {
|
||||
// if no exact match, closest is 2's compliment of result
|
||||
targetIndex = ~targetIndex;
|
||||
}
|
||||
if (!maps[targetIndex] || comparePaths(loc.fileName, maps[targetIndex].sourcePath, sourceRoot) !== 0) {
|
||||
return loc;
|
||||
}
|
||||
return { fileName: toPath(map.file!, sourceRoot, host.getCanonicalFileName), position: maps[targetIndex].emittedPosition }; // Closest pos
|
||||
}
|
||||
|
||||
function getOriginalPosition(loc: SourceMappableLocation): SourceMappableLocation {
|
||||
const maps = getGeneratedOrderedMappings();
|
||||
if (!length(maps)) return loc;
|
||||
let targetIndex = binarySearch(maps, { emittedPosition: loc.position }, identity, compareProcessedPositionEmittedPositions);
|
||||
if (targetIndex < 0 && maps.length > 0) {
|
||||
// if no exact match, closest is 2's compliment of result
|
||||
targetIndex = ~targetIndex;
|
||||
}
|
||||
return { fileName: toPath(maps[targetIndex].sourcePath, sourceRoot, host.getCanonicalFileName), position: maps[targetIndex].sourcePosition }; // Closest pos
|
||||
}
|
||||
|
||||
function getSourceFileLike(fileName: string, location: string): SourceFileLike | undefined {
|
||||
// Lookup file in program, if provided
|
||||
const path = toPath(fileName, location, host.getCanonicalFileName);
|
||||
const file = program && program.getSourceFile(path);
|
||||
// file returned here could be .d.ts when asked for .ts file if projectReferences and module resolution created this source file
|
||||
if (!file || file.resolvedPath !== path) {
|
||||
// Otherwise check the cache (which may hit disk)
|
||||
return fallbackCache.get(path);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
function getPositionOfLineAndCharacterUsingName(fileName: string, directory: string, line: number, character: number) {
|
||||
const file = getSourceFileLike(fileName, directory);
|
||||
if (!file) {
|
||||
return -1;
|
||||
}
|
||||
return getPositionOfLineAndCharacter(file, line, character);
|
||||
}
|
||||
|
||||
function getDecodedMappings() {
|
||||
return decodedMappings || (decodedMappings = calculateDecodedMappings(map, processPosition, host));
|
||||
}
|
||||
|
||||
function getSourceOrderedMappings() {
|
||||
return sourceOrderedMappings || (sourceOrderedMappings = getDecodedMappings().slice().sort(compareProcessedPositionSourcePositions));
|
||||
}
|
||||
|
||||
function getGeneratedOrderedMappings() {
|
||||
return generatedOrderedMappings || (generatedOrderedMappings = getDecodedMappings().slice().sort(compareProcessedPositionEmittedPositions));
|
||||
}
|
||||
|
||||
function compareProcessedPositionSourcePositions(a: ProcessedSourceMapPosition, b: ProcessedSourceMapPosition) {
|
||||
return comparePaths(a.sourcePath, b.sourcePath, sourceRoot) ||
|
||||
compareValues(a.sourcePosition, b.sourcePosition);
|
||||
}
|
||||
|
||||
function compareProcessedPositionEmittedPositions(a: ProcessedSourceMapPosition, b: ProcessedSourceMapPosition) {
|
||||
return compareValues(a.emittedPosition, b.emittedPosition);
|
||||
}
|
||||
|
||||
function processPosition(position: RawSourceMapPosition): ProcessedSourceMapPosition {
|
||||
const sourcePath = map.sources[position.sourceIndex];
|
||||
return {
|
||||
emittedPosition: getPositionOfLineAndCharacterUsingName(map.file!, currentDirectory, position.emittedLine, position.emittedColumn),
|
||||
sourcePosition: getPositionOfLineAndCharacterUsingName(sourcePath, sourceRoot, position.sourceLine, position.sourceColumn),
|
||||
sourcePath,
|
||||
// TODO: Consider using `name` field to remap the expected identifier to scan for renames to handle another tool renaming oout output
|
||||
// name: position.nameIndex ? map.names[position.nameIndex] : undefined
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export interface MappingsDecoder extends Iterator<SourceMapSpan> {
|
||||
readonly decodingIndex: number;
|
||||
readonly error: string | undefined;
|
||||
readonly lastSpan: SourceMapSpan;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function decodeMappings(map: SourceMapData): MappingsDecoder {
|
||||
const state: DecoderState = {
|
||||
encodedText: map.mappings,
|
||||
currentNameIndex: undefined,
|
||||
sourceMapNamesLength: map.names ? map.names.length : undefined,
|
||||
currentEmittedColumn: 0,
|
||||
currentEmittedLine: 0,
|
||||
currentSourceColumn: 0,
|
||||
currentSourceLine: 0,
|
||||
currentSourceIndex: 0,
|
||||
decodingIndex: 0
|
||||
};
|
||||
function captureSpan(): SourceMapSpan {
|
||||
return {
|
||||
emittedColumn: state.currentEmittedColumn,
|
||||
emittedLine: state.currentEmittedLine,
|
||||
sourceColumn: state.currentSourceColumn,
|
||||
sourceIndex: state.currentSourceIndex,
|
||||
sourceLine: state.currentSourceLine,
|
||||
nameIndex: state.currentNameIndex
|
||||
};
|
||||
}
|
||||
return {
|
||||
get decodingIndex() { return state.decodingIndex; },
|
||||
get error() { return state.error; },
|
||||
get lastSpan() { return captureSpan(); },
|
||||
next() {
|
||||
if (hasCompletedDecoding(state) || state.error) return { done: true, value: undefined as never };
|
||||
if (!decodeSinglePosition(state)) return { done: true, value: undefined as never };
|
||||
return { done: false, value: captureSpan() };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function calculateDecodedMappings<T>(map: SourceMapData, processPosition: (position: RawSourceMapPosition) => T, host?: { log?(s: string): void }): T[] {
|
||||
const decoder = decodeMappings(map);
|
||||
const positions = arrayFrom(decoder, processPosition);
|
||||
if (decoder.error) {
|
||||
if (host && host.log) {
|
||||
host.log(`Encountered error while decoding sourcemap: ${decoder.error}`);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
return positions;
|
||||
}
|
||||
|
||||
interface ProcessedSourceMapPosition {
|
||||
emittedPosition: number;
|
||||
sourcePosition: number;
|
||||
sourcePath: string;
|
||||
}
|
||||
|
||||
interface RawSourceMapPosition {
|
||||
emittedLine: number;
|
||||
emittedColumn: number;
|
||||
sourceLine: number;
|
||||
sourceColumn: number;
|
||||
sourceIndex: number;
|
||||
nameIndex?: number;
|
||||
}
|
||||
|
||||
interface DecoderState {
|
||||
decodingIndex: number;
|
||||
currentEmittedLine: number;
|
||||
currentEmittedColumn: number;
|
||||
currentSourceLine: number;
|
||||
currentSourceColumn: number;
|
||||
currentSourceIndex: number;
|
||||
currentNameIndex: number | undefined;
|
||||
encodedText: string;
|
||||
sourceMapNamesLength?: number;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
function hasCompletedDecoding(state: DecoderState) {
|
||||
return state.decodingIndex === state.encodedText.length;
|
||||
}
|
||||
|
||||
function decodeSinglePosition(state: DecoderState): boolean {
|
||||
while (state.decodingIndex < state.encodedText.length) {
|
||||
const char = state.encodedText.charCodeAt(state.decodingIndex);
|
||||
if (char === CharacterCodes.semicolon) {
|
||||
// New line
|
||||
state.currentEmittedLine++;
|
||||
state.currentEmittedColumn = 0;
|
||||
state.decodingIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (char === CharacterCodes.comma) {
|
||||
// Next entry is on same line - no action needed
|
||||
state.decodingIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read the current position
|
||||
// 1. Column offset from prev read jsColumn
|
||||
state.currentEmittedColumn += base64VLQFormatDecode();
|
||||
// Incorrect emittedColumn dont support this map
|
||||
if (createErrorIfCondition(state.currentEmittedColumn < 0, "Invalid emittedColumn found")) {
|
||||
return false;
|
||||
}
|
||||
// Dont support reading mappings that dont have information about original source and its line numbers
|
||||
if (createErrorIfCondition(isSourceMappingSegmentEnd(state.encodedText, state.decodingIndex), "Unsupported Error Format: No entries after emitted column")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. Relative sourceIndex
|
||||
state.currentSourceIndex += base64VLQFormatDecode();
|
||||
// Incorrect sourceIndex dont support this map
|
||||
if (createErrorIfCondition(state.currentSourceIndex < 0, "Invalid sourceIndex found")) {
|
||||
return false;
|
||||
}
|
||||
// Dont support reading mappings that dont have information about original source position
|
||||
if (createErrorIfCondition(isSourceMappingSegmentEnd(state.encodedText, state.decodingIndex), "Unsupported Error Format: No entries after sourceIndex")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. Relative sourceLine 0 based
|
||||
state.currentSourceLine += base64VLQFormatDecode();
|
||||
// Incorrect sourceLine dont support this map
|
||||
if (createErrorIfCondition(state.currentSourceLine < 0, "Invalid sourceLine found")) {
|
||||
return false;
|
||||
}
|
||||
// Dont support reading mappings that dont have information about original source and its line numbers
|
||||
if (createErrorIfCondition(isSourceMappingSegmentEnd(state.encodedText, state.decodingIndex), "Unsupported Error Format: No entries after emitted Line")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. Relative sourceColumn 0 based
|
||||
state.currentSourceColumn += base64VLQFormatDecode();
|
||||
// Incorrect sourceColumn dont support this map
|
||||
if (createErrorIfCondition(state.currentSourceColumn < 0, "Invalid sourceLine found")) {
|
||||
return false;
|
||||
}
|
||||
// 5. Check if there is name:
|
||||
if (!isSourceMappingSegmentEnd(state.encodedText, state.decodingIndex)) {
|
||||
if (state.currentNameIndex === undefined) {
|
||||
state.currentNameIndex = 0;
|
||||
}
|
||||
state.currentNameIndex += base64VLQFormatDecode();
|
||||
// Incorrect nameIndex dont support this map
|
||||
// TODO: If we start using `name`s, issue errors when they aren't correct in the sourcemap
|
||||
// if (createErrorIfCondition(state.currentNameIndex < 0 || state.currentNameIndex >= state.sourceMapNamesLength, "Invalid name index for the source map entry")) {
|
||||
// return;
|
||||
// }
|
||||
}
|
||||
// Dont support reading mappings that dont have information about original source and its line numbers
|
||||
if (createErrorIfCondition(!isSourceMappingSegmentEnd(state.encodedText, state.decodingIndex), "Unsupported Error Format: There are more entries after " + (state.currentNameIndex === undefined ? "sourceColumn" : "nameIndex"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Entry should be complete
|
||||
return true;
|
||||
}
|
||||
|
||||
createErrorIfCondition(/*condition*/ true, "No encoded entry found");
|
||||
return false;
|
||||
|
||||
function createErrorIfCondition(condition: boolean, errormsg: string) {
|
||||
if (state.error) {
|
||||
// An error was already reported
|
||||
return true;
|
||||
}
|
||||
|
||||
if (condition) {
|
||||
state.error = errormsg;
|
||||
}
|
||||
|
||||
return condition;
|
||||
}
|
||||
|
||||
function base64VLQFormatDecode(): number {
|
||||
let moreDigits = true;
|
||||
let shiftCount = 0;
|
||||
let value = 0;
|
||||
|
||||
for (; moreDigits; state.decodingIndex++) {
|
||||
if (createErrorIfCondition(state.decodingIndex >= state.encodedText.length, "Error in decoding base64VLQFormatDecode, past the mapping string")) {
|
||||
return undefined!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
// 6 digit number
|
||||
const currentByte = base64FormatDecode(state.encodedText.charAt(state.decodingIndex));
|
||||
|
||||
// If msb is set, we still have more bits to continue
|
||||
moreDigits = (currentByte & 32) !== 0;
|
||||
|
||||
// least significant 5 bits are the next msbs in the final value.
|
||||
value = value | ((currentByte & 31) << shiftCount);
|
||||
shiftCount += 5;
|
||||
}
|
||||
|
||||
// Least significant bit if 1 represents negative and rest of the msb is actual absolute value
|
||||
if ((value & 1) === 0) {
|
||||
// + number
|
||||
value = value >> 1;
|
||||
}
|
||||
else {
|
||||
// - number
|
||||
value = value >> 1;
|
||||
value = -value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
function base64FormatDecode(char: string) {
|
||||
return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".indexOf(char);
|
||||
}
|
||||
|
||||
function isSourceMappingSegmentEnd(encodedText: string, pos: number) {
|
||||
return (pos === encodedText.length ||
|
||||
encodedText.charCodeAt(pos) === CharacterCodes.comma ||
|
||||
encodedText.charCodeAt(pos) === CharacterCodes.semicolon);
|
||||
}
|
||||
}
|
||||
@@ -68,6 +68,14 @@ namespace ts {
|
||||
return transformers;
|
||||
}
|
||||
|
||||
export function noEmitSubstitution(_hint: EmitHint, node: Node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function noEmitNotification(hint: EmitHint, node: Node, callback: (hint: EmitHint, node: Node) => void) {
|
||||
callback(hint, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an array of SourceFiles by passing them through each transformer.
|
||||
*
|
||||
@@ -87,8 +95,8 @@ namespace ts {
|
||||
let lexicalEnvironmentStackOffset = 0;
|
||||
let lexicalEnvironmentSuspended = false;
|
||||
let emitHelpers: EmitHelper[] | undefined;
|
||||
let onSubstituteNode: TransformationContext["onSubstituteNode"] = (_, node) => node;
|
||||
let onEmitNode: TransformationContext["onEmitNode"] = (hint, node, callback) => callback(hint, node);
|
||||
let onSubstituteNode: TransformationContext["onSubstituteNode"] = noEmitSubstitution;
|
||||
let onEmitNode: TransformationContext["onEmitNode"] = noEmitNotification;
|
||||
let state = TransformationState.Uninitialized;
|
||||
const diagnostics: DiagnosticWithLocation[] = [];
|
||||
|
||||
|
||||
@@ -373,7 +373,7 @@ namespace ts {
|
||||
|
||||
function ensureNoInitializer(node: CanHaveLiteralInitializer) {
|
||||
if (shouldPrintWithInitializer(node)) {
|
||||
return resolver.createLiteralConstValue(getParseTreeNode(node) as CanHaveLiteralInitializer); // TODO: Make safe
|
||||
return resolver.createLiteralConstValue(getParseTreeNode(node) as CanHaveLiteralInitializer, symbolTracker); // TODO: Make safe
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -1043,7 +1043,7 @@ namespace ts {
|
||||
const modifiers = createNodeArray(ensureModifiers(input, isPrivate));
|
||||
const typeParameters = ensureTypeParams(input, input.typeParameters);
|
||||
const ctor = getFirstConstructorWithBody(input);
|
||||
let parameterProperties: PropertyDeclaration[] | undefined;
|
||||
let parameterProperties: ReadonlyArray<PropertyDeclaration> | undefined;
|
||||
if (ctor) {
|
||||
const oldDiag = getSymbolAccessibilityDiagnostic;
|
||||
parameterProperties = compact(flatMap(ctor.parameters, param => {
|
||||
|
||||
@@ -1901,6 +1901,9 @@ namespace ts {
|
||||
case SyntaxKind.NumericLiteral:
|
||||
return createIdentifier("Number");
|
||||
|
||||
case SyntaxKind.BigIntLiteral:
|
||||
return getGlobalBigIntNameWithFallback();
|
||||
|
||||
case SyntaxKind.TrueKeyword:
|
||||
case SyntaxKind.FalseKeyword:
|
||||
return createIdentifier("Boolean");
|
||||
@@ -1912,6 +1915,9 @@ namespace ts {
|
||||
case SyntaxKind.NumberKeyword:
|
||||
return createIdentifier("Number");
|
||||
|
||||
case SyntaxKind.BigIntKeyword:
|
||||
return getGlobalBigIntNameWithFallback();
|
||||
|
||||
case SyntaxKind.SymbolKeyword:
|
||||
return languageVersion < ScriptTarget.ES2015
|
||||
? getGlobalSymbolNameWithFallback()
|
||||
@@ -2006,6 +2012,9 @@ namespace ts {
|
||||
case TypeReferenceSerializationKind.VoidNullableOrNeverType:
|
||||
return createVoidZero();
|
||||
|
||||
case TypeReferenceSerializationKind.BigIntLikeType:
|
||||
return getGlobalBigIntNameWithFallback();
|
||||
|
||||
case TypeReferenceSerializationKind.BooleanType:
|
||||
return createIdentifier("Boolean");
|
||||
|
||||
@@ -2115,6 +2124,20 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that points to the global "BigInt" constructor at runtime if it is
|
||||
* available.
|
||||
*/
|
||||
function getGlobalBigIntNameWithFallback(): SerializedTypeNode {
|
||||
return languageVersion < ScriptTarget.ESNext
|
||||
? createConditional(
|
||||
createTypeCheck(createIdentifier("BigInt"), "function"),
|
||||
createIdentifier("BigInt"),
|
||||
createIdentifier("Object")
|
||||
)
|
||||
: createIdentifier("BigInt");
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple inlinable expression is an expression which can be copied into multiple locations
|
||||
* without risk of repeating any sideeffects and whose value could not possibly change between
|
||||
|
||||
+37
-20
@@ -29,6 +29,9 @@ namespace ts {
|
||||
preserveWatchOutput?: boolean;
|
||||
listEmittedFiles?: boolean;
|
||||
listFiles?: boolean;
|
||||
pretty?: boolean;
|
||||
|
||||
traceResolution?: boolean;
|
||||
}
|
||||
|
||||
enum BuildResultFlags {
|
||||
@@ -316,7 +319,7 @@ namespace ts {
|
||||
return fileExtensionIs(fileName, Extension.Dts);
|
||||
}
|
||||
|
||||
export interface SolutionBuilderHost extends CompilerHost {
|
||||
export interface SolutionBuilderHostBase extends CompilerHost {
|
||||
getModifiedTime(fileName: string): Date | undefined;
|
||||
setModifiedTime(fileName: string, date: Date): void;
|
||||
deleteFile(fileName: string): void;
|
||||
@@ -325,13 +328,18 @@ namespace ts {
|
||||
reportSolutionBuilderStatus: DiagnosticReporter;
|
||||
}
|
||||
|
||||
export interface SolutionBuilderWithWatchHost extends SolutionBuilderHost, WatchHost {
|
||||
export interface SolutionBuilderHost extends SolutionBuilderHostBase {
|
||||
reportErrorSummary?: ReportEmitErrorSummary;
|
||||
}
|
||||
|
||||
export interface SolutionBuilderWithWatchHost extends SolutionBuilderHostBase, WatchHost {
|
||||
}
|
||||
|
||||
export interface SolutionBuilder {
|
||||
buildAllProjects(): ExitStatus;
|
||||
cleanAllProjects(): ExitStatus;
|
||||
|
||||
// TODO:: All the below ones should technically only be in watch mode. but thats for later time
|
||||
/*@internal*/ resolveProjectName(name: string): ResolvedConfigFileName;
|
||||
/*@internal*/ getUpToDateStatusOfFile(configFileName: ResolvedConfigFileName): UpToDateStatus;
|
||||
/*@internal*/ getBuildGraph(configFileNames: ReadonlyArray<string>): DependencyGraph;
|
||||
@@ -340,7 +348,9 @@ namespace ts {
|
||||
/*@internal*/ buildInvalidatedProject(): void;
|
||||
|
||||
/*@internal*/ resetBuildContext(opts?: BuildOptions): void;
|
||||
}
|
||||
|
||||
export interface SolutionBuilderWithWatch extends SolutionBuilder {
|
||||
/*@internal*/ startWatching(): void;
|
||||
}
|
||||
|
||||
@@ -355,8 +365,8 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
export function createSolutionBuilderHost(system = sys, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter) {
|
||||
const host = createCompilerHostWorker({}, /*setParentNodes*/ undefined, system) as SolutionBuilderHost;
|
||||
function createSolutionBuilderHostBase(system = sys, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter) {
|
||||
const host = createCompilerHostWorker({}, /*setParentNodes*/ undefined, system) as SolutionBuilderHostBase;
|
||||
host.getModifiedTime = system.getModifiedTime ? path => system.getModifiedTime!(path) : () => undefined;
|
||||
host.setModifiedTime = system.setModifiedTime ? (path, date) => system.setModifiedTime!(path, date) : noop;
|
||||
host.deleteFile = system.deleteFile ? path => system.deleteFile!(path) : noop;
|
||||
@@ -365,8 +375,14 @@ namespace ts {
|
||||
return host;
|
||||
}
|
||||
|
||||
export function createSolutionBuilderWithWatchHost(system = sys, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter) {
|
||||
const host = createSolutionBuilderHost(system, reportDiagnostic, reportSolutionBuilderStatus) as SolutionBuilderWithWatchHost;
|
||||
export function createSolutionBuilderHost(system = sys, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter, reportErrorSummary?: ReportEmitErrorSummary) {
|
||||
const host = createSolutionBuilderHostBase(system, reportDiagnostic, reportSolutionBuilderStatus) as SolutionBuilderHost;
|
||||
host.reportErrorSummary = reportErrorSummary;
|
||||
return host;
|
||||
}
|
||||
|
||||
export function createSolutionBuilderWithWatchHost(system?: System, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter) {
|
||||
const host = createSolutionBuilderHostBase(system, reportDiagnostic, reportSolutionBuilderStatus) as SolutionBuilderWithWatchHost;
|
||||
const watchHost = createWatchHost(system, reportWatchStatus);
|
||||
host.onWatchStatusChange = watchHost.onWatchStatusChange;
|
||||
host.watchFile = watchHost.watchFile;
|
||||
@@ -390,7 +406,9 @@ namespace ts {
|
||||
* TODO: use SolutionBuilderWithWatchHost => watchedSolution
|
||||
* use SolutionBuilderHost => Solution
|
||||
*/
|
||||
export function createSolutionBuilder(host: SolutionBuilderHost, rootNames: ReadonlyArray<string>, defaultOptions: BuildOptions): SolutionBuilder {
|
||||
export function createSolutionBuilder(host: SolutionBuilderHost, rootNames: ReadonlyArray<string>, defaultOptions: BuildOptions): SolutionBuilder;
|
||||
export function createSolutionBuilder(host: SolutionBuilderWithWatchHost, rootNames: ReadonlyArray<string>, defaultOptions: BuildOptions): SolutionBuilderWithWatch;
|
||||
export function createSolutionBuilder(host: SolutionBuilderHost | SolutionBuilderWithWatchHost, rootNames: ReadonlyArray<string>, defaultOptions: BuildOptions): SolutionBuilderWithWatch {
|
||||
const hostWithWatch = host as SolutionBuilderWithWatchHost;
|
||||
const currentDirectory = host.getCurrentDirectory();
|
||||
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames());
|
||||
@@ -803,9 +821,7 @@ namespace ts {
|
||||
globalDependencyGraph = undefined;
|
||||
}
|
||||
projectStatus.removeKey(resolved);
|
||||
if (options.watch) {
|
||||
diagnostics.removeKey(resolved);
|
||||
}
|
||||
diagnostics.removeKey(resolved);
|
||||
|
||||
addProjToQueue(resolved, reloadLevel);
|
||||
}
|
||||
@@ -874,7 +890,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function reportErrorSummary() {
|
||||
if (options.watch) {
|
||||
if (options.watch || (host as SolutionBuilderHost).reportErrorSummary) {
|
||||
// Report errors from the other projects
|
||||
getGlobalDependencyGraph().buildQueue.forEach(project => {
|
||||
if (!projectErrorsReported.hasKey(project)) {
|
||||
@@ -882,8 +898,13 @@ namespace ts {
|
||||
}
|
||||
});
|
||||
let totalErrors = 0;
|
||||
diagnostics.forEach(singleProjectErrors => totalErrors += singleProjectErrors.filter(diagnostic => diagnostic.category === DiagnosticCategory.Error).length);
|
||||
reportWatchStatus(totalErrors === 1 ? Diagnostics.Found_1_error_Watching_for_file_changes : Diagnostics.Found_0_errors_Watching_for_file_changes, totalErrors);
|
||||
diagnostics.forEach(singleProjectErrors => totalErrors += getErrorCountForSummary(singleProjectErrors));
|
||||
if (options.watch) {
|
||||
reportWatchStatus(getWatchErrorSummaryDiagnosticMessage(totalErrors), totalErrors);
|
||||
}
|
||||
else {
|
||||
(host as SolutionBuilderHost).reportErrorSummary!(totalErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1066,9 +1087,7 @@ namespace ts {
|
||||
type: UpToDateStatusType.UpToDate,
|
||||
newestDeclarationFileContentChangedTime: anyDtsChanged ? maximumDate : newestDeclarationFileContentChangedTime
|
||||
};
|
||||
if (options.watch) {
|
||||
diagnostics.removeKey(proj);
|
||||
}
|
||||
diagnostics.removeKey(proj);
|
||||
projectStatus.setValue(proj, status);
|
||||
return resultFlags;
|
||||
|
||||
@@ -1207,10 +1226,8 @@ namespace ts {
|
||||
|
||||
function reportAndStoreErrors(proj: ResolvedConfigFileName, errors: ReadonlyArray<Diagnostic>) {
|
||||
reportErrors(errors);
|
||||
if (options.watch) {
|
||||
projectErrorsReported.setValue(proj, true);
|
||||
diagnostics.setValue(proj, errors);
|
||||
}
|
||||
projectErrorsReported.setValue(proj, true);
|
||||
diagnostics.setValue(proj, errors);
|
||||
}
|
||||
|
||||
function reportErrors(errors: ReadonlyArray<Diagnostic>) {
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"checker.ts",
|
||||
"factory.ts",
|
||||
"visitor.ts",
|
||||
"sourcemapDecoder.ts",
|
||||
"sourcemap.ts",
|
||||
"transformers/utilities.ts",
|
||||
"transformers/destructuring.ts",
|
||||
"transformers/ts.ts",
|
||||
@@ -42,8 +42,6 @@
|
||||
"transformers/declarations/diagnostics.ts",
|
||||
"transformers/declarations.ts",
|
||||
"transformer.ts",
|
||||
"sourcemap.ts",
|
||||
"comments.ts",
|
||||
"emitter.ts",
|
||||
"watchUtilities.ts",
|
||||
"program.ts",
|
||||
|
||||
+149
-55
@@ -31,6 +31,7 @@ namespace ts {
|
||||
| SyntaxKind.AbstractKeyword
|
||||
| SyntaxKind.AnyKeyword
|
||||
| SyntaxKind.AsKeyword
|
||||
| SyntaxKind.BigIntKeyword
|
||||
| SyntaxKind.BooleanKeyword
|
||||
| SyntaxKind.BreakKeyword
|
||||
| SyntaxKind.CaseKeyword
|
||||
@@ -128,6 +129,7 @@ namespace ts {
|
||||
ConflictMarkerTrivia,
|
||||
// Literals
|
||||
NumericLiteral,
|
||||
BigIntLiteral,
|
||||
StringLiteral,
|
||||
JsxText,
|
||||
JsxTextAllWhiteSpaces,
|
||||
@@ -271,6 +273,7 @@ namespace ts {
|
||||
UnknownKeyword,
|
||||
FromKeyword,
|
||||
GlobalKeyword,
|
||||
BigIntKeyword,
|
||||
OfKeyword, // LastKeyword and LastToken and LastContextualKeyword
|
||||
|
||||
// Parse tree nodes
|
||||
@@ -716,7 +719,6 @@ namespace ts {
|
||||
export type AsteriskToken = Token<SyntaxKind.AsteriskToken>;
|
||||
export type EqualsGreaterThanToken = Token<SyntaxKind.EqualsGreaterThanToken>;
|
||||
export type EndOfFileToken = Token<SyntaxKind.EndOfFileToken> & JSDocContainer;
|
||||
export type AtToken = Token<SyntaxKind.AtToken>;
|
||||
export type ReadonlyToken = Token<SyntaxKind.ReadonlyKeyword>;
|
||||
export type AwaitKeywordToken = Token<SyntaxKind.AwaitKeyword>;
|
||||
export type PlusToken = Token<SyntaxKind.PlusToken>;
|
||||
@@ -1109,6 +1111,7 @@ namespace ts {
|
||||
kind: SyntaxKind.AnyKeyword
|
||||
| SyntaxKind.UnknownKeyword
|
||||
| SyntaxKind.NumberKeyword
|
||||
| SyntaxKind.BigIntKeyword
|
||||
| SyntaxKind.ObjectKeyword
|
||||
| SyntaxKind.BooleanKeyword
|
||||
| SyntaxKind.StringKeyword
|
||||
@@ -1659,7 +1662,7 @@ namespace ts {
|
||||
OctalSpecifier = 1 << 8, // e.g. `0o777`
|
||||
ContainsSeparator = 1 << 9, // e.g. `0b1100_0101`
|
||||
BinaryOrOctalSpecifier = BinarySpecifier | OctalSpecifier,
|
||||
NumericLiteralFlags = Scientific | Octal | HexSpecifier | BinarySpecifier | OctalSpecifier | ContainsSeparator
|
||||
NumericLiteralFlags = Scientific | Octal | HexSpecifier | BinaryOrOctalSpecifier | ContainsSeparator
|
||||
}
|
||||
|
||||
export interface NumericLiteral extends LiteralExpression {
|
||||
@@ -1668,6 +1671,10 @@ namespace ts {
|
||||
numericLiteralFlags: TokenFlags;
|
||||
}
|
||||
|
||||
export interface BigIntLiteral extends LiteralExpression {
|
||||
kind: SyntaxKind.BigIntLiteral;
|
||||
}
|
||||
|
||||
export interface TemplateHead extends LiteralLikeNode {
|
||||
kind: SyntaxKind.TemplateHead;
|
||||
parent: TemplateExpression;
|
||||
@@ -2413,7 +2420,6 @@ namespace ts {
|
||||
|
||||
export interface JSDocTag extends Node {
|
||||
parent: JSDoc | JSDocTypeLiteral;
|
||||
atToken: AtToken;
|
||||
tagName: Identifier;
|
||||
comment?: string;
|
||||
}
|
||||
@@ -2793,7 +2799,7 @@ namespace ts {
|
||||
export interface ParseConfigHost {
|
||||
useCaseSensitiveFileNames: boolean;
|
||||
|
||||
readDirectory(rootDir: string, extensions: ReadonlyArray<string>, excludes: ReadonlyArray<string> | undefined, includes: ReadonlyArray<string>, depth?: number): string[];
|
||||
readDirectory(rootDir: string, extensions: ReadonlyArray<string>, excludes: ReadonlyArray<string> | undefined, includes: ReadonlyArray<string>, depth?: number): ReadonlyArray<string>;
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether the specified path exists and is a file.
|
||||
@@ -2957,16 +2963,10 @@ namespace ts {
|
||||
sourceIndex: number;
|
||||
}
|
||||
|
||||
export interface SourceMapData {
|
||||
sourceMapFilePath: string; // Where the sourcemap file is written
|
||||
jsSourceMappingURL: string; // source map URL written in the .js file
|
||||
sourceMapFile: string; // Source map's file field - .js file name
|
||||
sourceMapSourceRoot: string; // Source map's sourceRoot field - location where the sources will be present if not ""
|
||||
sourceMapSources: string[]; // Source map's sources field - list of sources that can be indexed in this source map
|
||||
sourceMapSourcesContent?: (string | null)[]; // Source map's sourcesContent field - list of the sources' text to be embedded in the source map
|
||||
inputSourceFileNames: string[]; // Input source file (which one can use on program to get the file), 1:1 mapping with the sourceMapSources list
|
||||
sourceMapNames?: string[]; // Source map's names field - list of names that can be indexed in this source map
|
||||
sourceMapMappings: string; // Source map's mapping field - encoded source map spans
|
||||
/* @internal */
|
||||
export interface SourceMapEmitResult {
|
||||
inputSourceFileNames: ReadonlyArray<string>; // Input source file (which one can use on program to get the file), 1:1 mapping with the sourceMap.sources list
|
||||
sourceMap: RawSourceMap;
|
||||
}
|
||||
|
||||
/** Return code used by getEmitOutput function to indicate status of the function */
|
||||
@@ -2988,7 +2988,7 @@ namespace ts {
|
||||
/** Contains declaration emit diagnostics */
|
||||
diagnostics: ReadonlyArray<Diagnostic>;
|
||||
emittedFiles?: string[]; // Array of files the compiler wrote to disk
|
||||
/* @internal */ sourceMaps?: SourceMapData[]; // Array of sourceMapData if compiler emitted sourcemaps
|
||||
/* @internal */ sourceMaps?: SourceMapEmitResult[]; // Array of sourceMapData if compiler emitted sourcemaps
|
||||
/* @internal */ exportedModulesFromDeclarationEmit?: ExportedModulesFromDeclarationEmit;
|
||||
}
|
||||
|
||||
@@ -3079,7 +3079,7 @@ namespace ts {
|
||||
|
||||
getFullyQualifiedName(symbol: Symbol): string;
|
||||
getAugmentedPropertiesOfType(type: Type): Symbol[];
|
||||
getRootSymbols(symbol: Symbol): Symbol[];
|
||||
getRootSymbols(symbol: Symbol): ReadonlyArray<Symbol>;
|
||||
getContextualType(node: Expression): Type | undefined;
|
||||
/* @internal */ getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike): Type | undefined;
|
||||
/* @internal */ getContextualTypeForArgumentAtIndex(call: CallLikeExpression, argIndex: number): Type | undefined;
|
||||
@@ -3173,6 +3173,8 @@ namespace ts {
|
||||
/* @internal */ getTypeCount(): number;
|
||||
|
||||
/* @internal */ isArrayLikeType(type: Type): boolean;
|
||||
/* @internal */ getObjectFlags(type: Type): ObjectFlags;
|
||||
|
||||
/**
|
||||
* True if `contextualType` should not be considered for completions because
|
||||
* e.g. it specifies `kind: "a"` and obj has `kind: "b"`.
|
||||
@@ -3459,6 +3461,7 @@ namespace ts {
|
||||
// of a type, such as the global `Promise` type in lib.d.ts).
|
||||
VoidNullableOrNeverType, // The TypeReferenceNode resolves to a Void-like, Nullable, or Never type.
|
||||
NumberLikeType, // The TypeReferenceNode resolves to a Number-like type.
|
||||
BigIntLikeType, // The TypeReferenceNode resolves to a BigInt-like type.
|
||||
StringLikeType, // The TypeReferenceNode resolves to a String-like type.
|
||||
BooleanType, // The TypeReferenceNode resolves to a Boolean-like type.
|
||||
ArrayLikeType, // The TypeReferenceNode resolves to an Array-like type.
|
||||
@@ -3491,7 +3494,7 @@ namespace ts {
|
||||
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined;
|
||||
createReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
|
||||
createTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
|
||||
createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): Expression;
|
||||
createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, tracker: SymbolTracker): Expression;
|
||||
isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags | undefined, shouldComputeAliasToMarkVisible: boolean): SymbolAccessibilityResult;
|
||||
isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult;
|
||||
// Returns the constant value this property access resolves to, or 'undefined' for a non-constant
|
||||
@@ -3803,29 +3806,27 @@ namespace ts {
|
||||
Number = 1 << 3,
|
||||
Boolean = 1 << 4,
|
||||
Enum = 1 << 5,
|
||||
StringLiteral = 1 << 6,
|
||||
NumberLiteral = 1 << 7,
|
||||
BooleanLiteral = 1 << 8,
|
||||
EnumLiteral = 1 << 9, // Always combined with StringLiteral, NumberLiteral, or Union
|
||||
ESSymbol = 1 << 10, // Type of symbol primitive introduced in ES6
|
||||
UniqueESSymbol = 1 << 11, // unique symbol
|
||||
Void = 1 << 12,
|
||||
Undefined = 1 << 13,
|
||||
Null = 1 << 14,
|
||||
Never = 1 << 15, // Never type
|
||||
TypeParameter = 1 << 16, // Type parameter
|
||||
Object = 1 << 17, // Object type
|
||||
Union = 1 << 18, // Union (T | U)
|
||||
Intersection = 1 << 19, // Intersection (T & U)
|
||||
Index = 1 << 20, // keyof T
|
||||
IndexedAccess = 1 << 21, // T[K]
|
||||
Conditional = 1 << 22, // T extends U ? X : Y
|
||||
Substitution = 1 << 23, // Type parameter substitution
|
||||
NonPrimitive = 1 << 24, // intrinsic object type
|
||||
/* @internal */
|
||||
FreshLiteral = 1 << 25, // Fresh literal or unique type
|
||||
/* @internal */
|
||||
UnionOfPrimitiveTypes = 1 << 26, // Type is union of primitive types
|
||||
BigInt = 1 << 6,
|
||||
StringLiteral = 1 << 7,
|
||||
NumberLiteral = 1 << 8,
|
||||
BooleanLiteral = 1 << 9,
|
||||
EnumLiteral = 1 << 10, // Always combined with StringLiteral, NumberLiteral, or Union
|
||||
BigIntLiteral = 1 << 11,
|
||||
ESSymbol = 1 << 12, // Type of symbol primitive introduced in ES6
|
||||
UniqueESSymbol = 1 << 13, // unique symbol
|
||||
Void = 1 << 14,
|
||||
Undefined = 1 << 15,
|
||||
Null = 1 << 16,
|
||||
Never = 1 << 17, // Never type
|
||||
TypeParameter = 1 << 18, // Type parameter
|
||||
Object = 1 << 19, // Object type
|
||||
Union = 1 << 20, // Union (T | U)
|
||||
Intersection = 1 << 21, // Intersection (T & U)
|
||||
Index = 1 << 22, // keyof T
|
||||
IndexedAccess = 1 << 23, // T[K]
|
||||
Conditional = 1 << 24, // T extends U ? X : Y
|
||||
Substitution = 1 << 25, // Type parameter substitution
|
||||
NonPrimitive = 1 << 26, // intrinsic object type
|
||||
/* @internal */
|
||||
ContainsWideningType = 1 << 27, // Type is or contains undefined or null widening type
|
||||
/* @internal */
|
||||
@@ -3837,26 +3838,27 @@ namespace ts {
|
||||
AnyOrUnknown = Any | Unknown,
|
||||
/* @internal */
|
||||
Nullable = Undefined | Null,
|
||||
Literal = StringLiteral | NumberLiteral | BooleanLiteral,
|
||||
Literal = StringLiteral | NumberLiteral | BigIntLiteral | BooleanLiteral,
|
||||
Unit = Literal | UniqueESSymbol | Nullable,
|
||||
StringOrNumberLiteral = StringLiteral | NumberLiteral,
|
||||
/* @internal */
|
||||
StringOrNumberLiteralOrUnique = StringLiteral | NumberLiteral | UniqueESSymbol,
|
||||
/* @internal */
|
||||
DefinitelyFalsy = StringLiteral | NumberLiteral | BooleanLiteral | Void | Undefined | Null,
|
||||
PossiblyFalsy = DefinitelyFalsy | String | Number | Boolean,
|
||||
DefinitelyFalsy = StringLiteral | NumberLiteral | BigIntLiteral | BooleanLiteral | Void | Undefined | Null,
|
||||
PossiblyFalsy = DefinitelyFalsy | String | Number | BigInt | Boolean,
|
||||
/* @internal */
|
||||
Intrinsic = Any | Unknown | String | Number | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never | NonPrimitive,
|
||||
Intrinsic = Any | Unknown | String | Number | BigInt | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never | NonPrimitive,
|
||||
/* @internal */
|
||||
Primitive = String | Number | Boolean | Enum | EnumLiteral | ESSymbol | Void | Undefined | Null | Literal | UniqueESSymbol,
|
||||
Primitive = String | Number | BigInt | Boolean | Enum | EnumLiteral | ESSymbol | Void | Undefined | Null | Literal | UniqueESSymbol,
|
||||
StringLike = String | StringLiteral,
|
||||
NumberLike = Number | NumberLiteral | Enum,
|
||||
BigIntLike = BigInt | BigIntLiteral,
|
||||
BooleanLike = Boolean | BooleanLiteral,
|
||||
EnumLike = Enum | EnumLiteral,
|
||||
ESSymbolLike = ESSymbol | UniqueESSymbol,
|
||||
VoidLike = Void | Undefined,
|
||||
/* @internal */
|
||||
DisjointDomains = NonPrimitive | StringLike | NumberLike | BooleanLike | ESSymbolLike | VoidLike | Null,
|
||||
DisjointDomains = NonPrimitive | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbolLike | VoidLike | Null,
|
||||
UnionOrIntersection = Union | Intersection,
|
||||
StructuredType = Object | Union | Intersection,
|
||||
TypeVariable = TypeParameter | IndexedAccess,
|
||||
@@ -3867,7 +3869,7 @@ namespace ts {
|
||||
|
||||
// 'Narrowable' types are types where narrowing actually narrows.
|
||||
// This *should* be every type other than null, undefined, void, and never
|
||||
Narrowable = Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive,
|
||||
Narrowable = Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive,
|
||||
NotUnionOrUnit = Any | Unknown | ESSymbol | Object | NonPrimitive,
|
||||
/* @internal */
|
||||
NotPrimitiveUnion = Any | Unknown | Enum | Void | Never | StructuredOrInstantiable,
|
||||
@@ -3924,10 +3926,11 @@ namespace ts {
|
||||
|
||||
// String literal types (TypeFlags.StringLiteral)
|
||||
// Numeric literal types (TypeFlags.NumberLiteral)
|
||||
// BigInt literal types (TypeFlags.BigIntLiteral)
|
||||
export interface LiteralType extends Type {
|
||||
value: string | number; // Value of literal
|
||||
freshType: LiteralType; // Fresh version of type
|
||||
regularType: LiteralType; // Regular version of type
|
||||
value: string | number | PseudoBigInt; // Value of literal
|
||||
freshType: LiteralType; // Fresh version of type
|
||||
regularType: LiteralType; // Regular version of type
|
||||
}
|
||||
|
||||
// Unique symbol types (TypeFlags.UniqueESSymbol)
|
||||
@@ -3943,6 +3946,10 @@ namespace ts {
|
||||
value: number;
|
||||
}
|
||||
|
||||
export interface BigIntLiteralType extends LiteralType {
|
||||
value: PseudoBigInt;
|
||||
}
|
||||
|
||||
// Enum types (TypeFlags.Enum)
|
||||
export interface EnumType extends Type {
|
||||
}
|
||||
@@ -3963,6 +3970,7 @@ namespace ts {
|
||||
JsxAttributes = 1 << 12, // Jsx attributes type
|
||||
MarkerType = 1 << 13, // Marker type used for variance probing
|
||||
JSLiteral = 1 << 14, // Object type declared in JS - disables errors on read/write of nonexisting members
|
||||
FreshLiteral = 1 << 15, // Fresh object literal
|
||||
ClassOrInterface = Class | Interface
|
||||
}
|
||||
|
||||
@@ -4058,7 +4066,10 @@ namespace ts {
|
||||
couldContainTypeVariables: boolean;
|
||||
}
|
||||
|
||||
export interface UnionType extends UnionOrIntersectionType { }
|
||||
export interface UnionType extends UnionOrIntersectionType {
|
||||
/* @internal */
|
||||
primitiveTypesOnly: boolean;
|
||||
}
|
||||
|
||||
export interface IntersectionType extends UnionOrIntersectionType {
|
||||
/* @internal */
|
||||
@@ -4484,6 +4495,7 @@ namespace ts {
|
||||
downlevelIteration?: boolean;
|
||||
emitBOM?: boolean;
|
||||
emitDecoratorMetadata?: boolean;
|
||||
experimentalBigInt?: boolean;
|
||||
experimentalDecorators?: boolean;
|
||||
forceConsistentCasingInFileNames?: boolean;
|
||||
/*@internal*/help?: boolean;
|
||||
@@ -4556,6 +4568,7 @@ namespace ts {
|
||||
/*@internal*/ version?: boolean;
|
||||
/*@internal*/ watch?: boolean;
|
||||
esModuleInterop?: boolean;
|
||||
/* @internal */ showConfig?: boolean;
|
||||
|
||||
[option: string]: CompilerOptionsValue | TsConfigSourceFile | undefined;
|
||||
}
|
||||
@@ -5198,6 +5211,7 @@ namespace ts {
|
||||
IdentifierName, // Emitting an IdentifierName
|
||||
MappedTypeParameter, // Emitting a TypeParameterDeclaration inside of a MappedTypeNode
|
||||
Unspecified, // Emitting an otherwise unspecified node
|
||||
EmbeddedStatement, // Emitting an embedded statement
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -5206,7 +5220,6 @@ namespace ts {
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
getCurrentDirectory(): string;
|
||||
|
||||
/* @internal */
|
||||
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
|
||||
getLibFileFromReference(ref: FileReference): SourceFile | undefined;
|
||||
|
||||
@@ -5368,8 +5381,8 @@ namespace ts {
|
||||
printBundle(bundle: Bundle): string;
|
||||
/*@internal*/ writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined, writer: EmitTextWriter): void;
|
||||
/*@internal*/ writeList<T extends Node>(format: ListFormat, list: NodeArray<T> | undefined, sourceFile: SourceFile | undefined, writer: EmitTextWriter): void;
|
||||
/*@internal*/ writeFile(sourceFile: SourceFile, writer: EmitTextWriter): void;
|
||||
/*@internal*/ writeBundle(bundle: Bundle, writer: EmitTextWriter, info?: BundleInfo): void;
|
||||
/*@internal*/ writeFile(sourceFile: SourceFile, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined): void;
|
||||
/*@internal*/ writeBundle(bundle: Bundle, info: BundleInfo | undefined, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined): void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5449,15 +5462,90 @@ namespace ts {
|
||||
/*@internal*/ target?: CompilerOptions["target"];
|
||||
/*@internal*/ sourceMap?: boolean;
|
||||
/*@internal*/ inlineSourceMap?: boolean;
|
||||
/*@internal*/ inlineSources?: boolean;
|
||||
/*@internal*/ extendedDiagnostics?: boolean;
|
||||
/*@internal*/ onlyPrintJsDocStyle?: boolean;
|
||||
/*@internal*/ neverAsciiEscape?: boolean;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface RawSourceMap {
|
||||
version: 3;
|
||||
file: string;
|
||||
sourceRoot?: string | null;
|
||||
sources: string[];
|
||||
sourcesContent?: (string | null)[] | null;
|
||||
mappings: string;
|
||||
names?: string[] | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a source map.
|
||||
*/
|
||||
/* @internal */
|
||||
export interface SourceMapGenerator {
|
||||
getSources(): ReadonlyArray<string>;
|
||||
/**
|
||||
* Adds a source to the source map.
|
||||
*/
|
||||
addSource(fileName: string): number;
|
||||
/**
|
||||
* Set the content for a source.
|
||||
*/
|
||||
setSourceContent(sourceIndex: number, content: string | null): void;
|
||||
/**
|
||||
* Adds a name.
|
||||
*/
|
||||
addName(name: string): number;
|
||||
/**
|
||||
* Adds a mapping without source information.
|
||||
*/
|
||||
addMapping(generatedLine: number, generatedCharacter: number): void;
|
||||
/**
|
||||
* Adds a mapping with source information.
|
||||
*/
|
||||
addMapping(generatedLine: number, generatedCharacter: number, sourceIndex: number, sourceLine: number, sourceCharacter: number, nameIndex?: number): void;
|
||||
/**
|
||||
* Appends a source map.
|
||||
*/
|
||||
appendSourceMap(generatedLine: number, generatedCharacter: number, sourceMap: RawSourceMap, sourceMapPath: string): void;
|
||||
/**
|
||||
* Gets the source map as a `RawSourceMap` object.
|
||||
*/
|
||||
toJSON(): RawSourceMap;
|
||||
/**
|
||||
* Gets the string representation of the source map.
|
||||
*/
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface DocumentPositionMapperHost {
|
||||
getSourceFileLike(path: Path): SourceFileLike | undefined;
|
||||
getCanonicalFileName(path: string): string;
|
||||
log?(text: string): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps positions between source and generated files.
|
||||
*/
|
||||
/* @internal */
|
||||
export interface DocumentPositionMapper {
|
||||
getSourcePosition(input: DocumentPosition): DocumentPosition;
|
||||
getGeneratedPosition(input: DocumentPosition): DocumentPosition;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface DocumentPosition {
|
||||
fileName: string;
|
||||
pos: number;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface EmitTextWriter extends SymbolWriter {
|
||||
write(s: string): void;
|
||||
writeTextOfNode(text: string, node: Node): void;
|
||||
writeTrailingSemicolon(text: string): void;
|
||||
writeComment(text: string): void;
|
||||
getText(): string;
|
||||
rawWrite(s: string): void;
|
||||
writeLiteral(s: string): void;
|
||||
@@ -5758,4 +5846,10 @@ namespace ts {
|
||||
readonly importModuleSpecifierEnding?: "minimal" | "index" | "js";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
|
||||
/** Represents a bigint literal value without requiring bigint support */
|
||||
export interface PseudoBigInt {
|
||||
negative: boolean;
|
||||
base10Value: string;
|
||||
}
|
||||
}
|
||||
|
||||
+181
-33
@@ -7,7 +7,7 @@ namespace ts {
|
||||
return pathIsRelative(moduleName) || isRootedDiskPath(moduleName);
|
||||
}
|
||||
|
||||
export function sortAndDeduplicateDiagnostics<T extends Diagnostic>(diagnostics: ReadonlyArray<T>): T[] {
|
||||
export function sortAndDeduplicateDiagnostics<T extends Diagnostic>(diagnostics: ReadonlyArray<T>): SortedReadonlyArray<T> {
|
||||
return sortAndDeduplicate<T>(diagnostics, compareDiagnostics);
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,6 @@ namespace ts {
|
||||
getText: () => str,
|
||||
write: writeText,
|
||||
rawWrite: writeText,
|
||||
writeTextOfNode: writeText,
|
||||
writeKeyword: writeText,
|
||||
writeOperator: writeText,
|
||||
writePunctuation: writeText,
|
||||
@@ -73,7 +72,9 @@ namespace ts {
|
||||
writeLiteral: writeText,
|
||||
writeParameter: writeText,
|
||||
writeProperty: writeText,
|
||||
writeSymbol: writeText,
|
||||
writeSymbol: (s, _) => writeText(s),
|
||||
writeTrailingSemicolon: writeText,
|
||||
writeComment: writeText,
|
||||
getTextPos: () => str.length,
|
||||
getLine: () => 0,
|
||||
getColumn: () => 0,
|
||||
@@ -527,7 +528,10 @@ namespace ts {
|
||||
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.
|
||||
if (!nodeIsSynthesized(node) && node.parent && !(isNumericLiteral(node) && node.numericLiteralFlags & TokenFlags.ContainsSeparator)) {
|
||||
if (!nodeIsSynthesized(node) && node.parent && !(
|
||||
(isNumericLiteral(node) && node.numericLiteralFlags & TokenFlags.ContainsSeparator) ||
|
||||
isBigIntLiteral(node)
|
||||
)) {
|
||||
return getSourceTextOfNodeFromSourceFile(sourceFile, node);
|
||||
}
|
||||
|
||||
@@ -554,6 +558,7 @@ namespace ts {
|
||||
case SyntaxKind.TemplateTail:
|
||||
return "}" + escapeText(node.text, CharacterCodes.backtick) + "`";
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.BigIntLiteral:
|
||||
case SyntaxKind.RegularExpressionLiteral:
|
||||
return node.text;
|
||||
}
|
||||
@@ -976,6 +981,7 @@ namespace ts {
|
||||
case SyntaxKind.AnyKeyword:
|
||||
case SyntaxKind.UnknownKeyword:
|
||||
case SyntaxKind.NumberKeyword:
|
||||
case SyntaxKind.BigIntKeyword:
|
||||
case SyntaxKind.StringKeyword:
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
case SyntaxKind.SymbolKeyword:
|
||||
@@ -1599,6 +1605,7 @@ namespace ts {
|
||||
}
|
||||
// falls through
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.BigIntLiteral:
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.ThisKeyword:
|
||||
return isInExpressionContext(node);
|
||||
@@ -2490,6 +2497,7 @@ namespace ts {
|
||||
// export { x as <symbol> } from ...
|
||||
// export = <EntityNameExpression>
|
||||
// export default <EntityNameExpression>
|
||||
// module.exports = <EntityNameExpression>
|
||||
export function isAliasSymbolDeclaration(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.ImportEqualsDeclaration ||
|
||||
node.kind === SyntaxKind.NamespaceExportDeclaration ||
|
||||
@@ -2498,7 +2506,7 @@ namespace ts {
|
||||
node.kind === SyntaxKind.ImportSpecifier ||
|
||||
node.kind === SyntaxKind.ExportSpecifier ||
|
||||
node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(<ExportAssignment>node) ||
|
||||
isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports;
|
||||
isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports && exportAssignmentIsAlias(node);
|
||||
}
|
||||
|
||||
export function exportAssignmentIsAlias(node: ExportAssignment | BinaryExpression): boolean {
|
||||
@@ -2585,6 +2593,10 @@ namespace ts {
|
||||
return token !== undefined && isNonContextualKeyword(token);
|
||||
}
|
||||
|
||||
export function isIdentifierANonContextualKeyword({ originalKeywordKind }: Identifier): boolean {
|
||||
return !!originalKeywordKind && !isContextualKeyword(originalKeywordKind);
|
||||
}
|
||||
|
||||
export type TriviaKind = SyntaxKind.SingleLineCommentTrivia
|
||||
| SyntaxKind.MultiLineCommentTrivia
|
||||
| SyntaxKind.NewLineTrivia
|
||||
@@ -2900,6 +2912,7 @@ namespace ts {
|
||||
case SyntaxKind.TrueKeyword:
|
||||
case SyntaxKind.FalseKeyword:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.BigIntLiteral:
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
@@ -2921,7 +2934,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function getBinaryOperatorPrecedence(kind: SyntaxKind): number {
|
||||
switch (kind) {
|
||||
case SyntaxKind.BarBarToken:
|
||||
@@ -3038,7 +3050,7 @@ namespace ts {
|
||||
return fileDiagnostics.get(fileName) || [];
|
||||
}
|
||||
|
||||
const fileDiags: Diagnostic[] = flatMap(filesWithDiagnostics, f => fileDiagnostics.get(f));
|
||||
const fileDiags: Diagnostic[] = flatMapToMutable(filesWithDiagnostics, f => fileDiagnostics.get(f));
|
||||
if (!nonFileDiagnostics.length) {
|
||||
return fileDiags;
|
||||
}
|
||||
@@ -3190,18 +3202,11 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function writeTextOfNode(text: string, node: Node) {
|
||||
const s = getTextOfNodeFromSourceText(text, node);
|
||||
write(s);
|
||||
updateLineCountAndPosFor(s);
|
||||
}
|
||||
|
||||
reset();
|
||||
|
||||
return {
|
||||
write,
|
||||
rawWrite,
|
||||
writeTextOfNode,
|
||||
writeLiteral,
|
||||
writeLine,
|
||||
increaseIndent: () => { indent++; },
|
||||
@@ -3224,7 +3229,79 @@ namespace ts {
|
||||
writePunctuation: write,
|
||||
writeSpace: write,
|
||||
writeStringLiteral: write,
|
||||
writeSymbol: write
|
||||
writeSymbol: (s, _) => write(s),
|
||||
writeTrailingSemicolon: write,
|
||||
writeComment: write
|
||||
};
|
||||
}
|
||||
|
||||
export function getTrailingSemicolonOmittingWriter(writer: EmitTextWriter): EmitTextWriter {
|
||||
let pendingTrailingSemicolon = false;
|
||||
|
||||
function commitPendingTrailingSemicolon() {
|
||||
if (pendingTrailingSemicolon) {
|
||||
writer.writeTrailingSemicolon(";");
|
||||
pendingTrailingSemicolon = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...writer,
|
||||
writeTrailingSemicolon() {
|
||||
pendingTrailingSemicolon = true;
|
||||
},
|
||||
writeLiteral(s) {
|
||||
commitPendingTrailingSemicolon();
|
||||
writer.writeLiteral(s);
|
||||
},
|
||||
writeStringLiteral(s) {
|
||||
commitPendingTrailingSemicolon();
|
||||
writer.writeStringLiteral(s);
|
||||
},
|
||||
writeSymbol(s, sym) {
|
||||
commitPendingTrailingSemicolon();
|
||||
writer.writeSymbol(s, sym);
|
||||
},
|
||||
writePunctuation(s) {
|
||||
commitPendingTrailingSemicolon();
|
||||
writer.writePunctuation(s);
|
||||
},
|
||||
writeKeyword(s) {
|
||||
commitPendingTrailingSemicolon();
|
||||
writer.writeKeyword(s);
|
||||
},
|
||||
writeOperator(s) {
|
||||
commitPendingTrailingSemicolon();
|
||||
writer.writeOperator(s);
|
||||
},
|
||||
writeParameter(s) {
|
||||
commitPendingTrailingSemicolon();
|
||||
writer.writeParameter(s);
|
||||
},
|
||||
writeSpace(s) {
|
||||
commitPendingTrailingSemicolon();
|
||||
writer.writeSpace(s);
|
||||
},
|
||||
writeProperty(s) {
|
||||
commitPendingTrailingSemicolon();
|
||||
writer.writeProperty(s);
|
||||
},
|
||||
writeComment(s) {
|
||||
commitPendingTrailingSemicolon();
|
||||
writer.writeComment(s);
|
||||
},
|
||||
writeLine() {
|
||||
commitPendingTrailingSemicolon();
|
||||
writer.writeLine();
|
||||
},
|
||||
increaseIndent() {
|
||||
commitPendingTrailingSemicolon();
|
||||
writer.increaseIndent();
|
||||
},
|
||||
decreaseIndent() {
|
||||
commitPendingTrailingSemicolon();
|
||||
writer.decreaseIndent();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3504,13 +3581,13 @@ namespace ts {
|
||||
writeComment: (text: string, lineMap: ReadonlyArray<number>, writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) => void) {
|
||||
if (comments && comments.length > 0) {
|
||||
if (leadingSeparator) {
|
||||
writer.write(" ");
|
||||
writer.writeSpace(" ");
|
||||
}
|
||||
|
||||
let emitInterveningSeparator = false;
|
||||
for (const comment of comments) {
|
||||
if (emitInterveningSeparator) {
|
||||
writer.write(" ");
|
||||
writer.writeSpace(" ");
|
||||
emitInterveningSeparator = false;
|
||||
}
|
||||
|
||||
@@ -3524,7 +3601,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (emitInterveningSeparator && trailingSeparator) {
|
||||
writer.write(" ");
|
||||
writer.writeSpace(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3658,7 +3735,7 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
// Single line comment of style //....
|
||||
writer.write(text.substring(commentPos, commentEnd));
|
||||
writer.writeComment(text.substring(commentPos, commentEnd));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3667,14 +3744,14 @@ namespace ts {
|
||||
const currentLineText = text.substring(pos, end).replace(/^\s+|\s+$/g, "");
|
||||
if (currentLineText) {
|
||||
// trimmed forward and ending spaces text
|
||||
writer.write(currentLineText);
|
||||
writer.writeComment(currentLineText);
|
||||
if (end !== commentEnd) {
|
||||
writer.writeLine();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Empty string - make sure we write empty line
|
||||
writer.writeLiteral(newLine);
|
||||
writer.rawWrite(newLine);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5234,7 +5311,7 @@ namespace ts {
|
||||
}
|
||||
if (isJSDocTypeAlias(node)) {
|
||||
Debug.assert(node.parent.kind === SyntaxKind.JSDocComment);
|
||||
return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined) as ReadonlyArray<TypeParameterDeclaration>;
|
||||
return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined);
|
||||
}
|
||||
if (node.typeParameters) {
|
||||
return node.typeParameters;
|
||||
@@ -5267,6 +5344,10 @@ namespace ts {
|
||||
return node.kind === SyntaxKind.NumericLiteral;
|
||||
}
|
||||
|
||||
export function isBigIntLiteral(node: Node): node is BigIntLiteral {
|
||||
return node.kind === SyntaxKind.BigIntLiteral;
|
||||
}
|
||||
|
||||
export function isStringLiteral(node: Node): node is StringLiteral {
|
||||
return node.kind === SyntaxKind.StringLiteral;
|
||||
}
|
||||
@@ -6210,6 +6291,7 @@ namespace ts {
|
||||
|| kind === SyntaxKind.AnyKeyword
|
||||
|| kind === SyntaxKind.UnknownKeyword
|
||||
|| kind === SyntaxKind.NumberKeyword
|
||||
|| kind === SyntaxKind.BigIntKeyword
|
||||
|| kind === SyntaxKind.ObjectKeyword
|
||||
|| kind === SyntaxKind.BooleanKeyword
|
||||
|| kind === SyntaxKind.StringKeyword
|
||||
@@ -6392,6 +6474,7 @@ namespace ts {
|
||||
case SyntaxKind.Identifier:
|
||||
case SyntaxKind.RegularExpressionLiteral:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.BigIntLiteral:
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.TemplateExpression:
|
||||
@@ -6834,7 +6917,6 @@ namespace ts {
|
||||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
/** @internal */
|
||||
export function isNamedImportsOrExports(node: Node): node is NamedImportsOrExports {
|
||||
return node.kind === SyntaxKind.NamedImports || node.kind === SyntaxKind.NamedExports;
|
||||
}
|
||||
@@ -6898,7 +6980,6 @@ namespace ts {
|
||||
getSourceMapSourceConstructor: () => <any>SourceMapSource,
|
||||
};
|
||||
|
||||
/* @internal */
|
||||
export function formatStringFromArgs(text: string, args: ArrayLike<string>, baseIndex = 0): string {
|
||||
return text.replace(/{(\d+)}/g, (_match, index: string) => Debug.assertDefined(args[+index + baseIndex]));
|
||||
}
|
||||
@@ -6909,7 +6990,6 @@ namespace ts {
|
||||
return localizedDiagnosticMessages && localizedDiagnosticMessages[message.key] || message.message;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage, ...args: (string | number | undefined)[]): DiagnosticWithLocation;
|
||||
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage): DiagnosticWithLocation {
|
||||
Debug.assertGreaterThanOrEqual(start, 0);
|
||||
@@ -6938,7 +7018,6 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function formatMessage(_dummy: any, message: DiagnosticMessage): string {
|
||||
let text = getLocaleSpecificMessage(message);
|
||||
|
||||
@@ -6949,7 +7028,6 @@ namespace ts {
|
||||
return text;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function createCompilerDiagnostic(message: DiagnosticMessage, ...args: (string | number | undefined)[]): Diagnostic;
|
||||
export function createCompilerDiagnostic(message: DiagnosticMessage): Diagnostic {
|
||||
let text = getLocaleSpecificMessage(message);
|
||||
@@ -6970,7 +7048,6 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function createCompilerDiagnosticFromMessageChain(chain: DiagnosticMessageChain): Diagnostic {
|
||||
return {
|
||||
file: undefined,
|
||||
@@ -6983,7 +7060,6 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function chainDiagnosticMessages(details: DiagnosticMessageChain | undefined, message: DiagnosticMessage, ...args: (string | undefined)[]): DiagnosticMessageChain;
|
||||
export function chainDiagnosticMessages(details: DiagnosticMessageChain | undefined, message: DiagnosticMessage): DiagnosticMessageChain {
|
||||
let text = getLocaleSpecificMessage(message);
|
||||
@@ -7015,14 +7091,12 @@ namespace ts {
|
||||
return diagnostic.file ? diagnostic.file.path : undefined;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function compareDiagnostics(d1: Diagnostic, d2: Diagnostic): Comparison {
|
||||
return compareDiagnosticsSkipRelatedInformation(d1, d2) ||
|
||||
compareRelatedInformation(d1, d2) ||
|
||||
Comparison.EqualTo;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function compareDiagnosticsSkipRelatedInformation(d1: Diagnostic, d2: Diagnostic): Comparison {
|
||||
return compareStringsCaseSensitive(getDiagnosticFilePath(d1), getDiagnosticFilePath(d2)) ||
|
||||
compareValues(d1.start, d2.start) ||
|
||||
@@ -7360,7 +7434,6 @@ namespace ts {
|
||||
return rootLength > 0 && rootLength === path.length;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function convertToRelativePath(absoluteOrRelativePath: string, basePath: string, getCanonicalFileName: (path: string) => string): string {
|
||||
return !isRootedDiskPath(absoluteOrRelativePath)
|
||||
? absoluteOrRelativePath
|
||||
@@ -7777,7 +7850,7 @@ namespace ts {
|
||||
return `^(${pattern})${terminator}`;
|
||||
}
|
||||
|
||||
export function getRegularExpressionsForWildcards(specs: ReadonlyArray<string> | undefined, basePath: string, usage: "files" | "directories" | "exclude"): string[] | undefined {
|
||||
export function getRegularExpressionsForWildcards(specs: ReadonlyArray<string> | undefined, basePath: string, usage: "files" | "directories" | "exclude"): ReadonlyArray<string> | undefined {
|
||||
if (specs === undefined || specs.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -8433,4 +8506,79 @@ namespace ts {
|
||||
return got;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a bigint literal string, e.g. `0x1234n`,
|
||||
* to its decimal string representation, e.g. `4660`.
|
||||
*/
|
||||
export function parsePseudoBigInt(stringValue: string): string {
|
||||
let log2Base: number;
|
||||
switch (stringValue.charCodeAt(1)) { // "x" in "0x123"
|
||||
case CharacterCodes.b:
|
||||
case CharacterCodes.B: // 0b or 0B
|
||||
log2Base = 1;
|
||||
break;
|
||||
case CharacterCodes.o:
|
||||
case CharacterCodes.O: // 0o or 0O
|
||||
log2Base = 3;
|
||||
break;
|
||||
case CharacterCodes.x:
|
||||
case CharacterCodes.X: // 0x or 0X
|
||||
log2Base = 4;
|
||||
break;
|
||||
default: // already in decimal; omit trailing "n"
|
||||
const nIndex = stringValue.length - 1;
|
||||
// Skip leading 0s
|
||||
let nonZeroStart = 0;
|
||||
while (stringValue.charCodeAt(nonZeroStart) === CharacterCodes._0) {
|
||||
nonZeroStart++;
|
||||
}
|
||||
return stringValue.slice(nonZeroStart, nIndex) || "0";
|
||||
}
|
||||
|
||||
// Omit leading "0b", "0o", or "0x", and trailing "n"
|
||||
const startIndex = 2, endIndex = stringValue.length - 1;
|
||||
const bitsNeeded = (endIndex - startIndex) * log2Base;
|
||||
// Stores the value specified by the string as a LE array of 16-bit integers
|
||||
// using Uint16 instead of Uint32 so combining steps can use bitwise operators
|
||||
const segments = new Uint16Array((bitsNeeded >>> 4) + (bitsNeeded & 15 ? 1 : 0));
|
||||
// Add the digits, one at a time
|
||||
for (let i = endIndex - 1, bitOffset = 0; i >= startIndex; i--, bitOffset += log2Base) {
|
||||
const segment = bitOffset >>> 4;
|
||||
const digitChar = stringValue.charCodeAt(i);
|
||||
// Find character range: 0-9 < A-F < a-f
|
||||
const digit = digitChar <= CharacterCodes._9
|
||||
? digitChar - CharacterCodes._0
|
||||
: 10 + digitChar -
|
||||
(digitChar <= CharacterCodes.F ? CharacterCodes.A : CharacterCodes.a);
|
||||
const shiftedDigit = digit << (bitOffset & 15);
|
||||
segments[segment] |= shiftedDigit;
|
||||
const residual = shiftedDigit >>> 16;
|
||||
if (residual) segments[segment + 1] |= residual; // overflows segment
|
||||
}
|
||||
// Repeatedly divide segments by 10 and add remainder to base10Value
|
||||
let base10Value = "";
|
||||
let firstNonzeroSegment = segments.length - 1;
|
||||
let segmentsRemaining = true;
|
||||
while (segmentsRemaining) {
|
||||
let mod10 = 0;
|
||||
segmentsRemaining = false;
|
||||
for (let segment = firstNonzeroSegment; segment >= 0; segment--) {
|
||||
const newSegment = mod10 << 16 | segments[segment];
|
||||
const segmentValue = (newSegment / 10) | 0;
|
||||
segments[segment] = segmentValue;
|
||||
mod10 = newSegment - segmentValue * 10;
|
||||
if (segmentValue && !segmentsRemaining) {
|
||||
firstNonzeroSegment = segment;
|
||||
segmentsRemaining = true;
|
||||
}
|
||||
}
|
||||
base10Value = mod10 + base10Value;
|
||||
}
|
||||
return base10Value;
|
||||
}
|
||||
|
||||
export function pseudoBigIntToString({negative, base10Value}: PseudoBigInt): string {
|
||||
return (negative && base10Value !== "0" ? "-" : "") + base10Value;
|
||||
}
|
||||
}
|
||||
|
||||
+29
-12
@@ -43,7 +43,6 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export const screenStartingMessageCodes: number[] = [
|
||||
Diagnostics.Starting_compilation_in_watch_mode.code,
|
||||
Diagnostics.File_change_detected_Starting_incremental_compilation.code,
|
||||
@@ -106,6 +105,22 @@ namespace ts {
|
||||
|
||||
export type ReportEmitErrorSummary = (errorCount: number) => void;
|
||||
|
||||
export function getErrorCountForSummary(diagnostics: ReadonlyArray<Diagnostic>) {
|
||||
return countWhere(diagnostics, diagnostic => diagnostic.category === DiagnosticCategory.Error);
|
||||
}
|
||||
|
||||
export function getWatchErrorSummaryDiagnosticMessage(errorCount: number) {
|
||||
return errorCount === 1 ?
|
||||
Diagnostics.Found_1_error_Watching_for_file_changes :
|
||||
Diagnostics.Found_0_errors_Watching_for_file_changes;
|
||||
}
|
||||
|
||||
export function getErrorSummaryText(errorCount: number, newLine: string) {
|
||||
if (errorCount === 0) return "";
|
||||
const d = createCompilerDiagnostic(errorCount === 1 ? Diagnostics.Found_1_error : Diagnostics.Found_0_errors, errorCount);
|
||||
return `${newLine}${flattenDiagnosticMessageText(d.messageText, newLine)}${newLine}${newLine}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper that emit files, report diagnostics and lists emitted and/or source files depending on compiler options
|
||||
*/
|
||||
@@ -151,7 +166,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (reportSummary) {
|
||||
reportSummary(diagnostics.filter(diagnostic => diagnostic.category === DiagnosticCategory.Error).length);
|
||||
reportSummary(getErrorCountForSummary(diagnostics));
|
||||
}
|
||||
|
||||
if (emitSkipped && diagnostics.length > 0) {
|
||||
@@ -227,16 +242,16 @@ namespace ts {
|
||||
const compilerOptions = builderProgram.getCompilerOptions();
|
||||
const newLine = getNewLineCharacter(compilerOptions, () => system.newLine);
|
||||
|
||||
const reportSummary = (errorCount: number) => {
|
||||
if (errorCount === 1) {
|
||||
onWatchStatusChange!(createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes, errorCount), newLine, compilerOptions);
|
||||
}
|
||||
else {
|
||||
onWatchStatusChange!(createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errorCount, errorCount), newLine, compilerOptions);
|
||||
}
|
||||
};
|
||||
|
||||
emitFilesAndReportErrors(builderProgram, reportDiagnostic, writeFileName, reportSummary);
|
||||
emitFilesAndReportErrors(
|
||||
builderProgram,
|
||||
reportDiagnostic,
|
||||
writeFileName,
|
||||
errorCount => onWatchStatusChange!(
|
||||
createCompilerDiagnostic(getWatchErrorSummaryDiagnosticMessage(errorCount), errorCount),
|
||||
newLine,
|
||||
compilerOptions
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -938,6 +953,8 @@ namespace ts {
|
||||
}
|
||||
nextSourceFileVersion(fileOrDirectoryPath);
|
||||
|
||||
if (isPathInNodeModulesStartingWithDot(fileOrDirectoryPath)) return;
|
||||
|
||||
// If the the added or created file or directory is not supported file name, ignore the file
|
||||
// But when watched directory is added/removed, we need to reload the file list
|
||||
if (fileOrDirectoryPath !== directory && hasExtension(fileOrDirectoryPath) && !isSupportedSourceFileName(fileOrDirectory, compilerOptions)) {
|
||||
|
||||
@@ -694,6 +694,10 @@ namespace ts.server {
|
||||
return response.body!.map(entry => this.decodeSpan(entry, fileName)); // TODO: GH#18217
|
||||
}
|
||||
|
||||
configurePlugin(pluginName: string, configuration: any): void {
|
||||
this.processRequest<protocol.ConfigurePluginRequest>("configurePlugin", { pluginName, configuration });
|
||||
}
|
||||
|
||||
getIndentationAtPosition(_fileName: string, _position: number, _options: EditorOptions): number {
|
||||
return notImplemented();
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace compiler {
|
||||
private _inputs: documents.TextDocument[] = [];
|
||||
private _inputsAndOutputs: collections.SortedMap<string, CompilationOutput>;
|
||||
|
||||
constructor(host: fakes.CompilerHost, options: ts.CompilerOptions, program: ts.Program | undefined, result: ts.EmitResult | undefined, diagnostics: ts.Diagnostic[]) {
|
||||
constructor(host: fakes.CompilerHost, options: ts.CompilerOptions, program: ts.Program | undefined, result: ts.EmitResult | undefined, diagnostics: ReadonlyArray<ts.Diagnostic>) {
|
||||
this.host = host;
|
||||
this.program = program;
|
||||
this.result = result;
|
||||
|
||||
+571
-401
File diff suppressed because it is too large
Load Diff
@@ -490,7 +490,7 @@ namespace Harness {
|
||||
getExecutingFilePath(): string;
|
||||
getWorkspaceRoot(): string;
|
||||
exit(exitCode?: number): void;
|
||||
readDirectory(path: string, extension?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
|
||||
readDirectory(path: string, extension?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): ReadonlyArray<string>;
|
||||
getAccessibleFileSystemEntries(dirname: string): ts.FileSystemEntries;
|
||||
tryEnableSourceMapsForHost?(): void;
|
||||
getEnvironmentVariable?(name: string): string;
|
||||
@@ -1325,6 +1325,9 @@ namespace Harness {
|
||||
const [, content] = value;
|
||||
outputLines += content;
|
||||
}
|
||||
if (pretty) {
|
||||
outputLines += ts.getErrorSummaryText(ts.getErrorCountForSummary(diagnostics), IO.newLine());
|
||||
}
|
||||
return outputLines;
|
||||
}
|
||||
|
||||
@@ -1643,6 +1646,7 @@ namespace Harness {
|
||||
else {
|
||||
sourceMapCode = "";
|
||||
result.maps.forEach(sourceMap => {
|
||||
if (sourceMapCode) sourceMapCode += "\r\n";
|
||||
sourceMapCode += fileOutput(sourceMap, harnessSettings);
|
||||
});
|
||||
}
|
||||
@@ -1668,6 +1672,9 @@ namespace Harness {
|
||||
|
||||
let jsCode = "";
|
||||
result.js.forEach(file => {
|
||||
if (jsCode.length && jsCode.charCodeAt(jsCode.length - 1) !== ts.CharacterCodes.lineFeed) {
|
||||
jsCode += "\r\n";
|
||||
}
|
||||
jsCode += fileOutput(file, harnessSettings);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
namespace Harness.LanguageService {
|
||||
|
||||
export function makeDefaultProxy(info: ts.server.PluginCreateInfo): ts.LanguageService {
|
||||
// tslint:disable-next-line:no-null-keyword
|
||||
const proxy = Object.create(/*prototype*/ null);
|
||||
const langSvc: any = info.languageService;
|
||||
for (const k of Object.keys(langSvc)) {
|
||||
// tslint:disable-next-line only-arrow-functions
|
||||
proxy[k] = function () {
|
||||
return langSvc[k].apply(langSvc, arguments);
|
||||
};
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
|
||||
export class ScriptInfo {
|
||||
public version = 1;
|
||||
public editRanges: { length: number; textChangeRange: ts.TextChangeRange; }[] = [];
|
||||
@@ -833,25 +847,42 @@ namespace Harness.LanguageService {
|
||||
error: undefined
|
||||
};
|
||||
|
||||
// Accepts configurations
|
||||
case "configurable-diagnostic-adder":
|
||||
let customMessage = "default message";
|
||||
return {
|
||||
module: () => ({
|
||||
create(info: ts.server.PluginCreateInfo) {
|
||||
customMessage = info.config.message;
|
||||
const proxy = makeDefaultProxy(info);
|
||||
proxy.getSemanticDiagnostics = filename => {
|
||||
const prev = info.languageService.getSemanticDiagnostics(filename);
|
||||
const sourceFile: ts.SourceFile = info.project.getSourceFile(ts.toPath(filename, /*basePath*/ undefined, ts.createGetCanonicalFileName(info.serverHost.useCaseSensitiveFileNames)))!;
|
||||
prev.push({
|
||||
category: ts.DiagnosticCategory.Error,
|
||||
file: sourceFile,
|
||||
code: 9999,
|
||||
length: 3,
|
||||
messageText: customMessage,
|
||||
start: 0
|
||||
});
|
||||
return prev;
|
||||
};
|
||||
return proxy;
|
||||
},
|
||||
onConfigurationChanged(config: any) {
|
||||
customMessage = config.message;
|
||||
}
|
||||
}),
|
||||
error: undefined
|
||||
};
|
||||
|
||||
default:
|
||||
return {
|
||||
module: undefined,
|
||||
error: new Error("Could not resolve module")
|
||||
};
|
||||
}
|
||||
|
||||
function makeDefaultProxy(info: ts.server.PluginCreateInfo): ts.LanguageService {
|
||||
// tslint:disable-next-line:no-null-keyword
|
||||
const proxy = Object.create(/*prototype*/ null);
|
||||
const langSvc: any = info.languageService;
|
||||
for (const k of Object.keys(langSvc)) {
|
||||
// tslint:disable-next-line only-arrow-functions
|
||||
proxy[k] = function () {
|
||||
return langSvc[k].apply(langSvc, arguments);
|
||||
};
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,44 +1,36 @@
|
||||
namespace Harness.SourceMapRecorder {
|
||||
|
||||
interface SourceMapSpanWithDecodeErrors {
|
||||
sourceMapSpan: ts.SourceMapSpan;
|
||||
sourceMapSpan: ts.Mapping;
|
||||
decodeErrors: string[] | undefined;
|
||||
}
|
||||
|
||||
namespace SourceMapDecoder {
|
||||
let sourceMapMappings: string;
|
||||
let decodingIndex: number;
|
||||
let mappings: ts.sourcemaps.MappingsDecoder | undefined;
|
||||
let mappings: ts.MappingsDecoder | undefined;
|
||||
|
||||
export interface DecodedMapping {
|
||||
sourceMapSpan: ts.SourceMapSpan;
|
||||
sourceMapSpan: ts.Mapping;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export function initializeSourceMapDecoding(sourceMapData: ts.SourceMapData) {
|
||||
export function initializeSourceMapDecoding(sourceMapData: ts.SourceMapEmitResult) {
|
||||
decodingIndex = 0;
|
||||
sourceMapMappings = sourceMapData.sourceMapMappings;
|
||||
mappings = ts.sourcemaps.decodeMappings({
|
||||
version: 3,
|
||||
file: sourceMapData.sourceMapFile,
|
||||
sources: sourceMapData.sourceMapSources,
|
||||
sourceRoot: sourceMapData.sourceMapSourceRoot,
|
||||
sourcesContent: sourceMapData.sourceMapSourcesContent,
|
||||
mappings: sourceMapData.sourceMapMappings,
|
||||
names: sourceMapData.sourceMapNames
|
||||
});
|
||||
sourceMapMappings = sourceMapData.sourceMap.mappings;
|
||||
mappings = ts.decodeMappings(sourceMapData.sourceMap.mappings);
|
||||
}
|
||||
|
||||
export function decodeNextEncodedSourceMapSpan(): DecodedMapping {
|
||||
if (!mappings) return ts.Debug.fail("not initialized");
|
||||
const result = mappings.next();
|
||||
if (result.done) return { error: mappings.error || "No encoded entry found", sourceMapSpan: mappings.lastSpan };
|
||||
if (result.done) return { error: mappings.error || "No encoded entry found", sourceMapSpan: mappings.state };
|
||||
return { sourceMapSpan: result.value };
|
||||
}
|
||||
|
||||
export function hasCompletedDecoding() {
|
||||
if (!mappings) return ts.Debug.fail("not initialized");
|
||||
return mappings.decodingIndex === sourceMapMappings.length;
|
||||
return mappings.pos === sourceMapMappings.length;
|
||||
}
|
||||
|
||||
export function getRemainingDecodeString() {
|
||||
@@ -49,7 +41,7 @@ namespace Harness.SourceMapRecorder {
|
||||
namespace SourceMapSpanWriter {
|
||||
let sourceMapRecorder: Compiler.WriterAggregator;
|
||||
let sourceMapSources: string[];
|
||||
let sourceMapNames: string[] | undefined;
|
||||
let sourceMapNames: string[] | null | undefined;
|
||||
|
||||
let jsFile: documents.TextDocument;
|
||||
let jsLineMap: ReadonlyArray<number>;
|
||||
@@ -61,10 +53,10 @@ namespace Harness.SourceMapRecorder {
|
||||
let nextJsLineToWrite: number;
|
||||
let spanMarkerContinues: boolean;
|
||||
|
||||
export function initializeSourceMapSpanWriter(sourceMapRecordWriter: Compiler.WriterAggregator, sourceMapData: ts.SourceMapData, currentJsFile: documents.TextDocument) {
|
||||
export function initializeSourceMapSpanWriter(sourceMapRecordWriter: Compiler.WriterAggregator, sourceMapData: ts.SourceMapEmitResult, currentJsFile: documents.TextDocument) {
|
||||
sourceMapRecorder = sourceMapRecordWriter;
|
||||
sourceMapSources = sourceMapData.sourceMapSources;
|
||||
sourceMapNames = sourceMapData.sourceMapNames;
|
||||
sourceMapSources = sourceMapData.sourceMap.sources;
|
||||
sourceMapNames = sourceMapData.sourceMap.names;
|
||||
|
||||
jsFile = currentJsFile;
|
||||
jsLineMap = jsFile.lineStarts;
|
||||
@@ -75,43 +67,39 @@ namespace Harness.SourceMapRecorder {
|
||||
spanMarkerContinues = false;
|
||||
|
||||
SourceMapDecoder.initializeSourceMapDecoding(sourceMapData);
|
||||
|
||||
sourceMapRecorder.WriteLine("===================================================================");
|
||||
sourceMapRecorder.WriteLine("JsFile: " + sourceMapData.sourceMapFile);
|
||||
sourceMapRecorder.WriteLine("mapUrl: " + sourceMapData.jsSourceMappingURL);
|
||||
sourceMapRecorder.WriteLine("sourceRoot: " + sourceMapData.sourceMapSourceRoot);
|
||||
sourceMapRecorder.WriteLine("sources: " + sourceMapData.sourceMapSources);
|
||||
if (sourceMapData.sourceMapSourcesContent) {
|
||||
sourceMapRecorder.WriteLine("sourcesContent: " + JSON.stringify(sourceMapData.sourceMapSourcesContent));
|
||||
sourceMapRecorder.WriteLine("JsFile: " + sourceMapData.sourceMap.file);
|
||||
sourceMapRecorder.WriteLine("mapUrl: " + ts.tryGetSourceMappingURL(jsFile.text, jsLineMap));
|
||||
sourceMapRecorder.WriteLine("sourceRoot: " + sourceMapData.sourceMap.sourceRoot);
|
||||
sourceMapRecorder.WriteLine("sources: " + sourceMapData.sourceMap.sources);
|
||||
if (sourceMapData.sourceMap.sourcesContent) {
|
||||
sourceMapRecorder.WriteLine("sourcesContent: " + JSON.stringify(sourceMapData.sourceMap.sourcesContent));
|
||||
}
|
||||
sourceMapRecorder.WriteLine("===================================================================");
|
||||
}
|
||||
|
||||
function getSourceMapSpanString(mapEntry: ts.SourceMapSpan, getAbsentNameIndex?: boolean) {
|
||||
let mapString = "Emitted(" + (mapEntry.emittedLine + 1) + ", " + (mapEntry.emittedColumn + 1) + ") Source(" + (mapEntry.sourceLine + 1) + ", " + (mapEntry.sourceColumn + 1) + ") + SourceIndex(" + mapEntry.sourceIndex + ")";
|
||||
if (mapEntry.nameIndex! >= 0 && mapEntry.nameIndex! < sourceMapNames!.length) {
|
||||
mapString += " name (" + sourceMapNames![mapEntry.nameIndex!] + ")";
|
||||
}
|
||||
else {
|
||||
if ((mapEntry.nameIndex && mapEntry.nameIndex !== -1) || getAbsentNameIndex) {
|
||||
mapString += " nameIndex (" + mapEntry.nameIndex + ")";
|
||||
function getSourceMapSpanString(mapEntry: ts.Mapping, getAbsentNameIndex?: boolean) {
|
||||
let mapString = "Emitted(" + (mapEntry.generatedLine + 1) + ", " + (mapEntry.generatedCharacter + 1) + ")";
|
||||
if (ts.isSourceMapping(mapEntry)) {
|
||||
mapString += " Source(" + (mapEntry.sourceLine + 1) + ", " + (mapEntry.sourceCharacter + 1) + ") + SourceIndex(" + mapEntry.sourceIndex + ")";
|
||||
if (mapEntry.nameIndex! >= 0 && mapEntry.nameIndex! < sourceMapNames!.length) {
|
||||
mapString += " name (" + sourceMapNames![mapEntry.nameIndex!] + ")";
|
||||
}
|
||||
else {
|
||||
if ((mapEntry.nameIndex && mapEntry.nameIndex !== -1) || getAbsentNameIndex) {
|
||||
mapString += " nameIndex (" + mapEntry.nameIndex + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mapString;
|
||||
}
|
||||
|
||||
export function recordSourceMapSpan(sourceMapSpan: ts.SourceMapSpan) {
|
||||
export function recordSourceMapSpan(sourceMapSpan: ts.Mapping) {
|
||||
// verify the decoded span is same as the new span
|
||||
const decodeResult = SourceMapDecoder.decodeNextEncodedSourceMapSpan();
|
||||
let decodeErrors: string[] | undefined;
|
||||
if (typeof decodeResult.error === "string"
|
||||
|| decodeResult.sourceMapSpan.emittedLine !== sourceMapSpan.emittedLine
|
||||
|| decodeResult.sourceMapSpan.emittedColumn !== sourceMapSpan.emittedColumn
|
||||
|| decodeResult.sourceMapSpan.sourceLine !== sourceMapSpan.sourceLine
|
||||
|| decodeResult.sourceMapSpan.sourceColumn !== sourceMapSpan.sourceColumn
|
||||
|| decodeResult.sourceMapSpan.sourceIndex !== sourceMapSpan.sourceIndex
|
||||
|| decodeResult.sourceMapSpan.nameIndex !== sourceMapSpan.nameIndex) {
|
||||
if (typeof decodeResult.error === "string" || !ts.sameMapping(decodeResult.sourceMapSpan, sourceMapSpan)) {
|
||||
if (decodeResult.error) {
|
||||
decodeErrors = ["!!^^ !!^^ There was decoding error in the sourcemap at this location: " + decodeResult.error];
|
||||
}
|
||||
@@ -121,7 +109,7 @@ namespace Harness.SourceMapRecorder {
|
||||
decodeErrors.push("!!^^ !!^^ Decoded span from sourcemap's mappings entry: " + getSourceMapSpanString(decodeResult.sourceMapSpan, /*getAbsentNameIndex*/ true) + " Span encoded by the emitter:" + getSourceMapSpanString(sourceMapSpan, /*getAbsentNameIndex*/ true));
|
||||
}
|
||||
|
||||
if (spansOnSingleLine.length && spansOnSingleLine[0].sourceMapSpan.emittedLine !== sourceMapSpan.emittedLine) {
|
||||
if (spansOnSingleLine.length && spansOnSingleLine[0].sourceMapSpan.generatedLine !== sourceMapSpan.generatedLine) {
|
||||
// On different line from the one that we have been recording till now,
|
||||
writeRecordedSpans();
|
||||
spansOnSingleLine = [];
|
||||
@@ -129,14 +117,21 @@ namespace Harness.SourceMapRecorder {
|
||||
spansOnSingleLine.push({ sourceMapSpan, decodeErrors });
|
||||
}
|
||||
|
||||
export function recordNewSourceFileSpan(sourceMapSpan: ts.SourceMapSpan, newSourceFileCode: string) {
|
||||
assert.isTrue(spansOnSingleLine.length === 0 || spansOnSingleLine[0].sourceMapSpan.emittedLine !== sourceMapSpan.emittedLine, "new file source map span should be on new line. We currently handle only that scenario");
|
||||
export function recordNewSourceFileSpan(sourceMapSpan: ts.Mapping, newSourceFileCode: string) {
|
||||
let continuesLine = false;
|
||||
if (spansOnSingleLine.length > 0 && spansOnSingleLine[0].sourceMapSpan.generatedCharacter === sourceMapSpan.generatedLine) {
|
||||
writeRecordedSpans();
|
||||
spansOnSingleLine = [];
|
||||
nextJsLineToWrite--; // walk back one line to reprint the line
|
||||
continuesLine = true;
|
||||
}
|
||||
|
||||
recordSourceMapSpan(sourceMapSpan);
|
||||
|
||||
assert.isTrue(spansOnSingleLine.length === 1);
|
||||
sourceMapRecorder.WriteLine("-------------------------------------------------------------------");
|
||||
sourceMapRecorder.WriteLine("emittedFile:" + jsFile.file);
|
||||
sourceMapRecorder.WriteLine("sourceFile:" + sourceMapSources[spansOnSingleLine[0].sourceMapSpan.sourceIndex]);
|
||||
sourceMapRecorder.WriteLine("emittedFile:" + jsFile.file + (continuesLine ? ` (${sourceMapSpan.generatedLine + 1}, ${sourceMapSpan.generatedCharacter + 1})` : ""));
|
||||
sourceMapRecorder.WriteLine("sourceFile:" + sourceMapSources[spansOnSingleLine[0].sourceMapSpan.sourceIndex!]);
|
||||
sourceMapRecorder.WriteLine("-------------------------------------------------------------------");
|
||||
|
||||
tsLineMap = ts.computeLineStarts(newSourceFileCode);
|
||||
@@ -195,7 +190,7 @@ namespace Harness.SourceMapRecorder {
|
||||
prevEmittedCol = 0;
|
||||
for (let i = 0; i < spansOnSingleLine.length; i++) {
|
||||
fn(spansOnSingleLine[i], i);
|
||||
prevEmittedCol = spansOnSingleLine[i].sourceMapSpan.emittedColumn;
|
||||
prevEmittedCol = spansOnSingleLine[i].sourceMapSpan.generatedCharacter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +201,7 @@ namespace Harness.SourceMapRecorder {
|
||||
}
|
||||
}
|
||||
|
||||
function writeSourceMapMarker(currentSpan: SourceMapSpanWithDecodeErrors, index: number, endColumn = currentSpan.sourceMapSpan.emittedColumn, endContinues = false) {
|
||||
function writeSourceMapMarker(currentSpan: SourceMapSpanWithDecodeErrors, index: number, endColumn = currentSpan.sourceMapSpan.generatedCharacter, endContinues = false) {
|
||||
const markerId = getMarkerId(index);
|
||||
markerIds.push(markerId);
|
||||
|
||||
@@ -223,7 +218,7 @@ namespace Harness.SourceMapRecorder {
|
||||
}
|
||||
|
||||
function writeSourceMapSourceText(currentSpan: SourceMapSpanWithDecodeErrors, index: number) {
|
||||
const sourcePos = tsLineMap[currentSpan.sourceMapSpan.sourceLine] + (currentSpan.sourceMapSpan.sourceColumn);
|
||||
const sourcePos = tsLineMap[currentSpan.sourceMapSpan.sourceLine!] + (currentSpan.sourceMapSpan.sourceCharacter!);
|
||||
let sourceText = "";
|
||||
if (prevWrittenSourcePos < sourcePos) {
|
||||
// Position that goes forward, get text
|
||||
@@ -255,7 +250,7 @@ namespace Harness.SourceMapRecorder {
|
||||
}
|
||||
|
||||
if (spansOnSingleLine.length) {
|
||||
const currentJsLine = spansOnSingleLine[0].sourceMapSpan.emittedLine;
|
||||
const currentJsLine = spansOnSingleLine[0].sourceMapSpan.generatedLine;
|
||||
|
||||
// Write js line
|
||||
writeJsFileLines(currentJsLine + 1);
|
||||
@@ -280,14 +275,14 @@ namespace Harness.SourceMapRecorder {
|
||||
}
|
||||
}
|
||||
|
||||
export function getSourceMapRecord(sourceMapDataList: ReadonlyArray<ts.SourceMapData>, program: ts.Program, jsFiles: ReadonlyArray<documents.TextDocument>, declarationFiles: ReadonlyArray<documents.TextDocument>) {
|
||||
export function getSourceMapRecord(sourceMapDataList: ReadonlyArray<ts.SourceMapEmitResult>, program: ts.Program, jsFiles: ReadonlyArray<documents.TextDocument>, declarationFiles: ReadonlyArray<documents.TextDocument>) {
|
||||
const sourceMapRecorder = new Compiler.WriterAggregator();
|
||||
|
||||
for (let i = 0; i < sourceMapDataList.length; i++) {
|
||||
const sourceMapData = sourceMapDataList[i];
|
||||
let prevSourceFile: ts.SourceFile | undefined;
|
||||
let currentFile: documents.TextDocument;
|
||||
if (ts.endsWith(sourceMapData.sourceMapFile, ts.Extension.Dts)) {
|
||||
if (ts.endsWith(sourceMapData.sourceMap.file, ts.Extension.Dts)) {
|
||||
if (sourceMapDataList.length > jsFiles.length) {
|
||||
currentFile = declarationFiles[Math.floor(i / 2)]; // When both kinds of source map are present, they alternate js/dts
|
||||
}
|
||||
@@ -305,11 +300,15 @@ namespace Harness.SourceMapRecorder {
|
||||
}
|
||||
|
||||
SourceMapSpanWriter.initializeSourceMapSpanWriter(sourceMapRecorder, sourceMapData, currentFile);
|
||||
const mapper = ts.sourcemaps.decodeMappings({ mappings: sourceMapData.sourceMapMappings, sources: sourceMapData.sourceMapSources });
|
||||
const mapper = ts.decodeMappings(sourceMapData.sourceMap.mappings);
|
||||
for (let { value: decodedSourceMapping, done } = mapper.next(); !done; { value: decodedSourceMapping, done } = mapper.next()) {
|
||||
const currentSourceFile = program.getSourceFile(sourceMapData.inputSourceFileNames[decodedSourceMapping.sourceIndex])!;
|
||||
const currentSourceFile = ts.isSourceMapping(decodedSourceMapping)
|
||||
? program.getSourceFile(sourceMapData.inputSourceFileNames[decodedSourceMapping.sourceIndex])
|
||||
: undefined;
|
||||
if (currentSourceFile !== prevSourceFile) {
|
||||
SourceMapSpanWriter.recordNewSourceFileSpan(decodedSourceMapping, currentSourceFile.text);
|
||||
if (currentSourceFile) {
|
||||
SourceMapSpanWriter.recordNewSourceFileSpan(decodedSourceMapping, currentSourceFile.text);
|
||||
}
|
||||
prevSourceFile = currentSourceFile;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -128,7 +128,7 @@ interface Array<T> {}`
|
||||
return s && isString((<FsSymLink>s).symLink);
|
||||
}
|
||||
|
||||
function invokeWatcherCallbacks<T>(callbacks: T[], invokeCallback: (cb: T) => void): void {
|
||||
function invokeWatcherCallbacks<T>(callbacks: ReadonlyArray<T> | undefined, invokeCallback: (cb: T) => void): void {
|
||||
if (callbacks) {
|
||||
// The array copy is made to ensure that even if one of the callback removes the callbacks,
|
||||
// we dont miss any callbacks following it
|
||||
@@ -341,6 +341,7 @@ interface Array<T> {}`
|
||||
private readonly currentDirectory: string;
|
||||
private readonly dynamicPriorityWatchFile: HostWatchFile | undefined;
|
||||
private readonly customRecursiveWatchDirectory: HostWatchDirectory | undefined;
|
||||
public require: (initialPath: string, moduleName: string) => server.RequireResult;
|
||||
|
||||
constructor(public withSafeList: boolean, public useCaseSensitiveFileNames: boolean, executingFilePath: string, currentDirectory: string, fileOrFolderorSymLinkList: ReadonlyArray<FileOrFolderOrSymLink>, public readonly newLine = "\n", public readonly useWindowsStylePath?: boolean, private readonly environmentVariables?: Map<string>) {
|
||||
this.getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
@@ -587,8 +588,8 @@ interface Array<T> {}`
|
||||
}
|
||||
this.invokeFileWatcher(fileOrDirectory.fullPath, FileWatcherEventKind.Created);
|
||||
if (isFsFolder(fileOrDirectory)) {
|
||||
this.invokeDirectoryWatcher(fileOrDirectory.fullPath, "");
|
||||
this.invokeWatchedDirectoriesRecursiveCallback(fileOrDirectory.fullPath, "");
|
||||
this.invokeDirectoryWatcher(fileOrDirectory.fullPath, fileOrDirectory.fullPath);
|
||||
this.invokeWatchedDirectoriesRecursiveCallback(fileOrDirectory.fullPath, fileOrDirectory.fullPath);
|
||||
}
|
||||
this.invokeDirectoryWatcher(folder.fullPath, fileOrDirectory.fullPath);
|
||||
}
|
||||
@@ -650,15 +651,15 @@ interface Array<T> {}`
|
||||
|
||||
// For overriding the methods
|
||||
invokeWatchedDirectoriesCallback(folderFullPath: string, relativePath: string) {
|
||||
invokeWatcherCallbacks(this.watchedDirectories.get(this.toPath(folderFullPath))!, cb => this.directoryCallback(cb, relativePath));
|
||||
invokeWatcherCallbacks(this.watchedDirectories.get(this.toPath(folderFullPath)), cb => this.directoryCallback(cb, relativePath));
|
||||
}
|
||||
|
||||
invokeWatchedDirectoriesRecursiveCallback(folderFullPath: string, relativePath: string) {
|
||||
invokeWatcherCallbacks(this.watchedDirectoriesRecursive.get(this.toPath(folderFullPath))!, cb => this.directoryCallback(cb, relativePath));
|
||||
invokeWatcherCallbacks(this.watchedDirectoriesRecursive.get(this.toPath(folderFullPath)), cb => this.directoryCallback(cb, relativePath));
|
||||
}
|
||||
|
||||
private invokeFileWatcher(fileFullPath: string, eventKind: FileWatcherEventKind, useFileNameInCallback?: boolean) {
|
||||
invokeWatcherCallbacks(this.watchedFiles.get(this.toPath(fileFullPath))!, ({ cb, fileName }) => cb(useFileNameInCallback ? fileName : fileFullPath, eventKind));
|
||||
invokeWatcherCallbacks(this.watchedFiles.get(this.toPath(fileFullPath)), ({ cb, fileName }) => cb(useFileNameInCallback ? fileName : fileFullPath, eventKind));
|
||||
}
|
||||
|
||||
private getRelativePathToDirectory(directoryFullPath: string, fileFullPath: string) {
|
||||
@@ -988,4 +989,16 @@ interface Array<T> {}`
|
||||
return this.environmentVariables && this.environmentVariables.get(name) || "";
|
||||
}
|
||||
}
|
||||
|
||||
export const tsbuildProjectsLocation = "/user/username/projects";
|
||||
export function getTsBuildProjectFilePath(project: string, file: string) {
|
||||
return `${tsbuildProjectsLocation}/${project}/${file}`;
|
||||
}
|
||||
|
||||
export function getTsBuildProjectFile(project: string, file: string): File {
|
||||
return {
|
||||
path: getTsBuildProjectFilePath(project, file),
|
||||
content: Harness.IO.readFile(`${Harness.IO.getWorkspaceRoot()}/tests/projects/${project}/${file}`)!
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,13 +24,11 @@ namespace ts.JsTyping {
|
||||
version: Version;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isTypingUpToDate(cachedTyping: CachedTyping, availableTypingVersions: MapLike<string>) {
|
||||
const availableVersion = new Version(getProperty(availableTypingVersions, `ts${versionMajorMinor}`) || getProperty(availableTypingVersions, "latest")!);
|
||||
return availableVersion.compareTo(cachedTyping.version) <= 0;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export const nodeCoreModuleList: ReadonlyArray<string> = [
|
||||
"assert",
|
||||
"async_hooks",
|
||||
@@ -70,7 +68,6 @@ namespace ts.JsTyping {
|
||||
"zlib"
|
||||
];
|
||||
|
||||
/* @internal */
|
||||
export const nodeCoreModules = arrayToSet(nodeCoreModuleList);
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,7 +34,6 @@ namespace ts.server {
|
||||
: undefined;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function nowString() {
|
||||
// E.g. "12:34:56.789"
|
||||
const d = new Date();
|
||||
|
||||
@@ -8,10 +8,6 @@ declare namespace ts.server {
|
||||
export type EventEndInstallTypes = "event::endInstallTypes";
|
||||
export type EventInitializationFailed = "event::initializationFailed";
|
||||
|
||||
export interface SortedReadonlyArray<T> extends ReadonlyArray<T> {
|
||||
" __sortedArrayBrand": any;
|
||||
}
|
||||
|
||||
export interface TypingInstallerResponse {
|
||||
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | ActionValueInspected | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
|
||||
}
|
||||
|
||||
Vendored
+493
-281
File diff suppressed because it is too large
Load Diff
Vendored
+11
-11
@@ -63,7 +63,7 @@ interface SymbolConstructor {
|
||||
}
|
||||
|
||||
interface Symbol {
|
||||
readonly [Symbol.toStringTag]: "Symbol";
|
||||
readonly [Symbol.toStringTag]: string;
|
||||
}
|
||||
|
||||
interface Array<T> {
|
||||
@@ -107,23 +107,23 @@ interface Date {
|
||||
}
|
||||
|
||||
interface Map<K, V> {
|
||||
readonly [Symbol.toStringTag]: "Map";
|
||||
readonly [Symbol.toStringTag]: string;
|
||||
}
|
||||
|
||||
interface WeakMap<K extends object, V> {
|
||||
readonly [Symbol.toStringTag]: "WeakMap";
|
||||
readonly [Symbol.toStringTag]: string;
|
||||
}
|
||||
|
||||
interface Set<T> {
|
||||
readonly [Symbol.toStringTag]: "Set";
|
||||
readonly [Symbol.toStringTag]: string;
|
||||
}
|
||||
|
||||
interface WeakSet<T extends object> {
|
||||
readonly [Symbol.toStringTag]: "WeakSet";
|
||||
readonly [Symbol.toStringTag]: string;
|
||||
}
|
||||
|
||||
interface JSON {
|
||||
readonly [Symbol.toStringTag]: "JSON";
|
||||
readonly [Symbol.toStringTag]: string;
|
||||
}
|
||||
|
||||
interface Function {
|
||||
@@ -138,15 +138,15 @@ interface Function {
|
||||
}
|
||||
|
||||
interface GeneratorFunction {
|
||||
readonly [Symbol.toStringTag]: "GeneratorFunction";
|
||||
readonly [Symbol.toStringTag]: string;
|
||||
}
|
||||
|
||||
interface Math {
|
||||
readonly [Symbol.toStringTag]: "Math";
|
||||
readonly [Symbol.toStringTag]: string;
|
||||
}
|
||||
|
||||
interface Promise<T> {
|
||||
readonly [Symbol.toStringTag]: "Promise";
|
||||
readonly [Symbol.toStringTag]: string;
|
||||
}
|
||||
|
||||
interface PromiseConstructor {
|
||||
@@ -241,11 +241,11 @@ interface String {
|
||||
}
|
||||
|
||||
interface ArrayBuffer {
|
||||
readonly [Symbol.toStringTag]: "ArrayBuffer";
|
||||
readonly [Symbol.toStringTag]: string;
|
||||
}
|
||||
|
||||
interface DataView {
|
||||
readonly [Symbol.toStringTag]: "DataView";
|
||||
readonly [Symbol.toStringTag]: string;
|
||||
}
|
||||
|
||||
interface Int8Array {
|
||||
|
||||
Vendored
+609
@@ -0,0 +1,609 @@
|
||||
interface BigInt {
|
||||
/**
|
||||
* Returns a string representation of an object.
|
||||
* @param radix Specifies a radix for converting numeric values to strings.
|
||||
*/
|
||||
toString(radix?: number): string;
|
||||
|
||||
/** Returns a string representation appropriate to the host environment's current locale. */
|
||||
toLocaleString(): string;
|
||||
|
||||
/** Returns the primitive value of the specified object. */
|
||||
valueOf(): bigint;
|
||||
|
||||
readonly [Symbol.toStringTag]: "BigInt";
|
||||
}
|
||||
|
||||
interface BigIntConstructor {
|
||||
(value?: any): bigint;
|
||||
readonly prototype: BigInt;
|
||||
|
||||
/**
|
||||
* Interprets the low bits of a BigInt as a 2's-complement signed integer.
|
||||
* All higher bits are discarded.
|
||||
* @param bits The number of low bits to use
|
||||
* @param int The BigInt whose bits to extract
|
||||
*/
|
||||
asIntN(bits: number, int: bigint): bigint;
|
||||
/**
|
||||
* Interprets the low bits of a BigInt as an unsigned integer.
|
||||
* All higher bits are discarded.
|
||||
* @param bits The number of low bits to use
|
||||
* @param int The BigInt whose bits to extract
|
||||
*/
|
||||
asUintN(bits: number, int: bigint): bigint;
|
||||
}
|
||||
|
||||
declare const BigInt: BigIntConstructor;
|
||||
|
||||
/**
|
||||
* A typed array of 64-bit signed integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated, an exception is raised.
|
||||
*/
|
||||
interface BigInt64Array {
|
||||
/** The size in bytes of each element in the array. */
|
||||
readonly BYTES_PER_ELEMENT: number;
|
||||
|
||||
/** The ArrayBuffer instance referenced by the array. */
|
||||
readonly buffer: ArrayBufferLike;
|
||||
|
||||
/** The length in bytes of the array. */
|
||||
readonly byteLength: number;
|
||||
|
||||
/** The offset in bytes of the array. */
|
||||
readonly byteOffset: number;
|
||||
|
||||
/**
|
||||
* Returns the this object after copying a section of the array identified by start and end
|
||||
* to the same array starting at position target
|
||||
* @param target If target is negative, it is treated as length+target where length is the
|
||||
* length of the array.
|
||||
* @param start If start is negative, it is treated as length+start. If end is negative, it
|
||||
* is treated as length+end.
|
||||
* @param end If not specified, length of the this object is used as its default value.
|
||||
*/
|
||||
copyWithin(target: number, start: number, end?: number): this;
|
||||
|
||||
/** Yields index, value pairs for every entry in the array. */
|
||||
entries(): IterableIterator<[number, bigint]>;
|
||||
|
||||
/**
|
||||
* Determines whether all the members of an array satisfy the specified test.
|
||||
* @param callbackfn A function that accepts up to three arguments. The every method calls
|
||||
* the callbackfn function for each element in the array until the callbackfn returns false,
|
||||
* or until the end of the array.
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
every(callbackfn: (value: bigint, index: number, array: BigInt64Array) => boolean, thisArg?: any): boolean;
|
||||
|
||||
/**
|
||||
* Returns the this object after filling the section identified by start and end with value
|
||||
* @param value value to fill array section with
|
||||
* @param start index to start filling the array at. If start is negative, it is treated as
|
||||
* length+start where length is the length of the array.
|
||||
* @param end index to stop filling the array at. If end is negative, it is treated as
|
||||
* length+end.
|
||||
*/
|
||||
fill(value: bigint, start?: number, end?: number): this;
|
||||
|
||||
/**
|
||||
* Returns the elements of an array that meet the condition specified in a callback function.
|
||||
* @param callbackfn A function that accepts up to three arguments. The filter method calls
|
||||
* the callbackfn function one time for each element in the array.
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
filter(callbackfn: (value: bigint, index: number, array: BigInt64Array) => any, thisArg?: any): BigInt64Array;
|
||||
|
||||
/**
|
||||
* Returns the value of the first element in the array where predicate is true, and undefined
|
||||
* otherwise.
|
||||
* @param predicate find calls predicate once for each element of the array, in ascending
|
||||
* order, until it finds one where predicate returns true. If such an element is found, find
|
||||
* immediately returns that element value. Otherwise, find returns undefined.
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: bigint, index: number, array: BigInt64Array) => boolean, thisArg?: any): bigint | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
* otherwise.
|
||||
* @param predicate find calls predicate once for each element of the array, in ascending
|
||||
* order, until it finds one where predicate returns true. If such an element is found,
|
||||
* findIndex immediately returns that element index. Otherwise, findIndex returns -1.
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: bigint, index: number, array: BigInt64Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
* @param callbackfn A function that accepts up to three arguments. forEach calls the
|
||||
* callbackfn function one time for each element in the array.
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
forEach(callbackfn: (value: bigint, index: number, array: BigInt64Array) => void, thisArg?: any): void;
|
||||
|
||||
/**
|
||||
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||
* @param searchElement The element to search for.
|
||||
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||
*/
|
||||
includes(searchElement: bigint, fromIndex?: number): boolean;
|
||||
|
||||
/**
|
||||
* Returns the index of the first occurrence of a value in an array.
|
||||
* @param searchElement The value to locate in the array.
|
||||
* @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the
|
||||
* search starts at index 0.
|
||||
*/
|
||||
indexOf(searchElement: bigint, fromIndex?: number): number;
|
||||
|
||||
/**
|
||||
* Adds all the elements of an array separated by the specified separator string.
|
||||
* @param separator A string used to separate one element of an array from the next in the
|
||||
* resulting String. If omitted, the array elements are separated with a comma.
|
||||
*/
|
||||
join(separator?: string): string;
|
||||
|
||||
/** Yields each index in the array. */
|
||||
keys(): IterableIterator<number>;
|
||||
|
||||
/**
|
||||
* Returns the index of the last occurrence of a value in an array.
|
||||
* @param searchElement The value to locate in the array.
|
||||
* @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the
|
||||
* search starts at index 0.
|
||||
*/
|
||||
lastIndexOf(searchElement: bigint, fromIndex?: number): number;
|
||||
|
||||
/** The length of the array. */
|
||||
readonly length: number;
|
||||
|
||||
/**
|
||||
* Calls a defined callback function on each element of an array, and returns an array that
|
||||
* contains the results.
|
||||
* @param callbackfn A function that accepts up to three arguments. The map method calls the
|
||||
* callbackfn function one time for each element in the array.
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
map(callbackfn: (value: bigint, index: number, array: BigInt64Array) => bigint, thisArg?: any): BigInt64Array;
|
||||
|
||||
/**
|
||||
* Calls the specified callback function for all the elements in an array. The return value of
|
||||
* the callback function is the accumulated result, and is provided as an argument in the next
|
||||
* call to the callback function.
|
||||
* @param callbackfn A function that accepts up to four arguments. The reduce method calls the
|
||||
* callbackfn function one time for each element in the array.
|
||||
* @param initialValue If initialValue is specified, it is used as the initial value to start
|
||||
* the accumulation. The first call to the callbackfn function provides this value as an argument
|
||||
* instead of an array value.
|
||||
*/
|
||||
reduce(callbackfn: (previousValue: bigint, currentValue: bigint, currentIndex: number, array: BigInt64Array) => bigint): bigint;
|
||||
|
||||
/**
|
||||
* Calls the specified callback function for all the elements in an array. The return value of
|
||||
* the callback function is the accumulated result, and is provided as an argument in the next
|
||||
* call to the callback function.
|
||||
* @param callbackfn A function that accepts up to four arguments. The reduce method calls the
|
||||
* callbackfn function one time for each element in the array.
|
||||
* @param initialValue If initialValue is specified, it is used as the initial value to start
|
||||
* the accumulation. The first call to the callbackfn function provides this value as an argument
|
||||
* instead of an array value.
|
||||
*/
|
||||
reduce<U>(callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigInt64Array) => U, initialValue: U): U;
|
||||
|
||||
/**
|
||||
* Calls the specified callback function for all the elements in an array, in descending order.
|
||||
* The return value of the callback function is the accumulated result, and is provided as an
|
||||
* argument in the next call to the callback function.
|
||||
* @param callbackfn A function that accepts up to four arguments. The reduceRight method calls
|
||||
* the callbackfn function one time for each element in the array.
|
||||
* @param initialValue If initialValue is specified, it is used as the initial value to start
|
||||
* the accumulation. The first call to the callbackfn function provides this value as an
|
||||
* argument instead of an array value.
|
||||
*/
|
||||
reduceRight(callbackfn: (previousValue: bigint, currentValue: bigint, currentIndex: number, array: BigInt64Array) => bigint): bigint;
|
||||
|
||||
/**
|
||||
* Calls the specified callback function for all the elements in an array, in descending order.
|
||||
* The return value of the callback function is the accumulated result, and is provided as an
|
||||
* argument in the next call to the callback function.
|
||||
* @param callbackfn A function that accepts up to four arguments. The reduceRight method calls
|
||||
* the callbackfn function one time for each element in the array.
|
||||
* @param initialValue If initialValue is specified, it is used as the initial value to start
|
||||
* the accumulation. The first call to the callbackfn function provides this value as an argument
|
||||
* instead of an array value.
|
||||
*/
|
||||
reduceRight<U>(callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigInt64Array) => U, initialValue: U): U;
|
||||
|
||||
/** Reverses the elements in the array. */
|
||||
reverse(): this;
|
||||
|
||||
/**
|
||||
* Sets a value or an array of values.
|
||||
* @param array A typed or untyped array of values to set.
|
||||
* @param offset The index in the current array at which the values are to be written.
|
||||
*/
|
||||
set(array: ArrayLike<bigint>, offset?: number): void;
|
||||
|
||||
/**
|
||||
* Returns a section of an array.
|
||||
* @param start The beginning of the specified portion of the array.
|
||||
* @param end The end of the specified portion of the array.
|
||||
*/
|
||||
slice(start?: number, end?: number): BigInt64Array;
|
||||
|
||||
/**
|
||||
* Determines whether the specified callback function returns true for any element of an array.
|
||||
* @param callbackfn A function that accepts up to three arguments. The some method calls the
|
||||
* callbackfn function for each element in the array until the callbackfn returns true, or until
|
||||
* the end of the array.
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
some(callbackfn: (value: bigint, index: number, array: BigInt64Array) => boolean, thisArg?: any): boolean;
|
||||
|
||||
/**
|
||||
* Sorts the array.
|
||||
* @param compareFn The function used to determine the order of the elements. If omitted, the elements are sorted in ascending order.
|
||||
*/
|
||||
sort(compareFn?: (a: bigint, b: bigint) => number | bigint): this;
|
||||
|
||||
/**
|
||||
* Gets a new BigInt64Array view of the ArrayBuffer store for this array, referencing the elements
|
||||
* at begin, inclusive, up to end, exclusive.
|
||||
* @param begin The index of the beginning of the array.
|
||||
* @param end The index of the end of the array.
|
||||
*/
|
||||
subarray(begin: number, end?: number): BigInt64Array;
|
||||
|
||||
/** Converts the array to a string by using the current locale. */
|
||||
toLocaleString(): string;
|
||||
|
||||
/** Returns a string representation of the array. */
|
||||
toString(): string;
|
||||
|
||||
/** Yields each value in the array. */
|
||||
values(): IterableIterator<bigint>;
|
||||
|
||||
[Symbol.iterator](): IterableIterator<bigint>;
|
||||
|
||||
readonly [Symbol.toStringTag]: "BigInt64Array";
|
||||
|
||||
[index: number]: bigint;
|
||||
}
|
||||
|
||||
interface BigInt64ArrayConstructor {
|
||||
readonly prototype: BigInt64Array;
|
||||
new(length?: number): BigInt64Array;
|
||||
new(array: Iterable<bigint>): BigInt64Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): BigInt64Array;
|
||||
|
||||
/** The size in bytes of each element in the array. */
|
||||
readonly BYTES_PER_ELEMENT: number;
|
||||
|
||||
/**
|
||||
* Returns a new array from a set of elements.
|
||||
* @param items A set of elements to include in the new array object.
|
||||
*/
|
||||
of(...items: bigint[]): BigInt64Array;
|
||||
|
||||
/**
|
||||
* Creates an array from an array-like or iterable object.
|
||||
* @param arrayLike An array-like or iterable object to convert to an array.
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: ArrayLike<bigint>): BigInt64Array;
|
||||
from<U>(arrayLike: ArrayLike<U>, mapfn: (v: U, k: number) => bigint, thisArg?: any): BigInt64Array;
|
||||
}
|
||||
|
||||
declare const BigInt64Array: BigInt64ArrayConstructor;
|
||||
|
||||
/**
|
||||
* A typed array of 64-bit unsigned integer values. The contents are initialized to 0. If the
|
||||
* requested number of bytes could not be allocated, an exception is raised.
|
||||
*/
|
||||
interface BigUint64Array {
|
||||
/** The size in bytes of each element in the array. */
|
||||
readonly BYTES_PER_ELEMENT: number;
|
||||
|
||||
/** The ArrayBuffer instance referenced by the array. */
|
||||
readonly buffer: ArrayBufferLike;
|
||||
|
||||
/** The length in bytes of the array. */
|
||||
readonly byteLength: number;
|
||||
|
||||
/** The offset in bytes of the array. */
|
||||
readonly byteOffset: number;
|
||||
|
||||
/**
|
||||
* Returns the this object after copying a section of the array identified by start and end
|
||||
* to the same array starting at position target
|
||||
* @param target If target is negative, it is treated as length+target where length is the
|
||||
* length of the array.
|
||||
* @param start If start is negative, it is treated as length+start. If end is negative, it
|
||||
* is treated as length+end.
|
||||
* @param end If not specified, length of the this object is used as its default value.
|
||||
*/
|
||||
copyWithin(target: number, start: number, end?: number): this;
|
||||
|
||||
/** Yields index, value pairs for every entry in the array. */
|
||||
entries(): IterableIterator<[number, bigint]>;
|
||||
|
||||
/**
|
||||
* Determines whether all the members of an array satisfy the specified test.
|
||||
* @param callbackfn A function that accepts up to three arguments. The every method calls
|
||||
* the callbackfn function for each element in the array until the callbackfn returns false,
|
||||
* or until the end of the array.
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
every(callbackfn: (value: bigint, index: number, array: BigUint64Array) => boolean, thisArg?: any): boolean;
|
||||
|
||||
/**
|
||||
* Returns the this object after filling the section identified by start and end with value
|
||||
* @param value value to fill array section with
|
||||
* @param start index to start filling the array at. If start is negative, it is treated as
|
||||
* length+start where length is the length of the array.
|
||||
* @param end index to stop filling the array at. If end is negative, it is treated as
|
||||
* length+end.
|
||||
*/
|
||||
fill(value: bigint, start?: number, end?: number): this;
|
||||
|
||||
/**
|
||||
* Returns the elements of an array that meet the condition specified in a callback function.
|
||||
* @param callbackfn A function that accepts up to three arguments. The filter method calls
|
||||
* the callbackfn function one time for each element in the array.
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
filter(callbackfn: (value: bigint, index: number, array: BigUint64Array) => any, thisArg?: any): BigUint64Array;
|
||||
|
||||
/**
|
||||
* Returns the value of the first element in the array where predicate is true, and undefined
|
||||
* otherwise.
|
||||
* @param predicate find calls predicate once for each element of the array, in ascending
|
||||
* order, until it finds one where predicate returns true. If such an element is found, find
|
||||
* immediately returns that element value. Otherwise, find returns undefined.
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: bigint, index: number, array: BigUint64Array) => boolean, thisArg?: any): bigint | undefined;
|
||||
|
||||
/**
|
||||
* Returns the index of the first element in the array where predicate is true, and -1
|
||||
* otherwise.
|
||||
* @param predicate find calls predicate once for each element of the array, in ascending
|
||||
* order, until it finds one where predicate returns true. If such an element is found,
|
||||
* findIndex immediately returns that element index. Otherwise, findIndex returns -1.
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
findIndex(predicate: (value: bigint, index: number, array: BigUint64Array) => boolean, thisArg?: any): number;
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
* @param callbackfn A function that accepts up to three arguments. forEach calls the
|
||||
* callbackfn function one time for each element in the array.
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
forEach(callbackfn: (value: bigint, index: number, array: BigUint64Array) => void, thisArg?: any): void;
|
||||
|
||||
/**
|
||||
* Determines whether an array includes a certain element, returning true or false as appropriate.
|
||||
* @param searchElement The element to search for.
|
||||
* @param fromIndex The position in this array at which to begin searching for searchElement.
|
||||
*/
|
||||
includes(searchElement: bigint, fromIndex?: number): boolean;
|
||||
|
||||
/**
|
||||
* Returns the index of the first occurrence of a value in an array.
|
||||
* @param searchElement The value to locate in the array.
|
||||
* @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the
|
||||
* search starts at index 0.
|
||||
*/
|
||||
indexOf(searchElement: bigint, fromIndex?: number): number;
|
||||
|
||||
/**
|
||||
* Adds all the elements of an array separated by the specified separator string.
|
||||
* @param separator A string used to separate one element of an array from the next in the
|
||||
* resulting String. If omitted, the array elements are separated with a comma.
|
||||
*/
|
||||
join(separator?: string): string;
|
||||
|
||||
/** Yields each index in the array. */
|
||||
keys(): IterableIterator<number>;
|
||||
|
||||
/**
|
||||
* Returns the index of the last occurrence of a value in an array.
|
||||
* @param searchElement The value to locate in the array.
|
||||
* @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the
|
||||
* search starts at index 0.
|
||||
*/
|
||||
lastIndexOf(searchElement: bigint, fromIndex?: number): number;
|
||||
|
||||
/** The length of the array. */
|
||||
readonly length: number;
|
||||
|
||||
/**
|
||||
* Calls a defined callback function on each element of an array, and returns an array that
|
||||
* contains the results.
|
||||
* @param callbackfn A function that accepts up to three arguments. The map method calls the
|
||||
* callbackfn function one time for each element in the array.
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
map(callbackfn: (value: bigint, index: number, array: BigUint64Array) => bigint, thisArg?: any): BigUint64Array;
|
||||
|
||||
/**
|
||||
* Calls the specified callback function for all the elements in an array. The return value of
|
||||
* the callback function is the accumulated result, and is provided as an argument in the next
|
||||
* call to the callback function.
|
||||
* @param callbackfn A function that accepts up to four arguments. The reduce method calls the
|
||||
* callbackfn function one time for each element in the array.
|
||||
* @param initialValue If initialValue is specified, it is used as the initial value to start
|
||||
* the accumulation. The first call to the callbackfn function provides this value as an argument
|
||||
* instead of an array value.
|
||||
*/
|
||||
reduce(callbackfn: (previousValue: bigint, currentValue: bigint, currentIndex: number, array: BigUint64Array) => bigint): bigint;
|
||||
|
||||
/**
|
||||
* Calls the specified callback function for all the elements in an array. The return value of
|
||||
* the callback function is the accumulated result, and is provided as an argument in the next
|
||||
* call to the callback function.
|
||||
* @param callbackfn A function that accepts up to four arguments. The reduce method calls the
|
||||
* callbackfn function one time for each element in the array.
|
||||
* @param initialValue If initialValue is specified, it is used as the initial value to start
|
||||
* the accumulation. The first call to the callbackfn function provides this value as an argument
|
||||
* instead of an array value.
|
||||
*/
|
||||
reduce<U>(callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigUint64Array) => U, initialValue: U): U;
|
||||
|
||||
/**
|
||||
* Calls the specified callback function for all the elements in an array, in descending order.
|
||||
* The return value of the callback function is the accumulated result, and is provided as an
|
||||
* argument in the next call to the callback function.
|
||||
* @param callbackfn A function that accepts up to four arguments. The reduceRight method calls
|
||||
* the callbackfn function one time for each element in the array.
|
||||
* @param initialValue If initialValue is specified, it is used as the initial value to start
|
||||
* the accumulation. The first call to the callbackfn function provides this value as an
|
||||
* argument instead of an array value.
|
||||
*/
|
||||
reduceRight(callbackfn: (previousValue: bigint, currentValue: bigint, currentIndex: number, array: BigUint64Array) => bigint): bigint;
|
||||
|
||||
/**
|
||||
* Calls the specified callback function for all the elements in an array, in descending order.
|
||||
* The return value of the callback function is the accumulated result, and is provided as an
|
||||
* argument in the next call to the callback function.
|
||||
* @param callbackfn A function that accepts up to four arguments. The reduceRight method calls
|
||||
* the callbackfn function one time for each element in the array.
|
||||
* @param initialValue If initialValue is specified, it is used as the initial value to start
|
||||
* the accumulation. The first call to the callbackfn function provides this value as an argument
|
||||
* instead of an array value.
|
||||
*/
|
||||
reduceRight<U>(callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigUint64Array) => U, initialValue: U): U;
|
||||
|
||||
/** Reverses the elements in the array. */
|
||||
reverse(): this;
|
||||
|
||||
/**
|
||||
* Sets a value or an array of values.
|
||||
* @param array A typed or untyped array of values to set.
|
||||
* @param offset The index in the current array at which the values are to be written.
|
||||
*/
|
||||
set(array: ArrayLike<bigint>, offset?: number): void;
|
||||
|
||||
/**
|
||||
* Returns a section of an array.
|
||||
* @param start The beginning of the specified portion of the array.
|
||||
* @param end The end of the specified portion of the array.
|
||||
*/
|
||||
slice(start?: number, end?: number): BigUint64Array;
|
||||
|
||||
/**
|
||||
* Determines whether the specified callback function returns true for any element of an array.
|
||||
* @param callbackfn A function that accepts up to three arguments. The some method calls the
|
||||
* callbackfn function for each element in the array until the callbackfn returns true, or until
|
||||
* the end of the array.
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function.
|
||||
* If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
some(callbackfn: (value: bigint, index: number, array: BigUint64Array) => boolean, thisArg?: any): boolean;
|
||||
|
||||
/**
|
||||
* Sorts the array.
|
||||
* @param compareFn The function used to determine the order of the elements. If omitted, the elements are sorted in ascending order.
|
||||
*/
|
||||
sort(compareFn?: (a: bigint, b: bigint) => number | bigint): this;
|
||||
|
||||
/**
|
||||
* Gets a new BigUint64Array view of the ArrayBuffer store for this array, referencing the elements
|
||||
* at begin, inclusive, up to end, exclusive.
|
||||
* @param begin The index of the beginning of the array.
|
||||
* @param end The index of the end of the array.
|
||||
*/
|
||||
subarray(begin: number, end?: number): BigUint64Array;
|
||||
|
||||
/** Converts the array to a string by using the current locale. */
|
||||
toLocaleString(): string;
|
||||
|
||||
/** Returns a string representation of the array. */
|
||||
toString(): string;
|
||||
|
||||
/** Yields each value in the array. */
|
||||
values(): IterableIterator<bigint>;
|
||||
|
||||
[Symbol.iterator](): IterableIterator<bigint>;
|
||||
|
||||
readonly [Symbol.toStringTag]: "BigUint64Array";
|
||||
|
||||
[index: number]: bigint;
|
||||
}
|
||||
|
||||
interface BigUint64ArrayConstructor {
|
||||
readonly prototype: BigUint64Array;
|
||||
new(length?: number): BigUint64Array;
|
||||
new(array: Iterable<bigint>): BigUint64Array;
|
||||
new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): BigUint64Array;
|
||||
|
||||
/** The size in bytes of each element in the array. */
|
||||
readonly BYTES_PER_ELEMENT: number;
|
||||
|
||||
/**
|
||||
* Returns a new array from a set of elements.
|
||||
* @param items A set of elements to include in the new array object.
|
||||
*/
|
||||
of(...items: bigint[]): BigUint64Array;
|
||||
|
||||
/**
|
||||
* Creates an array from an array-like or iterable object.
|
||||
* @param arrayLike An array-like or iterable object to convert to an array.
|
||||
* @param mapfn A mapping function to call on every element of the array.
|
||||
* @param thisArg Value of 'this' used to invoke the mapfn.
|
||||
*/
|
||||
from(arrayLike: ArrayLike<bigint>): BigUint64Array;
|
||||
from<U>(arrayLike: ArrayLike<U>, mapfn: (v: U, k: number) => bigint, thisArg?: any): BigUint64Array;
|
||||
}
|
||||
|
||||
declare const BigUint64Array: BigUint64ArrayConstructor;
|
||||
|
||||
interface DataView {
|
||||
/**
|
||||
* Gets the BigInt64 value at the specified byte offset from the start of the view. There is
|
||||
* no alignment constraint; multi-byte values may be fetched from any offset.
|
||||
* @param byteOffset The place in the buffer at which the value should be retrieved.
|
||||
*/
|
||||
getBigInt64(byteOffset: number, littleEndian?: boolean): bigint;
|
||||
|
||||
/**
|
||||
* Gets the BigUint64 value at the specified byte offset from the start of the view. There is
|
||||
* no alignment constraint; multi-byte values may be fetched from any offset.
|
||||
* @param byteOffset The place in the buffer at which the value should be retrieved.
|
||||
*/
|
||||
getBigUint64(byteOffset: number, littleEndian?: boolean): bigint;
|
||||
|
||||
/**
|
||||
* Stores a BigInt64 value at the specified byte offset from the start of the view.
|
||||
* @param byteOffset The place in the buffer at which the value should be set.
|
||||
* @param value The value to set.
|
||||
* @param littleEndian If false or undefined, a big-endian value should be written,
|
||||
* otherwise a little-endian value should be written.
|
||||
*/
|
||||
setBigInt64(byteOffset: number, value: bigint, littleEndian?: boolean): void;
|
||||
|
||||
/**
|
||||
* Stores a BigUint64 value at the specified byte offset from the start of the view.
|
||||
* @param byteOffset The place in the buffer at which the value should be set.
|
||||
* @param value The value to set.
|
||||
* @param littleEndian If false or undefined, a big-endian value should be written,
|
||||
* otherwise a little-endian value should be written.
|
||||
*/
|
||||
setBigUint64(byteOffset: number, value: bigint, littleEndian?: boolean): void;
|
||||
}
|
||||
Vendored
+1
@@ -1,5 +1,6 @@
|
||||
/// <reference lib="es2018" />
|
||||
/// <reference lib="esnext.asynciterable" />
|
||||
/// <reference lib="esnext.array" />
|
||||
/// <reference lib="esnext.bigint" />
|
||||
/// <reference lib="esnext.symbol" />
|
||||
/// <reference lib="esnext.intl" />
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"es2018.intl",
|
||||
"esnext.asynciterable",
|
||||
"esnext.array",
|
||||
"esnext.bigint",
|
||||
"esnext.symbol",
|
||||
"esnext.intl",
|
||||
// Default libraries
|
||||
|
||||
Vendored
+1268
-10
File diff suppressed because it is too large
Load Diff
@@ -3766,7 +3766,7 @@
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Extract constant]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[解壓縮常數]]></Val>
|
||||
<Val><![CDATA[擷取常數]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
@@ -3775,7 +3775,7 @@
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Extract function]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[解壓縮函式]]></Val>
|
||||
<Val><![CDATA[擷取函式]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -509,6 +509,8 @@ namespace ts.server {
|
||||
public readonly globalPlugins: ReadonlyArray<string>;
|
||||
public readonly pluginProbeLocations: ReadonlyArray<string>;
|
||||
public readonly allowLocalPluginLoads: boolean;
|
||||
private currentPluginConfigOverrides: Map<any> | undefined;
|
||||
|
||||
public readonly typesMapLocation: string | undefined;
|
||||
|
||||
public readonly syntaxOnly?: boolean;
|
||||
@@ -833,9 +835,9 @@ namespace ts.server {
|
||||
|
||||
/* @internal */
|
||||
private forEachProject(cb: (project: Project) => void) {
|
||||
this.inferredProjects.forEach(cb);
|
||||
this.configuredProjects.forEach(cb);
|
||||
this.externalProjects.forEach(cb);
|
||||
this.configuredProjects.forEach(cb);
|
||||
this.inferredProjects.forEach(cb);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -865,7 +867,7 @@ namespace ts.server {
|
||||
private doEnsureDefaultProjectForFile(fileName: NormalizedPath): Project {
|
||||
this.ensureProjectStructuresUptoDate();
|
||||
const scriptInfo = this.getScriptInfoForNormalizedPath(fileName);
|
||||
return scriptInfo ? scriptInfo.getDefaultProject() : Errors.ThrowNoProject();
|
||||
return scriptInfo ? scriptInfo.getDefaultProject() : (this.logErrorForScriptInfoNotFound(fileName), Errors.ThrowNoProject());
|
||||
}
|
||||
|
||||
getScriptInfoEnsuringProjectsUptoDate(uncheckedFileName: string) {
|
||||
@@ -962,6 +964,7 @@ namespace ts.server {
|
||||
fileOrDirectory => {
|
||||
const fileOrDirectoryPath = this.toPath(fileOrDirectory);
|
||||
project.getCachedDirectoryStructureHost().addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath);
|
||||
if (isPathInNodeModulesStartingWithDot(fileOrDirectoryPath)) return;
|
||||
const configFilename = project.getConfigFilePath();
|
||||
|
||||
// If the the added or created file or directory is not supported file name, ignore the file
|
||||
@@ -1034,11 +1037,12 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
private removeProject(project: Project) {
|
||||
this.logger.info(`remove project: ${project.getRootFiles().toString()}`);
|
||||
this.logger.info("`remove Project::");
|
||||
project.print();
|
||||
|
||||
project.close();
|
||||
if (Debug.shouldAssert(AssertionLevel.Normal)) {
|
||||
this.filenameToScriptInfo.forEach(info => Debug.assert(!info.isAttached(project)));
|
||||
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))}`));
|
||||
}
|
||||
// Remove the project from pending project updates
|
||||
this.pendingProjectUpdates.delete(project.getProjectName());
|
||||
@@ -1474,19 +1478,9 @@ namespace ts.server {
|
||||
|
||||
const writeProjectFileNames = this.logger.hasLevel(LogLevel.verbose);
|
||||
this.logger.startGroup();
|
||||
let counter = 0;
|
||||
const printProjects = (projects: Project[], counter: number): number => {
|
||||
for (const project of projects) {
|
||||
this.logger.info(`Project '${project.getProjectName()}' (${ProjectKind[project.projectKind]}) ${counter}`);
|
||||
this.logger.info(project.filesToString(writeProjectFileNames));
|
||||
this.logger.info("-----------------------------------------------");
|
||||
counter++;
|
||||
}
|
||||
return counter;
|
||||
};
|
||||
counter = printProjects(this.externalProjects, counter);
|
||||
counter = printProjects(arrayFrom(this.configuredProjects.values()), counter);
|
||||
printProjects(this.inferredProjects, counter);
|
||||
let counter = printProjectsWithCounter(this.externalProjects, 0);
|
||||
counter = printProjectsWithCounter(arrayFrom(this.configuredProjects.values()), counter);
|
||||
printProjectsWithCounter(this.inferredProjects, counter);
|
||||
|
||||
this.logger.info("Open files: ");
|
||||
this.openFiles.forEach((projectRootPath, path) => {
|
||||
@@ -1742,7 +1736,7 @@ namespace ts.server {
|
||||
project.enableLanguageService();
|
||||
project.watchWildcards(createMapFromTemplate(parsedCommandLine.wildcardDirectories!)); // TODO: GH#18217
|
||||
}
|
||||
project.enablePluginsWithOptions(compilerOptions);
|
||||
project.enablePluginsWithOptions(compilerOptions, this.currentPluginConfigOverrides);
|
||||
const filesToAdd = parsedCommandLine.fileNames.concat(project.getExternalFiles());
|
||||
this.updateRootAndOptionsOfNonInferredProject(project, filesToAdd, fileNamePropertyReader, compilerOptions, parsedCommandLine.typeAcquisition!, parsedCommandLine.compileOnSave!); // TODO: GH#18217
|
||||
}
|
||||
@@ -1932,7 +1926,7 @@ namespace ts.server {
|
||||
|
||||
private createInferredProject(currentDirectory: string | undefined, isSingleInferredProject?: boolean, projectRootPath?: NormalizedPath): InferredProject {
|
||||
const compilerOptions = projectRootPath && this.compilerOptionsForInferredProjectsPerProjectRoot.get(projectRootPath) || this.compilerOptionsForInferredProjects;
|
||||
const project = new InferredProject(this, this.documentRegistry, compilerOptions, projectRootPath, currentDirectory);
|
||||
const project = new InferredProject(this, this.documentRegistry, compilerOptions, projectRootPath, currentDirectory, this.currentPluginConfigOverrides);
|
||||
if (isSingleInferredProject) {
|
||||
this.inferredProjects.unshift(project);
|
||||
}
|
||||
@@ -1963,6 +1957,12 @@ namespace ts.server {
|
||||
return configProject && configProject.getCompilerOptions().configFile;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
logErrorForScriptInfoNotFound(fileName: string): void {
|
||||
const names = arrayFrom(this.filenameToScriptInfo.entries()).map(([path, scriptInfo]) => ({ path, fileName: scriptInfo.fileName }));
|
||||
this.logger.msg(`Could not find file ${JSON.stringify(fileName)}.\nAll files are: ${JSON.stringify(names)}`, Msg.Err);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the projects that contain script info through SymLink
|
||||
* Note that this does not return projects in info.containingProjects
|
||||
@@ -2040,6 +2040,8 @@ namespace ts.server {
|
||||
watchDir,
|
||||
(fileOrDirectory) => {
|
||||
const fileOrDirectoryPath = this.toPath(fileOrDirectory);
|
||||
if (isPathInNodeModulesStartingWithDot(fileOrDirectoryPath)) return;
|
||||
|
||||
// Has extension
|
||||
Debug.assert(result.refCount > 0);
|
||||
if (watchDir === fileOrDirectoryPath) {
|
||||
@@ -2107,7 +2109,20 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
private getOrCreateScriptInfoNotOpenedByClientForNormalizedPath(fileName: NormalizedPath, currentDirectory: string, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined, hostToQueryFileExistsOn: DirectoryStructureHost | undefined) {
|
||||
return this.getOrCreateScriptInfoWorker(fileName, currentDirectory, /*openedByClient*/ false, /*fileContent*/ undefined, scriptKind, hasMixedContent, hostToQueryFileExistsOn);
|
||||
if (isRootedDiskPath(fileName) || isDynamicFileName(fileName)) {
|
||||
return this.getOrCreateScriptInfoWorker(fileName, currentDirectory, /*openedByClient*/ false, /*fileContent*/ undefined, scriptKind, hasMixedContent, hostToQueryFileExistsOn);
|
||||
}
|
||||
|
||||
// This is non rooted path with different current directory than project service current directory
|
||||
// Only paths recognized are open relative file paths
|
||||
const info = this.openFilesWithNonRootedDiskPath.get(this.toCanonicalFileName(fileName));
|
||||
if (info) {
|
||||
return info;
|
||||
}
|
||||
|
||||
// This means triple slash references wont be resolved in dynamic and unsaved files
|
||||
// which is intentional since we dont know what it means to be relative to non disk files
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName: NormalizedPath, currentDirectory: string, fileContent: string | undefined, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined) {
|
||||
@@ -2124,7 +2139,7 @@ namespace ts.server {
|
||||
let info = this.getScriptInfoForPath(path);
|
||||
if (!info) {
|
||||
const isDynamic = isDynamicFileName(fileName);
|
||||
Debug.assert(isRootedDiskPath(fileName) || isDynamic || openedByClient, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nScript info with non-dynamic relative file name can only be open script info`);
|
||||
Debug.assert(isRootedDiskPath(fileName) || isDynamic || openedByClient, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nScript info with non-dynamic relative file name can only be open script info or in context of host currentDirectory`);
|
||||
Debug.assert(!isRootedDiskPath(fileName) || this.currentDirectory === currentDirectory || !this.openFilesWithNonRootedDiskPath.has(this.toCanonicalFileName(fileName)), "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nOpen script files with non rooted disk path opened with current directory context cannot have same canonical names`);
|
||||
Debug.assert(!isDynamic || this.currentDirectory === currentDirectory, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nDynamic files must always have current directory context since containing external project name will always match the script info name.`);
|
||||
// If the file is not opened by client and the file doesnot exist on the disk, return
|
||||
@@ -2137,7 +2152,7 @@ namespace ts.server {
|
||||
if (!openedByClient) {
|
||||
this.watchClosedScriptInfo(info);
|
||||
}
|
||||
else if (!isRootedDiskPath(fileName) && currentDirectory !== this.currentDirectory) {
|
||||
else if (!isRootedDiskPath(fileName) && !isDynamic) {
|
||||
// File that is opened by user but isn't rooted disk path
|
||||
this.openFilesWithNonRootedDiskPath.set(this.toCanonicalFileName(fileName), info);
|
||||
}
|
||||
@@ -2352,8 +2367,8 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
getOriginalLocationEnsuringConfiguredProject(project: Project, location: sourcemaps.SourceMappableLocation): sourcemaps.SourceMappableLocation | undefined {
|
||||
const originalLocation = project.getSourceMapper().tryGetOriginalLocation(location);
|
||||
getOriginalLocationEnsuringConfiguredProject(project: Project, location: DocumentPosition): DocumentPosition | undefined {
|
||||
const originalLocation = project.getSourceMapper().tryGetSourcePosition(location);
|
||||
if (!originalLocation) return undefined;
|
||||
|
||||
const { fileName } = originalLocation;
|
||||
@@ -2880,6 +2895,16 @@ namespace ts.server {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
configurePlugin(args: protocol.ConfigurePluginRequestArguments) {
|
||||
// For any projects that already have the plugin loaded, configure the plugin
|
||||
this.forEachEnabledProject(project => project.onPluginConfigurationChanged(args.pluginName, args.configuration));
|
||||
|
||||
// Also save the current configuration to pass on to any projects that are yet to be loaded.
|
||||
// If a plugin is configured twice, only the latest configuration will be remembered.
|
||||
this.currentPluginConfigOverrides = this.currentPluginConfigOverrides || createMap();
|
||||
this.currentPluginConfigOverrides.set(args.pluginName, args.configuration);
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -2888,4 +2913,12 @@ namespace ts.server {
|
||||
export function isConfigFile(config: ScriptInfoOrConfig): config is TsConfigSourceFile {
|
||||
return (config as TsConfigSourceFile).kind !== undefined;
|
||||
}
|
||||
|
||||
function printProjectsWithCounter(projects: Project[], counter: number) {
|
||||
for (const project of projects) {
|
||||
project.print(counter);
|
||||
counter++;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
}
|
||||
|
||||
+77
-72
@@ -72,6 +72,12 @@ namespace ts.server {
|
||||
export interface PluginModule {
|
||||
create(createInfo: PluginCreateInfo): LanguageService;
|
||||
getExternalFiles?(proj: Project): string[];
|
||||
onConfigurationChanged?(config: any): void;
|
||||
}
|
||||
|
||||
export interface PluginModuleWithName {
|
||||
name: string;
|
||||
module: PluginModule;
|
||||
}
|
||||
|
||||
export type PluginModuleFactory = (mod: { typescript: typeof ts }) => PluginModule;
|
||||
@@ -92,7 +98,7 @@ namespace ts.server {
|
||||
private program: Program;
|
||||
private externalFiles: SortedReadonlyArray<string>;
|
||||
private missingFilesMap: Map<FileWatcher>;
|
||||
private plugins: PluginModule[] = [];
|
||||
private plugins: PluginModuleWithName[] = [];
|
||||
|
||||
/*@internal*/
|
||||
/**
|
||||
@@ -198,7 +204,7 @@ namespace ts.server {
|
||||
|
||||
/*@internal*/
|
||||
constructor(
|
||||
/*@internal*/readonly projectName: string,
|
||||
readonly projectName: string,
|
||||
readonly projectKind: ProjectKind,
|
||||
readonly projectService: ProjectService,
|
||||
private documentRegistry: DocumentRegistry,
|
||||
@@ -548,10 +554,10 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
getExternalFiles(): SortedReadonlyArray<string> {
|
||||
return toSortedArray(flatMap(this.plugins, plugin => {
|
||||
if (typeof plugin.getExternalFiles !== "function") return;
|
||||
return sort(flatMap(this.plugins, plugin => {
|
||||
if (typeof plugin.module.getExternalFiles !== "function") return;
|
||||
try {
|
||||
return plugin.getExternalFiles(this);
|
||||
return plugin.module.getExternalFiles(this);
|
||||
}
|
||||
catch (e) {
|
||||
this.projectService.logger.info(`A plugin threw an exception in getExternalFiles: ${e}`);
|
||||
@@ -789,41 +795,6 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
private extractUnresolvedImportsFromSourceFile(file: SourceFile, ambientModules: string[]): ReadonlyArray<string> {
|
||||
const cached = this.cachedUnresolvedImportsPerFile.get(file.path);
|
||||
if (cached) {
|
||||
// found cached result, return
|
||||
return cached;
|
||||
}
|
||||
let unresolvedImports: string[] | undefined;
|
||||
if (file.resolvedModules) {
|
||||
file.resolvedModules.forEach((resolvedModule, name) => {
|
||||
// pick unresolved non-relative names
|
||||
if (!resolvedModule && !isExternalModuleNameRelative(name) && !isAmbientlyDeclaredModule(name)) {
|
||||
// for non-scoped names extract part up-to the first slash
|
||||
// for scoped names - extract up to the second slash
|
||||
let trimmed = name.trim();
|
||||
let i = trimmed.indexOf("/");
|
||||
if (i !== -1 && trimmed.charCodeAt(0) === CharacterCodes.at) {
|
||||
i = trimmed.indexOf("/", i + 1);
|
||||
}
|
||||
if (i !== -1) {
|
||||
trimmed = trimmed.substr(0, i);
|
||||
}
|
||||
(unresolvedImports || (unresolvedImports = [])).push(trimmed);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.cachedUnresolvedImportsPerFile.set(file.path, unresolvedImports || emptyArray);
|
||||
return unresolvedImports || emptyArray;
|
||||
|
||||
function isAmbientlyDeclaredModule(name: string) {
|
||||
return ambientModules.some(m => m === name);
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
onFileAddedOrRemoved() {
|
||||
this.hasAddedorRemovedFiles = true;
|
||||
@@ -857,15 +828,7 @@ namespace ts.server {
|
||||
// (can reuse cached imports for files that were not changed)
|
||||
// 4. compilation settings were changed in the way that might affect module resolution - drop all caches and collect all data from the scratch
|
||||
if (hasNewProgram || changedFiles.length) {
|
||||
let result: string[] | undefined;
|
||||
const ambientModules = this.program.getTypeChecker().getAmbientModules().map(mod => stripQuotes(mod.getName()));
|
||||
for (const sourceFile of this.program.getSourceFiles()) {
|
||||
const unResolved = this.extractUnresolvedImportsFromSourceFile(sourceFile, ambientModules);
|
||||
if (unResolved !== emptyArray) {
|
||||
(result || (result = [])).push(...unResolved);
|
||||
}
|
||||
}
|
||||
this.lastCachedUnresolvedImportsList = result ? toDeduplicatedSortedArray(result) : emptyArray;
|
||||
this.lastCachedUnresolvedImportsList = getUnresolvedImports(this.program, this.cachedUnresolvedImportsPerFile);
|
||||
}
|
||||
|
||||
this.projectService.typingsCache.enqueueInstallTypingsForProject(this, this.lastCachedUnresolvedImportsList, hasAddedorRemovedFiles);
|
||||
@@ -882,7 +845,7 @@ namespace ts.server {
|
||||
|
||||
/*@internal*/
|
||||
updateTypingFiles(typingFiles: SortedReadonlyArray<string>) {
|
||||
enumerateInsertsAndDeletes(typingFiles, this.typingFiles, getStringComparer(!this.useCaseSensitiveFileNames()),
|
||||
enumerateInsertsAndDeletes<string, string>(typingFiles, this.typingFiles, getStringComparer(!this.useCaseSensitiveFileNames()),
|
||||
/*inserted*/ noop,
|
||||
removed => this.detachScriptInfoFromProject(removed)
|
||||
);
|
||||
@@ -953,7 +916,7 @@ namespace ts.server {
|
||||
|
||||
const oldExternalFiles = this.externalFiles || emptyArray as SortedReadonlyArray<string>;
|
||||
this.externalFiles = this.getExternalFiles();
|
||||
enumerateInsertsAndDeletes(this.externalFiles, oldExternalFiles, getStringComparer(!this.useCaseSensitiveFileNames()),
|
||||
enumerateInsertsAndDeletes<string, string>(this.externalFiles, oldExternalFiles, getStringComparer(!this.useCaseSensitiveFileNames()),
|
||||
// Ensure a ScriptInfo is created for new external files. This is performed indirectly
|
||||
// by the LSHost for files in the program when the program is retrieved above but
|
||||
// the program doesn't contain external files so this must be done explicitly.
|
||||
@@ -1032,6 +995,13 @@ namespace ts.server {
|
||||
return strBuilder;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
print(counter?: number) {
|
||||
this.writeLog(`Project '${this.projectName}' (${ProjectKind[this.projectKind]}) ${counter === undefined ? "" : counter}`);
|
||||
this.writeLog(this.filesToString(this.projectService.logger.hasLevel(LogLevel.verbose)));
|
||||
this.writeLog("-----------------------------------------------");
|
||||
}
|
||||
|
||||
setCompilerOptions(compilerOptions: CompilerOptions) {
|
||||
if (compilerOptions) {
|
||||
compilerOptions.allowNonTsExtensions = true;
|
||||
@@ -1111,7 +1081,7 @@ namespace ts.server {
|
||||
this.rootFilesMap.delete(info.path);
|
||||
}
|
||||
|
||||
protected enableGlobalPlugins(options: CompilerOptions) {
|
||||
protected enableGlobalPlugins(options: CompilerOptions, pluginConfigOverrides: Map<any> | undefined) {
|
||||
const host = this.projectService.host;
|
||||
|
||||
if (!host.require) {
|
||||
@@ -1134,12 +1104,13 @@ namespace ts.server {
|
||||
|
||||
// Provide global: true so plugins can detect why they can't find their config
|
||||
this.projectService.logger.info(`Loading global plugin ${globalPluginName}`);
|
||||
this.enablePlugin({ name: globalPluginName, global: true } as PluginImport, searchPaths);
|
||||
|
||||
this.enablePlugin({ name: globalPluginName, global: true } as PluginImport, searchPaths, pluginConfigOverrides);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected enablePlugin(pluginConfigEntry: PluginImport, searchPaths: string[]) {
|
||||
protected enablePlugin(pluginConfigEntry: PluginImport, searchPaths: string[], pluginConfigOverrides: Map<any> | undefined) {
|
||||
this.projectService.logger.info(`Enabling plugin ${pluginConfigEntry.name} from candidate paths: ${searchPaths.join(",")}`);
|
||||
|
||||
const log = (message: string) => {
|
||||
@@ -1149,6 +1120,14 @@ namespace ts.server {
|
||||
const resolvedModule = firstDefined(searchPaths, searchPath =>
|
||||
<PluginModuleFactory | undefined>Project.resolveModule(pluginConfigEntry.name, searchPath, this.projectService.host, log));
|
||||
if (resolvedModule) {
|
||||
const configurationOverride = pluginConfigOverrides && pluginConfigOverrides.get(pluginConfigEntry.name);
|
||||
if (configurationOverride) {
|
||||
// Preserve the name property since it's immutable
|
||||
const pluginName = pluginConfigEntry.name;
|
||||
pluginConfigEntry = configurationOverride;
|
||||
pluginConfigEntry.name = pluginName;
|
||||
}
|
||||
|
||||
this.enableProxy(resolvedModule, pluginConfigEntry);
|
||||
}
|
||||
else {
|
||||
@@ -1156,11 +1135,6 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
/** Starts a new check for diagnostics. Call this if some file has updated that would cause diagnostics to be changed. */
|
||||
refreshDiagnostics() {
|
||||
this.projectService.sendProjectsUpdatedInBackgroundEvent();
|
||||
}
|
||||
|
||||
private enableProxy(pluginModuleFactory: PluginModuleFactory, configEntry: PluginImport) {
|
||||
try {
|
||||
if (typeof pluginModuleFactory !== "function") {
|
||||
@@ -1186,12 +1160,47 @@ namespace ts.server {
|
||||
}
|
||||
this.projectService.logger.info(`Plugin validation succeded`);
|
||||
this.languageService = newLS;
|
||||
this.plugins.push(pluginModule);
|
||||
this.plugins.push({ name: configEntry.name, module: pluginModule });
|
||||
}
|
||||
catch (e) {
|
||||
this.projectService.logger.info(`Plugin activation failed: ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
onPluginConfigurationChanged(pluginName: string, configuration: any) {
|
||||
this.plugins.filter(plugin => plugin.name === pluginName).forEach(plugin => {
|
||||
if (plugin.module.onConfigurationChanged) {
|
||||
plugin.module.onConfigurationChanged(configuration);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Starts a new check for diagnostics. Call this if some file has updated that would cause diagnostics to be changed. */
|
||||
refreshDiagnostics() {
|
||||
this.projectService.sendProjectsUpdatedInBackgroundEvent();
|
||||
}
|
||||
}
|
||||
|
||||
function getUnresolvedImports(program: Program, cachedUnresolvedImportsPerFile: Map<ReadonlyArray<string>>): SortedReadonlyArray<string> {
|
||||
const ambientModules = program.getTypeChecker().getAmbientModules().map(mod => stripQuotes(mod.getName()));
|
||||
return sortAndDeduplicate(flatMap(program.getSourceFiles(), sourceFile =>
|
||||
extractUnresolvedImportsFromSourceFile(sourceFile, ambientModules, cachedUnresolvedImportsPerFile)));
|
||||
}
|
||||
function extractUnresolvedImportsFromSourceFile(file: SourceFile, ambientModules: ReadonlyArray<string>, cachedUnresolvedImportsPerFile: Map<ReadonlyArray<string>>): ReadonlyArray<string> {
|
||||
return getOrUpdate(cachedUnresolvedImportsPerFile, file.path, () => {
|
||||
if (!file.resolvedModules) return emptyArray;
|
||||
let unresolvedImports: string[] | undefined;
|
||||
file.resolvedModules.forEach((resolvedModule, name) => {
|
||||
// pick unresolved non-relative names
|
||||
if ((!resolvedModule || !resolutionExtensionIsTSOrJson(resolvedModule.extension)) &&
|
||||
!isExternalModuleNameRelative(name) &&
|
||||
!ambientModules.some(m => m === name)) {
|
||||
unresolvedImports = append(unresolvedImports, parsePackageName(name).packageName);
|
||||
}
|
||||
});
|
||||
return unresolvedImports || emptyArray;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1219,11 +1228,10 @@ namespace ts.server {
|
||||
|
||||
setCompilerOptions(options?: CompilerOptions) {
|
||||
// Avoid manipulating the given options directly
|
||||
const newOptions = options ? cloneCompilerOptions(options) : this.getCompilationSettings();
|
||||
if (!newOptions) {
|
||||
if (!options && !this.getCompilationSettings()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newOptions = cloneCompilerOptions(options || this.getCompilationSettings());
|
||||
if (this._isJsInferredProject && typeof newOptions.maxNodeModuleJsDepth !== "number") {
|
||||
newOptions.maxNodeModuleJsDepth = 2;
|
||||
}
|
||||
@@ -1247,7 +1255,8 @@ namespace ts.server {
|
||||
documentRegistry: DocumentRegistry,
|
||||
compilerOptions: CompilerOptions,
|
||||
projectRootPath: NormalizedPath | undefined,
|
||||
currentDirectory: string | undefined) {
|
||||
currentDirectory: string | undefined,
|
||||
pluginConfigOverrides: Map<any> | undefined) {
|
||||
super(InferredProject.newName(),
|
||||
ProjectKind.Inferred,
|
||||
projectService,
|
||||
@@ -1263,7 +1272,7 @@ namespace ts.server {
|
||||
if (!projectRootPath && !projectService.useSingleInferredProject) {
|
||||
this.canonicalCurrentDirectory = projectService.toCanonicalFileName(this.currentDirectory);
|
||||
}
|
||||
this.enableGlobalPlugins(this.getCompilerOptions());
|
||||
this.enableGlobalPlugins(this.getCompilerOptions(), pluginConfigOverrides);
|
||||
}
|
||||
|
||||
addRoot(info: ScriptInfo) {
|
||||
@@ -1419,12 +1428,8 @@ namespace ts.server {
|
||||
return program && program.forEachResolvedProjectReference(cb);
|
||||
}
|
||||
|
||||
enablePlugins() {
|
||||
this.enablePluginsWithOptions(this.getCompilerOptions());
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
enablePluginsWithOptions(options: CompilerOptions) {
|
||||
enablePluginsWithOptions(options: CompilerOptions, pluginConfigOverrides: Map<any> | undefined) {
|
||||
const host = this.projectService.host;
|
||||
|
||||
if (!host.require) {
|
||||
@@ -1445,11 +1450,11 @@ namespace ts.server {
|
||||
// Enable tsconfig-specified plugins
|
||||
if (options.plugins) {
|
||||
for (const pluginConfigEntry of options.plugins) {
|
||||
this.enablePlugin(pluginConfigEntry, searchPaths);
|
||||
this.enablePlugin(pluginConfigEntry, searchPaths, pluginConfigOverrides);
|
||||
}
|
||||
}
|
||||
|
||||
this.enableGlobalPlugins(options);
|
||||
this.enableGlobalPlugins(options, pluginConfigOverrides);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+22
-1
@@ -129,6 +129,7 @@ namespace ts.server.protocol {
|
||||
GetEditsForFileRename = "getEditsForFileRename",
|
||||
/* @internal */
|
||||
GetEditsForFileRenameFull = "getEditsForFileRename-full",
|
||||
ConfigurePlugin = "configurePlugin"
|
||||
|
||||
// NOTE: If updating this, be sure to also update `allCommandNames` in `harness/unittests/session.ts`.
|
||||
}
|
||||
@@ -220,6 +221,11 @@ namespace ts.server.protocol {
|
||||
* Contains message body if success === true.
|
||||
*/
|
||||
body?: any;
|
||||
|
||||
/**
|
||||
* Contains extra information that plugin can include to be passed on
|
||||
*/
|
||||
metadata?: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1023,7 +1029,7 @@ namespace ts.server.protocol {
|
||||
/**
|
||||
* The file locations referencing the symbol.
|
||||
*/
|
||||
refs: ReferencesResponseItem[];
|
||||
refs: ReadonlyArray<ReferencesResponseItem>;
|
||||
|
||||
/**
|
||||
* The name of the symbol.
|
||||
@@ -1375,6 +1381,16 @@ namespace ts.server.protocol {
|
||||
export interface ConfigureResponse extends Response {
|
||||
}
|
||||
|
||||
export interface ConfigurePluginRequestArguments {
|
||||
pluginName: string;
|
||||
configuration: any;
|
||||
}
|
||||
|
||||
export interface ConfigurePluginRequest extends Request {
|
||||
command: CommandTypes.ConfigurePlugin;
|
||||
arguments: ConfigurePluginRequestArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Information found in an "open" request.
|
||||
*/
|
||||
@@ -2390,6 +2406,7 @@ namespace ts.server.protocol {
|
||||
*/
|
||||
export interface DiagnosticEvent extends Event {
|
||||
body?: DiagnosticEventBody;
|
||||
event: DiagnosticEventKind;
|
||||
}
|
||||
|
||||
export interface ConfigFileDiagnosticEventBody {
|
||||
@@ -2509,6 +2526,10 @@ namespace ts.server.protocol {
|
||||
maxFileSize: number;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export type AnyEvent = RequestCompletedEvent | DiagnosticEvent | ConfigFileDiagnosticEvent | ProjectLanguageServiceStateEvent | TelemetryEvent |
|
||||
ProjectsUpdatedInBackgroundEvent | ProjectLoadingStartEvent | ProjectLoadingFinishEvent | SurveyReadyEvent | LargeFileReferencedEvent;
|
||||
|
||||
/**
|
||||
* Arguments for reload request.
|
||||
*/
|
||||
|
||||
@@ -6,7 +6,6 @@ namespace ts.server {
|
||||
|
||||
/* @internal */
|
||||
export class TextStorage {
|
||||
/*@internal*/
|
||||
version: ScriptInfoVersion;
|
||||
|
||||
/**
|
||||
|
||||
@@ -382,7 +382,6 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export class LineIndex {
|
||||
root: LineNode;
|
||||
// set this to true to check each edit for accuracy
|
||||
|
||||
+132
-70
@@ -267,7 +267,7 @@ namespace ts.server {
|
||||
projects: Projects,
|
||||
action: (project: Project, value: T) => ReadonlyArray<U> | U | undefined,
|
||||
): U[] {
|
||||
const outputs = flatMap(isArray(projects) ? projects : projects.projects, project => action(project, defaultValue));
|
||||
const outputs = flatMapToMutable(isArray(projects) ? projects : projects.projects, project => action(project, defaultValue));
|
||||
if (!isArray(projects) && projects.symLinkedProjects) {
|
||||
projects.symLinkedProjects.forEach((projects, path) => {
|
||||
const value = getValue(path as Path);
|
||||
@@ -289,9 +289,8 @@ namespace ts.server {
|
||||
function combineProjectOutputWhileOpeningReferencedProjects<T>(
|
||||
projects: Projects,
|
||||
defaultProject: Project,
|
||||
projectService: ProjectService,
|
||||
action: (project: Project) => ReadonlyArray<T>,
|
||||
getLocation: (t: T) => sourcemaps.SourceMappableLocation,
|
||||
getLocation: (t: T) => DocumentPosition,
|
||||
resultsEqual: (a: T, b: T) => boolean,
|
||||
): T[] {
|
||||
const outputs: T[] = [];
|
||||
@@ -299,7 +298,6 @@ namespace ts.server {
|
||||
projects,
|
||||
defaultProject,
|
||||
/*initialLocation*/ undefined,
|
||||
projectService,
|
||||
({ project }, tryAddToTodo) => {
|
||||
for (const output of action(project)) {
|
||||
if (!contains(outputs, output, resultsEqual) && !tryAddToTodo(project, getLocation(output))) {
|
||||
@@ -312,57 +310,77 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
function combineProjectOutputForRenameLocations(
|
||||
projects: Projects, defaultProject: Project, initialLocation: sourcemaps.SourceMappableLocation, projectService: ProjectService, findInStrings: boolean, findInComments: boolean
|
||||
projects: Projects,
|
||||
defaultProject: Project,
|
||||
initialLocation: DocumentPosition,
|
||||
findInStrings: boolean,
|
||||
findInComments: boolean
|
||||
): ReadonlyArray<RenameLocation> {
|
||||
const outputs: RenameLocation[] = [];
|
||||
|
||||
combineProjectOutputWorker<sourcemaps.SourceMappableLocation>(projects, defaultProject, initialLocation, projectService, ({ project, location }, tryAddToTodo) => {
|
||||
for (const output of project.getLanguageService().findRenameLocations(location.fileName, location.position, findInStrings, findInComments) || emptyArray) {
|
||||
if (!contains(outputs, output, documentSpansEqual) && !tryAddToTodo(project, documentSpanLocation(output))) {
|
||||
outputs.push(output);
|
||||
combineProjectOutputWorker<DocumentPosition>(
|
||||
projects,
|
||||
defaultProject,
|
||||
initialLocation,
|
||||
({ project, location }, tryAddToTodo) => {
|
||||
for (const output of project.getLanguageService().findRenameLocations(location.fileName, location.pos, findInStrings, findInComments) || emptyArray) {
|
||||
if (!contains(outputs, output, documentSpansEqual) && !tryAddToTodo(project, documentSpanLocation(output))) {
|
||||
outputs.push(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, () => getDefinitionLocation(defaultProject, initialLocation));
|
||||
},
|
||||
() => getDefinitionLocation(defaultProject, initialLocation)
|
||||
);
|
||||
|
||||
return outputs;
|
||||
}
|
||||
|
||||
function getDefinitionLocation(defaultProject: Project, initialLocation: sourcemaps.SourceMappableLocation): sourcemaps.SourceMappableLocation | undefined {
|
||||
const infos = defaultProject.getLanguageService().getDefinitionAtPosition(initialLocation.fileName, initialLocation.position);
|
||||
function getDefinitionLocation(defaultProject: Project, initialLocation: DocumentPosition): DocumentPosition | undefined {
|
||||
const infos = defaultProject.getLanguageService().getDefinitionAtPosition(initialLocation.fileName, initialLocation.pos);
|
||||
const info = infos && firstOrUndefined(infos);
|
||||
return info && { fileName: info.fileName, position: info.textSpan.start };
|
||||
return info && { fileName: info.fileName, pos: info.textSpan.start };
|
||||
}
|
||||
|
||||
function combineProjectOutputForReferences(projects: Projects, defaultProject: Project, initialLocation: sourcemaps.SourceMappableLocation, projectService: ProjectService): ReadonlyArray<ReferencedSymbol> {
|
||||
function combineProjectOutputForReferences(
|
||||
projects: Projects,
|
||||
defaultProject: Project,
|
||||
initialLocation: DocumentPosition
|
||||
): ReadonlyArray<ReferencedSymbol> {
|
||||
const outputs: ReferencedSymbol[] = [];
|
||||
|
||||
combineProjectOutputWorker<sourcemaps.SourceMappableLocation>(projects, defaultProject, initialLocation, projectService, ({ project, location }, getMappedLocation) => {
|
||||
for (const outputReferencedSymbol of project.getLanguageService().findReferences(location.fileName, location.position) || emptyArray) {
|
||||
const mappedDefinitionFile = getMappedLocation(project, documentSpanLocation(outputReferencedSymbol.definition));
|
||||
const definition: ReferencedSymbolDefinitionInfo = mappedDefinitionFile === undefined ? outputReferencedSymbol.definition : {
|
||||
...outputReferencedSymbol.definition,
|
||||
textSpan: createTextSpan(mappedDefinitionFile.position, outputReferencedSymbol.definition.textSpan.length),
|
||||
fileName: mappedDefinitionFile.fileName,
|
||||
};
|
||||
let symbolToAddTo = find(outputs, o => documentSpansEqual(o.definition, definition));
|
||||
if (!symbolToAddTo) {
|
||||
symbolToAddTo = { definition, references: [] };
|
||||
outputs.push(symbolToAddTo);
|
||||
}
|
||||
combineProjectOutputWorker<DocumentPosition>(
|
||||
projects,
|
||||
defaultProject,
|
||||
initialLocation,
|
||||
({ project, location }, getMappedLocation) => {
|
||||
for (const outputReferencedSymbol of project.getLanguageService().findReferences(location.fileName, location.pos) || emptyArray) {
|
||||
const mappedDefinitionFile = getMappedLocation(project, documentSpanLocation(outputReferencedSymbol.definition));
|
||||
const definition: ReferencedSymbolDefinitionInfo = mappedDefinitionFile === undefined ? outputReferencedSymbol.definition : {
|
||||
...outputReferencedSymbol.definition,
|
||||
textSpan: createTextSpan(mappedDefinitionFile.pos, outputReferencedSymbol.definition.textSpan.length),
|
||||
fileName: mappedDefinitionFile.fileName,
|
||||
};
|
||||
let symbolToAddTo = find(outputs, o => documentSpansEqual(o.definition, definition));
|
||||
if (!symbolToAddTo) {
|
||||
symbolToAddTo = { definition, references: [] };
|
||||
outputs.push(symbolToAddTo);
|
||||
}
|
||||
|
||||
for (const ref of outputReferencedSymbol.references) {
|
||||
// If it's in a mapped file, that is added to the todo list by `getMappedLocation`.
|
||||
if (!contains(symbolToAddTo.references, ref, documentSpansEqual) && !getMappedLocation(project, documentSpanLocation(ref))) {
|
||||
symbolToAddTo.references.push(ref);
|
||||
for (const ref of outputReferencedSymbol.references) {
|
||||
// If it's in a mapped file, that is added to the todo list by `getMappedLocation`.
|
||||
if (!contains(symbolToAddTo.references, ref, documentSpansEqual) && !getMappedLocation(project, documentSpanLocation(ref))) {
|
||||
symbolToAddTo.references.push(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, () => getDefinitionLocation(defaultProject, initialLocation));
|
||||
},
|
||||
() => getDefinitionLocation(defaultProject, initialLocation)
|
||||
);
|
||||
|
||||
return outputs.filter(o => o.references.length !== 0);
|
||||
}
|
||||
|
||||
interface ProjectAndLocation<TLocation extends sourcemaps.SourceMappableLocation | undefined> {
|
||||
interface ProjectAndLocation<TLocation extends DocumentPosition | undefined> {
|
||||
readonly project: Project;
|
||||
readonly location: TLocation;
|
||||
}
|
||||
@@ -380,24 +398,24 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
type CombineProjectOutputCallback<TLocation extends sourcemaps.SourceMappableLocation | undefined> = (
|
||||
type CombineProjectOutputCallback<TLocation extends DocumentPosition | undefined> = (
|
||||
where: ProjectAndLocation<TLocation>,
|
||||
getMappedLocation: (project: Project, location: sourcemaps.SourceMappableLocation) => sourcemaps.SourceMappableLocation | undefined,
|
||||
getMappedLocation: (project: Project, location: DocumentPosition) => DocumentPosition | undefined,
|
||||
) => void;
|
||||
|
||||
function combineProjectOutputWorker<TLocation extends sourcemaps.SourceMappableLocation | undefined>(
|
||||
function combineProjectOutputWorker<TLocation extends DocumentPosition | undefined>(
|
||||
projects: Projects,
|
||||
defaultProject: Project,
|
||||
initialLocation: TLocation,
|
||||
projectService: ProjectService,
|
||||
cb: CombineProjectOutputCallback<TLocation>,
|
||||
getDefinition: (() => sourcemaps.SourceMappableLocation | undefined) | undefined,
|
||||
getDefinition: (() => DocumentPosition | undefined) | undefined,
|
||||
): void {
|
||||
const projectService = defaultProject.projectService;
|
||||
let toDo: ProjectAndLocation<TLocation>[] | undefined;
|
||||
const seenProjects = createMap<true>();
|
||||
forEachProjectInProjects(projects, initialLocation && initialLocation.fileName, (project, path) => {
|
||||
// TLocation shoud be either `sourcemaps.SourceMappableLocation` or `undefined`. Since `initialLocation` is `TLocation` this cast should be valid.
|
||||
const location = (initialLocation ? { fileName: path, position: initialLocation.position } : undefined) as TLocation;
|
||||
// TLocation shoud be either `DocumentPosition` or `undefined`. Since `initialLocation` is `TLocation` this cast should be valid.
|
||||
const location = (initialLocation ? { fileName: path, pos: initialLocation.pos } : undefined) as TLocation;
|
||||
toDo = callbackProjectAndLocation({ project, location }, projectService, toDo, seenProjects, cb);
|
||||
});
|
||||
|
||||
@@ -418,13 +436,13 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
function getDefinitionInProject(definition: sourcemaps.SourceMappableLocation | undefined, definingProject: Project, project: Project): sourcemaps.SourceMappableLocation | undefined {
|
||||
function getDefinitionInProject(definition: DocumentPosition | undefined, definingProject: Project, project: Project): DocumentPosition | undefined {
|
||||
if (!definition || project.containsFile(toNormalizedPath(definition.fileName))) return definition;
|
||||
const mappedDefinition = definingProject.getLanguageService().getSourceMapper().tryGetGeneratedLocation(definition);
|
||||
const mappedDefinition = definingProject.getLanguageService().getSourceMapper().tryGetGeneratedPosition(definition);
|
||||
return mappedDefinition && project.containsFile(toNormalizedPath(mappedDefinition.fileName)) ? mappedDefinition : undefined;
|
||||
}
|
||||
|
||||
function callbackProjectAndLocation<TLocation extends sourcemaps.SourceMappableLocation | undefined>(
|
||||
function callbackProjectAndLocation<TLocation extends DocumentPosition | undefined>(
|
||||
projectAndLocation: ProjectAndLocation<TLocation>,
|
||||
projectService: ProjectService,
|
||||
toDo: ProjectAndLocation<TLocation>[] | undefined,
|
||||
@@ -454,16 +472,16 @@ namespace ts.server {
|
||||
return toDo;
|
||||
}
|
||||
|
||||
function addToTodo<TLocation extends sourcemaps.SourceMappableLocation | undefined>(projectAndLocation: ProjectAndLocation<TLocation>, toDo: Push<ProjectAndLocation<TLocation>>, seenProjects: Map<true>): void {
|
||||
function addToTodo<TLocation extends DocumentPosition | undefined>(projectAndLocation: ProjectAndLocation<TLocation>, toDo: Push<ProjectAndLocation<TLocation>>, seenProjects: Map<true>): void {
|
||||
if (addToSeen(seenProjects, projectAndLocation.project.projectName)) toDo.push(projectAndLocation);
|
||||
}
|
||||
|
||||
function documentSpanLocation({ fileName, textSpan }: DocumentSpan): sourcemaps.SourceMappableLocation {
|
||||
return { fileName, position: textSpan.start };
|
||||
function documentSpanLocation({ fileName, textSpan }: DocumentSpan): DocumentPosition {
|
||||
return { fileName, pos: textSpan.start };
|
||||
}
|
||||
|
||||
function getMappedLocation(location: sourcemaps.SourceMappableLocation, projectService: ProjectService, project: Project): sourcemaps.SourceMappableLocation | undefined {
|
||||
const mapsTo = project.getSourceMapper().tryGetOriginalLocation(location);
|
||||
function getMappedLocation(location: DocumentPosition, projectService: ProjectService, project: Project): DocumentPosition | undefined {
|
||||
const mapsTo = project.getSourceMapper().tryGetSourcePosition(location);
|
||||
return mapsTo && projectService.fileExists(toNormalizedPath(mapsTo.fileName)) ? mapsTo : undefined;
|
||||
}
|
||||
|
||||
@@ -576,7 +594,7 @@ namespace ts.server {
|
||||
break;
|
||||
case ProjectLoadingFinishEvent:
|
||||
const { project: finishProject } = event.data;
|
||||
this.event<protocol.ProjectLoadingFinishEventBody>({ projectName: finishProject.getProjectName() }, ProjectLoadingStartEvent);
|
||||
this.event<protocol.ProjectLoadingFinishEventBody>({ projectName: finishProject.getProjectName() }, ProjectLoadingFinishEvent);
|
||||
break;
|
||||
case LargeFileReferencedEvent:
|
||||
const { file, fileSize, maxFileSize } = event.data;
|
||||
@@ -688,7 +706,26 @@ namespace ts.server {
|
||||
success,
|
||||
};
|
||||
if (success) {
|
||||
res.body = info;
|
||||
let metadata: unknown;
|
||||
if (isArray(info)) {
|
||||
res.body = info;
|
||||
metadata = (info as WithMetadata<ReadonlyArray<any>>).metadata;
|
||||
delete (info as WithMetadata<ReadonlyArray<any>>).metadata;
|
||||
}
|
||||
else if (typeof info === "object") {
|
||||
if ((info as WithMetadata<{}>).metadata) {
|
||||
const { metadata: infoMetadata, ...body } = (info as WithMetadata<{}>);
|
||||
res.body = body;
|
||||
metadata = infoMetadata;
|
||||
}
|
||||
else {
|
||||
res.body = info;
|
||||
}
|
||||
}
|
||||
else {
|
||||
res.body = info;
|
||||
}
|
||||
if (metadata) res.metadata = metadata;
|
||||
}
|
||||
else {
|
||||
Debug.assert(info === undefined);
|
||||
@@ -904,7 +941,7 @@ namespace ts.server {
|
||||
kind: info.kind,
|
||||
name: info.name,
|
||||
textSpan: {
|
||||
start: newLoc.position,
|
||||
start: newLoc.pos,
|
||||
length: info.textSpan.length
|
||||
},
|
||||
originalFileName: info.fileName,
|
||||
@@ -1001,7 +1038,7 @@ namespace ts.server {
|
||||
kind: info.kind,
|
||||
displayParts: info.displayParts,
|
||||
textSpan: {
|
||||
start: newLoc.position,
|
||||
start: newLoc.pos,
|
||||
length: info.textSpan.length
|
||||
},
|
||||
originalFileName: info.fileName,
|
||||
@@ -1157,7 +1194,9 @@ namespace ts.server {
|
||||
this.projectService.getScriptInfoEnsuringProjectsUptoDate(args.file) :
|
||||
this.projectService.getScriptInfo(args.file);
|
||||
if (!scriptInfo) {
|
||||
return ignoreNoProjectError ? emptyArray : Errors.ThrowNoProject();
|
||||
if (ignoreNoProjectError) return emptyArray;
|
||||
this.projectService.logErrorForScriptInfoNotFound(args.file);
|
||||
return Errors.ThrowNoProject();
|
||||
}
|
||||
projects = scriptInfo.containingProjects;
|
||||
symLinkedProjects = this.projectService.getSymlinkedProjects(scriptInfo);
|
||||
@@ -1165,6 +1204,7 @@ namespace ts.server {
|
||||
// filter handles case when 'projects' is undefined
|
||||
projects = filter(projects, p => p.languageServiceEnabled && !p.isOrphan());
|
||||
if (!ignoreNoProjectError && (!projects || !projects.length) && !symLinkedProjects) {
|
||||
this.projectService.logErrorForScriptInfoNotFound(args.file);
|
||||
return Errors.ThrowNoProject();
|
||||
}
|
||||
return symLinkedProjects ? { projects: projects!, symLinkedProjects } : projects!; // TODO: GH#18217
|
||||
@@ -1186,7 +1226,13 @@ namespace ts.server {
|
||||
const position = this.getPositionInFile(args, file);
|
||||
const projects = this.getProjects(args);
|
||||
|
||||
const locations = combineProjectOutputForRenameLocations(projects, this.getDefaultProject(args), { fileName: args.file, position }, this.projectService, !!args.findInStrings, !!args.findInComments);
|
||||
const locations = combineProjectOutputForRenameLocations(
|
||||
projects,
|
||||
this.getDefaultProject(args),
|
||||
{ fileName: args.file, pos: position },
|
||||
!!args.findInStrings,
|
||||
!!args.findInComments
|
||||
);
|
||||
if (!simplifiedResult) return locations;
|
||||
|
||||
const defaultProject = this.getDefaultProject(args);
|
||||
@@ -1220,7 +1266,11 @@ namespace ts.server {
|
||||
const file = toNormalizedPath(args.file);
|
||||
const projects = this.getProjects(args);
|
||||
const position = this.getPositionInFile(args, file);
|
||||
const references = combineProjectOutputForReferences(projects, this.getDefaultProject(args), { fileName: args.file, position }, this.projectService);
|
||||
const references = combineProjectOutputForReferences(
|
||||
projects,
|
||||
this.getDefaultProject(args),
|
||||
{ fileName: args.file, pos: position },
|
||||
);
|
||||
|
||||
if (simplifiedResult) {
|
||||
const defaultProject = this.getDefaultProject(args);
|
||||
@@ -1230,7 +1280,7 @@ namespace ts.server {
|
||||
const nameSpan = nameInfo && nameInfo.textSpan;
|
||||
const symbolStartOffset = nameSpan ? scriptInfo.positionToLineOffset(nameSpan.start).offset : 0;
|
||||
const symbolName = nameSpan ? scriptInfo.getSnapshot().getText(nameSpan.start, textSpanEnd(nameSpan)) : "";
|
||||
const refs: protocol.ReferencesResponseItem[] = flatMap(references, referencedSymbol =>
|
||||
const refs: ReadonlyArray<protocol.ReferencesResponseItem> = flatMap(references, referencedSymbol =>
|
||||
referencedSymbol.references.map(({ fileName, textSpan, isWriteAccess, isDefinition }): protocol.ReferencesResponseItem => {
|
||||
const scriptInfo = Debug.assertDefined(this.projectService.getScriptInfo(fileName));
|
||||
const start = scriptInfo.positionToLineOffset(textSpan.start);
|
||||
@@ -1464,7 +1514,7 @@ namespace ts.server {
|
||||
});
|
||||
}
|
||||
|
||||
private getCompletions(args: protocol.CompletionsRequestArgs, kind: protocol.CommandTypes.CompletionInfo | protocol.CommandTypes.Completions | protocol.CommandTypes.CompletionsFull): ReadonlyArray<protocol.CompletionEntry> | protocol.CompletionInfo | CompletionInfo | undefined {
|
||||
private getCompletions(args: protocol.CompletionsRequestArgs, kind: protocol.CommandTypes.CompletionInfo | protocol.CommandTypes.Completions | protocol.CommandTypes.CompletionsFull): WithMetadata<ReadonlyArray<protocol.CompletionEntry>> | protocol.CompletionInfo | CompletionInfo | undefined {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
@@ -1489,7 +1539,10 @@ namespace ts.server {
|
||||
}
|
||||
}).sort((a, b) => compareStringsCaseSensitiveUI(a.name, b.name));
|
||||
|
||||
if (kind === protocol.CommandTypes.Completions) return entries;
|
||||
if (kind === protocol.CommandTypes.Completions) {
|
||||
if (completions.metadata) (entries as WithMetadata<ReadonlyArray<protocol.CompletionEntry>>).metadata = completions.metadata;
|
||||
return entries;
|
||||
}
|
||||
|
||||
const res: protocol.CompletionInfo = {
|
||||
...completions,
|
||||
@@ -1724,7 +1777,6 @@ namespace ts.server {
|
||||
return combineProjectOutputWhileOpeningReferencedProjects<NavigateToItem>(
|
||||
this.getProjects(args),
|
||||
this.getDefaultProject(args),
|
||||
this.projectService,
|
||||
project =>
|
||||
project.getLanguageService().getNavigateToItems(searchValue, maxResultCount, /*fileName*/ undefined, /*excludeDts*/ project.isNonTsProject()),
|
||||
documentSpanLocation,
|
||||
@@ -1908,8 +1960,17 @@ namespace ts.server {
|
||||
return textChanges.map(change => this.mapTextChangeToCodeEdit(change));
|
||||
}
|
||||
|
||||
private mapTextChangeToCodeEdit(change: FileTextChanges): protocol.FileCodeEdits {
|
||||
return mapTextChangesToCodeEdits(change, this.projectService.getScriptInfoOrConfig(change.fileName));
|
||||
private mapTextChangeToCodeEdit(textChanges: FileTextChanges): protocol.FileCodeEdits {
|
||||
const scriptInfo = this.projectService.getScriptInfoOrConfig(textChanges.fileName);
|
||||
if (!!textChanges.isNewFile === !!scriptInfo) {
|
||||
if (!scriptInfo) { // and !isNewFile
|
||||
this.projectService.logErrorForScriptInfoNotFound(textChanges.fileName);
|
||||
}
|
||||
Debug.fail("Expected isNewFile for (only) new files. " + JSON.stringify({ isNewFile: !!textChanges.isNewFile, hasScriptInfo: !!scriptInfo }));
|
||||
}
|
||||
return scriptInfo
|
||||
? { fileName: textChanges.fileName, textChanges: textChanges.textChanges.map(textChange => convertTextChangeToCodeEdit(textChange, scriptInfo)) }
|
||||
: convertNewFileTextChangeToCodeEdit(textChanges);
|
||||
}
|
||||
|
||||
private convertTextChangeToCodeEdit(change: TextChange, scriptInfo: ScriptInfo): protocol.CodeEdit {
|
||||
@@ -1983,6 +2044,10 @@ namespace ts.server {
|
||||
this.updateErrorCheck(next, checkList, delay, /*requireOpen*/ false);
|
||||
}
|
||||
|
||||
private configurePlugin(args: protocol.ConfigurePluginRequestArguments) {
|
||||
this.projectService.configurePlugin(args);
|
||||
}
|
||||
|
||||
getCanonicalFileName(fileName: string) {
|
||||
const name = this.host.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
return normalizePath(name);
|
||||
@@ -2304,6 +2369,10 @@ namespace ts.server {
|
||||
[CommandNames.GetEditsForFileRenameFull]: (request: protocol.GetEditsForFileRenameRequest) => {
|
||||
return this.requiredResponse(this.getEditsForFileRename(request.arguments, /*simplifiedResult*/ false));
|
||||
},
|
||||
[CommandNames.ConfigurePlugin]: (request: protocol.ConfigurePluginRequest) => {
|
||||
this.configurePlugin(request.arguments);
|
||||
return this.notRequired();
|
||||
}
|
||||
});
|
||||
|
||||
public addProtocolHandler(command: string, handler: (request: protocol.Request) => HandlerResponse) {
|
||||
@@ -2423,13 +2492,6 @@ namespace ts.server {
|
||||
return { file: fileName, start: scriptInfo.positionToLineOffset(textSpan.start), end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan)) };
|
||||
}
|
||||
|
||||
function mapTextChangesToCodeEdits(textChanges: FileTextChanges, scriptInfo: ScriptInfoOrConfig | undefined): protocol.FileCodeEdits {
|
||||
Debug.assert(!!textChanges.isNewFile === !scriptInfo, "Expected isNewFile for (only) new files", () => JSON.stringify({ isNewFile: !!textChanges.isNewFile, hasScriptInfo: !!scriptInfo }));
|
||||
return scriptInfo
|
||||
? { fileName: textChanges.fileName, textChanges: textChanges.textChanges.map(textChange => convertTextChangeToCodeEdit(textChange, scriptInfo)) }
|
||||
: convertNewFileTextChangeToCodeEdit(textChanges);
|
||||
}
|
||||
|
||||
function convertTextChangeToCodeEdit(change: TextChange, scriptInfo: ScriptInfoOrConfig): protocol.CodeEdit {
|
||||
return { start: positionToLineOffset(scriptInfo, change.span.start), end: positionToLineOffset(scriptInfo, textSpanEnd(change.span)), newText: change.newText };
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
updateTypingsForProject(projectName: string, compilerOptions: CompilerOptions, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray<string>, newTypings: string[]) {
|
||||
const typings = toSortedArray(newTypings);
|
||||
const typings = sort(newTypings);
|
||||
this.perProjectCache.set(projectName, {
|
||||
compilerOptions,
|
||||
typeAcquisition,
|
||||
|
||||
@@ -206,31 +206,13 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
export function toSortedArray(arr: string[]): SortedArray<string>;
|
||||
export function toSortedArray<T>(arr: T[], comparer: Comparer<T>): SortedArray<T>;
|
||||
export function toSortedArray<T>(arr: T[], comparer?: Comparer<T>): SortedArray<T> {
|
||||
arr.sort(comparer);
|
||||
return arr as SortedArray<T>;
|
||||
}
|
||||
|
||||
export function toDeduplicatedSortedArray(arr: string[]): SortedArray<string> {
|
||||
arr.sort();
|
||||
filterMutate(arr, isNonDuplicateInSortedArray);
|
||||
return arr as SortedArray<string>;
|
||||
}
|
||||
function isNonDuplicateInSortedArray<T>(value: T, index: number, array: T[]) {
|
||||
return index === 0 || value !== array[index - 1];
|
||||
}
|
||||
|
||||
const indentStr = "\n ";
|
||||
|
||||
/* @internal */
|
||||
export function indent(str: string): string {
|
||||
return indentStr + str.replace(/\n/g, indentStr);
|
||||
}
|
||||
|
||||
/** Put stringified JSON on the next line, indented. */
|
||||
/* @internal */
|
||||
export function stringifyIndented(json: {}): string {
|
||||
return indentStr + JSON.stringify(json);
|
||||
}
|
||||
|
||||
@@ -182,6 +182,7 @@ namespace ts {
|
||||
SyntaxKind.Identifier,
|
||||
SyntaxKind.StringLiteral,
|
||||
SyntaxKind.NumericLiteral,
|
||||
SyntaxKind.BigIntLiteral,
|
||||
SyntaxKind.RegularExpressionLiteral,
|
||||
SyntaxKind.ThisKeyword,
|
||||
SyntaxKind.PlusPlusToken,
|
||||
@@ -286,6 +287,7 @@ namespace ts {
|
||||
case ClassificationType.comment: return TokenClass.Comment;
|
||||
case ClassificationType.keyword: return TokenClass.Keyword;
|
||||
case ClassificationType.numericLiteral: return TokenClass.NumberLiteral;
|
||||
case ClassificationType.bigintLiteral: return TokenClass.BigIntLiteral;
|
||||
case ClassificationType.operator: return TokenClass.Operator;
|
||||
case ClassificationType.stringLiteral: return TokenClass.StringLiteral;
|
||||
case ClassificationType.whiteSpace: return TokenClass.Whitespace;
|
||||
@@ -422,6 +424,8 @@ namespace ts {
|
||||
switch (token) {
|
||||
case SyntaxKind.NumericLiteral:
|
||||
return ClassificationType.numericLiteral;
|
||||
case SyntaxKind.BigIntLiteral:
|
||||
return ClassificationType.bigintLiteral;
|
||||
case SyntaxKind.StringLiteral:
|
||||
return ClassificationType.stringLiteral;
|
||||
case SyntaxKind.RegularExpressionLiteral:
|
||||
@@ -542,6 +546,7 @@ namespace ts {
|
||||
case ClassificationType.identifier: return ClassificationTypeNames.identifier;
|
||||
case ClassificationType.keyword: return ClassificationTypeNames.keyword;
|
||||
case ClassificationType.numericLiteral: return ClassificationTypeNames.numericLiteral;
|
||||
case ClassificationType.bigintLiteral: return ClassificationTypeNames.bigintLiteral;
|
||||
case ClassificationType.operator: return ClassificationTypeNames.operator;
|
||||
case ClassificationType.stringLiteral: return ClassificationTypeNames.stringLiteral;
|
||||
case ClassificationType.whiteSpace: return ClassificationTypeNames.whiteSpace;
|
||||
@@ -698,7 +703,7 @@ namespace ts {
|
||||
pushCommentRange(pos, tag.pos - pos);
|
||||
}
|
||||
|
||||
pushClassification(tag.atToken.pos, tag.atToken.end - tag.atToken.pos, ClassificationType.punctuation); // "@"
|
||||
pushClassification(tag.pos, 1, ClassificationType.punctuation); // "@"
|
||||
pushClassification(tag.tagName.pos, tag.tagName.end - tag.tagName.pos, ClassificationType.docCommentTagName); // e.g. "param"
|
||||
|
||||
pos = tag.tagName.end;
|
||||
@@ -886,6 +891,9 @@ namespace ts {
|
||||
else if (tokenKind === SyntaxKind.NumericLiteral) {
|
||||
return ClassificationType.numericLiteral;
|
||||
}
|
||||
else if (tokenKind === SyntaxKind.BigIntLiteral) {
|
||||
return ClassificationType.bigintLiteral;
|
||||
}
|
||||
else if (tokenKind === SyntaxKind.StringLiteral) {
|
||||
// TODO: GH#18217
|
||||
return token!.parent.kind === SyntaxKind.JsxAttribute ? ClassificationType.jsxAttributeStringLiteralValue : ClassificationType.stringLiteral;
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace ts {
|
||||
return arrayFrom(errorCodeToFixes.keys());
|
||||
}
|
||||
|
||||
export function getFixes(context: CodeFixContext): CodeFixAction[] {
|
||||
export function getFixes(context: CodeFixContext): ReadonlyArray<CodeFixAction> {
|
||||
return flatMap(errorCodeToFixes.get(String(context.errorCode)) || emptyArray, f => f.getCodeActions(context));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
const fixId = "addConvertToUnknownForNonOverlappingTypes";
|
||||
const errorCodes = [Diagnostics.Conversion_of_type_0_to_type_1_may_be_a_mistake_because_neither_type_sufficiently_overlaps_with_the_other_If_this_was_intentional_convert_the_expression_to_unknown_first.code];
|
||||
registerCodeFix({
|
||||
errorCodes,
|
||||
getCodeActions: (context) => {
|
||||
const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span.start));
|
||||
return [createCodeFixAction(fixId, changes, Diagnostics.Add_unknown_conversion_for_non_overlapping_types, fixId, Diagnostics.Add_unknown_to_all_conversions_of_non_overlapping_types)];
|
||||
},
|
||||
fixIds: [fixId],
|
||||
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag.start)),
|
||||
});
|
||||
|
||||
function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number) {
|
||||
const token = getTokenAtPosition(sourceFile, pos);
|
||||
const assertion = Debug.assertDefined(findAncestor(token, (n): n is AsExpression | TypeAssertion => isAsExpression(n) || isTypeAssertion(n)));
|
||||
const replacement = isAsExpression(assertion)
|
||||
? createAsExpression(assertion.expression, createKeywordTypeNode(SyntaxKind.UnknownKeyword))
|
||||
: createTypeAssertion(createKeywordTypeNode(SyntaxKind.UnknownKeyword), assertion.expression);
|
||||
changeTracker.replaceNode(sourceFile, assertion.expression, replacement);
|
||||
}
|
||||
}
|
||||
@@ -185,6 +185,10 @@ namespace ts.codefix {
|
||||
const widenedType = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(otherExpression)));
|
||||
typeNode = checker.typeToTypeNode(widenedType, classDeclaration);
|
||||
}
|
||||
else {
|
||||
const contextualType = checker.getContextualType(token.parent as Expression);
|
||||
typeNode = contextualType ? checker.typeToTypeNode(contextualType) : undefined;
|
||||
}
|
||||
return typeNode || createKeywordTypeNode(SyntaxKind.AnyKeyword);
|
||||
}
|
||||
|
||||
|
||||
@@ -181,8 +181,8 @@ namespace ts.codefix {
|
||||
|
||||
function deleteAssignments(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Identifier, checker: TypeChecker) {
|
||||
FindAllReferences.Core.eachSymbolReferenceInFile(token, checker, sourceFile, (ref: Node) => {
|
||||
if (ref.parent.kind === SyntaxKind.PropertyAccessExpression) ref = ref.parent;
|
||||
if (ref.parent.kind === SyntaxKind.BinaryExpression && ref.parent.parent.kind === SyntaxKind.ExpressionStatement) {
|
||||
if (isPropertyAccessExpression(ref.parent) && ref.parent.name === ref) ref = ref.parent;
|
||||
if (isBinaryExpression(ref.parent) && isExpressionStatement(ref.parent.parent) && ref.parent.left === ref) {
|
||||
changes.delete(sourceFile, ref.parent.parent);
|
||||
}
|
||||
});
|
||||
@@ -200,8 +200,16 @@ namespace ts.codefix {
|
||||
|
||||
function tryDeleteParameter(changes: textChanges.ChangeTracker, sourceFile: SourceFile, p: ParameterDeclaration, checker: TypeChecker, sourceFiles: ReadonlyArray<SourceFile>, isFixAll: boolean): void {
|
||||
if (mayDeleteParameter(p, checker, isFixAll)) {
|
||||
changes.delete(sourceFile, p);
|
||||
deleteUnusedArguments(changes, sourceFile, p, sourceFiles, checker);
|
||||
if (p.modifiers && p.modifiers.length > 0
|
||||
&& (!isIdentifier(p.name) || FindAllReferences.Core.isSymbolReferencedInFile(p.name, checker, sourceFile))) {
|
||||
p.modifiers.forEach(modifier => {
|
||||
changes.deleteModifier(sourceFile, modifier);
|
||||
});
|
||||
}
|
||||
else {
|
||||
changes.delete(sourceFile, p);
|
||||
deleteUnusedArguments(changes, sourceFile, p, sourceFiles, checker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -289,7 +289,7 @@ namespace ts.codefix {
|
||||
// `position` should only be undefined at a missing jsx namespace, in which case we shouldn't be looking for pure types.
|
||||
exportedSymbolIsTypeOnly && isJs ? { kind: ImportFixKind.ImportType, moduleSpecifier, position: Debug.assertDefined(position) } : { kind: ImportFixKind.AddNew, moduleSpecifier, importKind }));
|
||||
// Sort to keep the shortest paths first
|
||||
return choicesForEachExportingModule.sort((a, b) => a.moduleSpecifier.length - b.moduleSpecifier.length);
|
||||
return sort(choicesForEachExportingModule, (a, b) => a.moduleSpecifier.length - b.moduleSpecifier.length);
|
||||
}
|
||||
|
||||
function getFixesForAddImport(
|
||||
|
||||
@@ -21,6 +21,27 @@ namespace ts.codefix {
|
||||
|
||||
// Property declarations
|
||||
Diagnostics.Member_0_implicitly_has_an_1_type.code,
|
||||
|
||||
//// Suggestions
|
||||
// Variable declarations
|
||||
Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_but_a_better_type_may_be_inferred_from_usage.code,
|
||||
|
||||
// Variable uses
|
||||
Diagnostics.Variable_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code,
|
||||
|
||||
// Parameter declarations
|
||||
Diagnostics.Parameter_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code,
|
||||
Diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage.code,
|
||||
|
||||
// Get Accessor declarations
|
||||
Diagnostics.Property_0_implicitly_has_type_any_but_a_better_type_for_its_get_accessor_may_be_inferred_from_usage.code,
|
||||
Diagnostics._0_implicitly_has_an_1_return_type_but_a_better_type_may_be_inferred_from_usage.code,
|
||||
|
||||
// Set Accessor declarations
|
||||
Diagnostics.Property_0_implicitly_has_type_any_but_a_better_type_for_its_set_accessor_may_be_inferred_from_usage.code,
|
||||
|
||||
// Property declarations
|
||||
Diagnostics.Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code,
|
||||
];
|
||||
registerCodeFix({
|
||||
errorCodes,
|
||||
@@ -47,20 +68,46 @@ namespace ts.codefix {
|
||||
function getDiagnostic(errorCode: number, token: Node): DiagnosticMessage {
|
||||
switch (errorCode) {
|
||||
case Diagnostics.Parameter_0_implicitly_has_an_1_type.code:
|
||||
case Diagnostics.Parameter_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code:
|
||||
return isSetAccessorDeclaration(getContainingFunction(token)!) ? Diagnostics.Infer_type_of_0_from_usage : Diagnostics.Infer_parameter_types_from_usage; // TODO: GH#18217
|
||||
case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code:
|
||||
case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage.code:
|
||||
return Diagnostics.Infer_parameter_types_from_usage;
|
||||
default:
|
||||
return Diagnostics.Infer_type_of_0_from_usage;
|
||||
}
|
||||
}
|
||||
|
||||
/** Map suggestion code to error code */
|
||||
function mapSuggestionDiagnostic(errorCode: number) {
|
||||
switch (errorCode) {
|
||||
case Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_but_a_better_type_may_be_inferred_from_usage.code:
|
||||
return Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined.code;
|
||||
case Diagnostics.Variable_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code:
|
||||
return Diagnostics.Variable_0_implicitly_has_an_1_type.code;
|
||||
case Diagnostics.Parameter_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code:
|
||||
return Diagnostics.Parameter_0_implicitly_has_an_1_type.code;
|
||||
case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage.code:
|
||||
return Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code;
|
||||
case Diagnostics.Property_0_implicitly_has_type_any_but_a_better_type_for_its_get_accessor_may_be_inferred_from_usage.code:
|
||||
return Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation.code;
|
||||
case Diagnostics._0_implicitly_has_an_1_return_type_but_a_better_type_may_be_inferred_from_usage.code:
|
||||
return Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type.code;
|
||||
case Diagnostics.Property_0_implicitly_has_type_any_but_a_better_type_for_its_set_accessor_may_be_inferred_from_usage.code:
|
||||
return Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation.code;
|
||||
case Diagnostics.Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code:
|
||||
return Diagnostics.Member_0_implicitly_has_an_1_type.code;
|
||||
}
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node, errorCode: number, program: Program, cancellationToken: CancellationToken, markSeen: NodeSeenTracker, host: LanguageServiceHost): Declaration | undefined {
|
||||
if (!isParameterPropertyModifier(token.kind) && token.kind !== SyntaxKind.Identifier && token.kind !== SyntaxKind.DotDotDotToken && token.kind !== SyntaxKind.ThisKeyword) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const { parent } = token;
|
||||
errorCode = mapSuggestionDiagnostic(errorCode);
|
||||
switch (errorCode) {
|
||||
// Variable and Property declarations
|
||||
case Diagnostics.Member_0_implicitly_has_an_1_type.code:
|
||||
@@ -71,7 +118,7 @@ namespace ts.codefix {
|
||||
}
|
||||
if (isPropertyAccessExpression(parent)) {
|
||||
const type = inferTypeForVariableFromUsage(parent.name, program, cancellationToken);
|
||||
const typeNode = type && getTypeNodeIfAccessible(type, parent, program, host);
|
||||
const typeNode = getTypeNodeIfAccessible(type, parent, program, host);
|
||||
if (typeNode) {
|
||||
// Note that the codefix will never fire with an existing `@type` tag, so there is no need to merge tags
|
||||
const typeTag = createJSDocTypeTag(createJSDocTypeExpression(typeNode), /*comment*/ "");
|
||||
@@ -107,7 +154,7 @@ namespace ts.codefix {
|
||||
case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code:
|
||||
if (markSeen(containingFunction)) {
|
||||
const param = cast(parent, isParameter);
|
||||
annotateParameters(changes, param, containingFunction, sourceFile, program, host, cancellationToken);
|
||||
annotateParameters(changes, sourceFile, param, containingFunction, program, host, cancellationToken);
|
||||
return param;
|
||||
}
|
||||
return undefined;
|
||||
@@ -147,12 +194,13 @@ namespace ts.codefix {
|
||||
case SyntaxKind.Constructor:
|
||||
return true;
|
||||
case SyntaxKind.FunctionExpression:
|
||||
return !!declaration.name;
|
||||
const parent = declaration.parent;
|
||||
return isVariableDeclaration(parent) && isIdentifier(parent.name) || !!declaration.name;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function annotateParameters(changes: textChanges.ChangeTracker, parameterDeclaration: ParameterDeclaration, containingFunction: FunctionLike, sourceFile: SourceFile, program: Program, host: LanguageServiceHost, cancellationToken: CancellationToken): void {
|
||||
function annotateParameters(changes: textChanges.ChangeTracker, sourceFile: SourceFile, parameterDeclaration: ParameterDeclaration, containingFunction: FunctionLike, program: Program, host: LanguageServiceHost, cancellationToken: CancellationToken): void {
|
||||
if (!isIdentifier(parameterDeclaration.name) || !isApplicableFunctionForInference(containingFunction)) {
|
||||
return;
|
||||
}
|
||||
@@ -160,7 +208,7 @@ namespace ts.codefix {
|
||||
const parameterInferences = inferTypeForParametersFromUsage(containingFunction, sourceFile, program, cancellationToken) ||
|
||||
containingFunction.parameters.map<ParameterInference>(p => ({
|
||||
declaration: p,
|
||||
type: isIdentifier(p.name) ? inferTypeForVariableFromUsage(p.name, program, cancellationToken) : undefined
|
||||
type: isIdentifier(p.name) ? inferTypeForVariableFromUsage(p.name, program, cancellationToken) : program.getTypeChecker().getAnyType()
|
||||
}));
|
||||
Debug.assert(containingFunction.parameters.length === parameterInferences.length);
|
||||
|
||||
@@ -179,8 +227,10 @@ namespace ts.codefix {
|
||||
function annotateSetAccessor(changes: textChanges.ChangeTracker, sourceFile: SourceFile, setAccessorDeclaration: SetAccessorDeclaration, program: Program, host: LanguageServiceHost, cancellationToken: CancellationToken): void {
|
||||
const param = firstOrUndefined(setAccessorDeclaration.parameters);
|
||||
if (param && isIdentifier(setAccessorDeclaration.name) && isIdentifier(param.name)) {
|
||||
const type = inferTypeForVariableFromUsage(setAccessorDeclaration.name, program, cancellationToken) ||
|
||||
inferTypeForVariableFromUsage(param.name, program, cancellationToken);
|
||||
let type = inferTypeForVariableFromUsage(setAccessorDeclaration.name, program, cancellationToken);
|
||||
if (type === program.getTypeChecker().getAnyType()) {
|
||||
type = inferTypeForVariableFromUsage(param.name, program, cancellationToken);
|
||||
}
|
||||
if (isInJSFile(setAccessorDeclaration)) {
|
||||
annotateJSDocParameters(changes, sourceFile, [{ declaration: param, type }], program, host);
|
||||
}
|
||||
@@ -190,8 +240,8 @@ namespace ts.codefix {
|
||||
}
|
||||
}
|
||||
|
||||
function annotate(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: textChanges.TypeAnnotatable, type: Type | undefined, program: Program, host: LanguageServiceHost): void {
|
||||
const typeNode = type && getTypeNodeIfAccessible(type, declaration, program, host);
|
||||
function annotate(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: textChanges.TypeAnnotatable, type: Type, program: Program, host: LanguageServiceHost): void {
|
||||
const typeNode = getTypeNodeIfAccessible(type, declaration, program, host);
|
||||
if (typeNode) {
|
||||
if (isInJSFile(sourceFile) && declaration.kind !== SyntaxKind.PropertySignature) {
|
||||
const parent = isVariableDeclaration(declaration) ? tryCast(declaration.parent.parent, isVariableStatement) : declaration;
|
||||
@@ -228,7 +278,7 @@ namespace ts.codefix {
|
||||
|
||||
function addJSDocTags(changes: textChanges.ChangeTracker, sourceFile: SourceFile, parent: HasJSDoc, newTags: ReadonlyArray<JSDocTag>): void {
|
||||
const comments = mapDefined(parent.jsDoc, j => j.comment);
|
||||
const oldTags = flatMap(parent.jsDoc, j => j.tags);
|
||||
const oldTags = flatMapToMutable(parent.jsDoc, j => j.tags);
|
||||
const unmergedNewTags = newTags.filter(newTag => !oldTags || !oldTags.some((tag, i) => {
|
||||
const merged = tryMergeJsdocTags(tag, newTag);
|
||||
if (merged) oldTags[i] = merged;
|
||||
@@ -285,29 +335,38 @@ namespace ts.codefix {
|
||||
entry.kind !== FindAllReferences.EntryKind.Span ? tryCast(entry.node, isIdentifier) : undefined);
|
||||
}
|
||||
|
||||
function inferTypeForVariableFromUsage(token: Identifier, program: Program, cancellationToken: CancellationToken): Type | undefined {
|
||||
return InferFromReference.inferTypeFromReferences(getReferences(token, program, cancellationToken), program.getTypeChecker(), cancellationToken);
|
||||
function inferTypeForVariableFromUsage(token: Identifier, program: Program, cancellationToken: CancellationToken): Type {
|
||||
const references = getReferences(token, program, cancellationToken);
|
||||
const checker = program.getTypeChecker();
|
||||
const types = InferFromReference.inferTypesFromReferences(references, checker, cancellationToken);
|
||||
return InferFromReference.unifyFromContext(types, checker);
|
||||
}
|
||||
|
||||
function inferTypeForParametersFromUsage(containingFunction: FunctionLikeDeclaration, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
|
||||
let searchToken;
|
||||
switch (containingFunction.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
searchToken = findChildOfKind<Token<SyntaxKind.ConstructorKeyword>>(containingFunction, SyntaxKind.ConstructorKeyword, sourceFile);
|
||||
break;
|
||||
case SyntaxKind.FunctionExpression:
|
||||
const parent = containingFunction.parent;
|
||||
searchToken = isVariableDeclaration(parent) && isIdentifier(parent.name) ?
|
||||
parent.name :
|
||||
containingFunction.name;
|
||||
break;
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
const isConstructor = containingFunction.kind === SyntaxKind.Constructor;
|
||||
const searchToken = isConstructor ?
|
||||
findChildOfKind<Token<SyntaxKind.ConstructorKeyword>>(containingFunction, SyntaxKind.ConstructorKeyword, sourceFile) :
|
||||
containingFunction.name;
|
||||
if (searchToken) {
|
||||
return InferFromReference.inferTypeForParametersFromReferences(getReferences(searchToken, program, cancellationToken), containingFunction, program.getTypeChecker(), cancellationToken);
|
||||
}
|
||||
searchToken = containingFunction.name;
|
||||
break;
|
||||
}
|
||||
if (searchToken) {
|
||||
return InferFromReference.inferTypeForParametersFromReferences(getReferences(searchToken, program, cancellationToken), containingFunction, program, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
interface ParameterInference {
|
||||
readonly declaration: ParameterDeclaration;
|
||||
readonly type?: Type;
|
||||
readonly type: Type;
|
||||
readonly isOptional?: boolean;
|
||||
}
|
||||
|
||||
@@ -320,7 +379,9 @@ namespace ts.codefix {
|
||||
interface UsageContext {
|
||||
isNumber?: boolean;
|
||||
isString?: boolean;
|
||||
isNumberOrString?: boolean;
|
||||
hasNonVacuousType?: boolean;
|
||||
hasNonVacuousNonAnonymousType?: boolean;
|
||||
|
||||
candidateTypes?: Type[];
|
||||
properties?: UnderscoreEscapedMap<UsageContext>;
|
||||
callContexts?: CallContext[];
|
||||
@@ -329,20 +390,20 @@ namespace ts.codefix {
|
||||
stringIndexContext?: UsageContext;
|
||||
}
|
||||
|
||||
export function inferTypeFromReferences(references: ReadonlyArray<Identifier>, checker: TypeChecker, cancellationToken: CancellationToken): Type | undefined {
|
||||
export function inferTypesFromReferences(references: ReadonlyArray<Identifier>, checker: TypeChecker, cancellationToken: CancellationToken): Type[] {
|
||||
const usageContext: UsageContext = {};
|
||||
for (const reference of references) {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
inferTypeFromContext(reference, checker, usageContext);
|
||||
}
|
||||
return getTypeFromUsageContext(usageContext, checker);
|
||||
return inferFromContext(usageContext, checker);
|
||||
}
|
||||
|
||||
export function inferTypeForParametersFromReferences(references: ReadonlyArray<Identifier>, declaration: FunctionLikeDeclaration, checker: TypeChecker, cancellationToken: CancellationToken): ParameterInference[] | undefined {
|
||||
export function inferTypeForParametersFromReferences(references: ReadonlyArray<Identifier>, declaration: FunctionLikeDeclaration, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
|
||||
const checker = program.getTypeChecker();
|
||||
if (references.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!declaration.parameters) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -361,10 +422,9 @@ namespace ts.codefix {
|
||||
for (const callContext of callContexts) {
|
||||
if (callContext.argumentTypes.length <= parameterIndex) {
|
||||
isOptional = isInJSFile(declaration);
|
||||
continue;
|
||||
types.push(checker.getUndefinedType());
|
||||
}
|
||||
|
||||
if (isRest) {
|
||||
else if (isRest) {
|
||||
for (let i = parameterIndex; i < callContext.argumentTypes.length; i++) {
|
||||
types.push(checker.getBaseTypeOfLiteralType(callContext.argumentTypes[i]));
|
||||
}
|
||||
@@ -373,10 +433,10 @@ namespace ts.codefix {
|
||||
types.push(checker.getBaseTypeOfLiteralType(callContext.argumentTypes[parameterIndex]));
|
||||
}
|
||||
}
|
||||
if (!types.length) {
|
||||
return { declaration: parameter };
|
||||
if (isIdentifier(parameter.name)) {
|
||||
types.push(...inferTypesFromReferences(getReferences(parameter.name, program, cancellationToken), checker, cancellationToken));
|
||||
}
|
||||
const type = checker.getWidenedType(checker.getUnionType(types, UnionReduction.Subtype));
|
||||
const type = unifyFromContext(types, checker);
|
||||
return {
|
||||
type: isRest ? checker.createArrayType(type) : type,
|
||||
isOptional: isOptional && !isRest,
|
||||
@@ -450,7 +510,8 @@ namespace ts.codefix {
|
||||
break;
|
||||
|
||||
case SyntaxKind.PlusToken:
|
||||
usageContext.isNumberOrString = true;
|
||||
usageContext.isNumber = true;
|
||||
usageContext.isString = true;
|
||||
break;
|
||||
|
||||
// case SyntaxKind.ExclamationToken:
|
||||
@@ -521,7 +582,8 @@ namespace ts.codefix {
|
||||
usageContext.isString = true;
|
||||
}
|
||||
else {
|
||||
usageContext.isNumberOrString = true;
|
||||
usageContext.isNumber = true;
|
||||
usageContext.isString = true;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -595,7 +657,8 @@ namespace ts.codefix {
|
||||
|
||||
function inferTypeFromPropertyElementExpressionContext(parent: ElementAccessExpression, node: Expression, checker: TypeChecker, usageContext: UsageContext): void {
|
||||
if (node === parent.argumentExpression) {
|
||||
usageContext.isNumberOrString = true;
|
||||
usageContext.isNumber = true;
|
||||
usageContext.isString = true;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
@@ -611,29 +674,83 @@ namespace ts.codefix {
|
||||
}
|
||||
}
|
||||
|
||||
function getTypeFromUsageContext(usageContext: UsageContext, checker: TypeChecker): Type | undefined {
|
||||
if (usageContext.isNumberOrString && !usageContext.isNumber && !usageContext.isString) {
|
||||
return checker.getUnionType([checker.getNumberType(), checker.getStringType()]);
|
||||
export function unifyFromContext(inferences: ReadonlyArray<Type>, checker: TypeChecker, fallback = checker.getAnyType()): Type {
|
||||
if (!inferences.length) return fallback;
|
||||
const hasNonVacuousType = inferences.some(i => !(i.flags & (TypeFlags.Any | TypeFlags.Void)));
|
||||
const hasNonVacuousNonAnonymousType = inferences.some(
|
||||
i => !(i.flags & (TypeFlags.Nullable | TypeFlags.Any | TypeFlags.Void)) && !(checker.getObjectFlags(i) & ObjectFlags.Anonymous));
|
||||
const anons = inferences.filter(i => checker.getObjectFlags(i) & ObjectFlags.Anonymous) as AnonymousType[];
|
||||
const good = [];
|
||||
if (!hasNonVacuousNonAnonymousType && anons.length) {
|
||||
good.push(unifyAnonymousTypes(anons, checker));
|
||||
}
|
||||
else if (usageContext.isNumber) {
|
||||
return checker.getNumberType();
|
||||
good.push(...inferences.filter(i => !(checker.getObjectFlags(i) & ObjectFlags.Anonymous) && !(hasNonVacuousType && i.flags & (TypeFlags.Any | TypeFlags.Void))));
|
||||
return checker.getWidenedType(checker.getUnionType(good));
|
||||
}
|
||||
|
||||
function unifyAnonymousTypes(anons: AnonymousType[], checker: TypeChecker) {
|
||||
if (anons.length === 1) {
|
||||
return anons[0];
|
||||
}
|
||||
else if (usageContext.isString) {
|
||||
return checker.getStringType();
|
||||
const calls = [];
|
||||
const constructs = [];
|
||||
const stringIndices = [];
|
||||
const numberIndices = [];
|
||||
let stringIndexReadonly = false;
|
||||
let numberIndexReadonly = false;
|
||||
const props = createMultiMap<Type>();
|
||||
for (const anon of anons) {
|
||||
for (const p of checker.getPropertiesOfType(anon)) {
|
||||
props.add(p.name, checker.getTypeOfSymbolAtLocation(p, p.valueDeclaration));
|
||||
}
|
||||
calls.push(...checker.getSignaturesOfType(anon, SignatureKind.Call));
|
||||
constructs.push(...checker.getSignaturesOfType(anon, SignatureKind.Construct));
|
||||
if (anon.stringIndexInfo) {
|
||||
stringIndices.push(anon.stringIndexInfo.type);
|
||||
stringIndexReadonly = stringIndexReadonly || anon.stringIndexInfo.isReadonly;
|
||||
}
|
||||
if (anon.numberIndexInfo) {
|
||||
numberIndices.push(anon.numberIndexInfo.type);
|
||||
numberIndexReadonly = numberIndexReadonly || anon.numberIndexInfo.isReadonly;
|
||||
}
|
||||
}
|
||||
else if (usageContext.candidateTypes) {
|
||||
return checker.getWidenedType(checker.getUnionType(usageContext.candidateTypes.map(t => checker.getBaseTypeOfLiteralType(t)), UnionReduction.Subtype));
|
||||
const members = mapEntries(props, (name, types) => {
|
||||
const isOptional = types.length < anons.length ? SymbolFlags.Optional : 0;
|
||||
const s = checker.createSymbol(SymbolFlags.Property | isOptional, name as __String);
|
||||
s.type = checker.getUnionType(types);
|
||||
return [name, s];
|
||||
});
|
||||
return checker.createAnonymousType(
|
||||
anons[0].symbol,
|
||||
members as UnderscoreEscapedMap<TransientSymbol>,
|
||||
calls,
|
||||
constructs,
|
||||
stringIndices.length ? checker.createIndexInfo(checker.getUnionType(stringIndices), stringIndexReadonly) : undefined,
|
||||
numberIndices.length ? checker.createIndexInfo(checker.getUnionType(numberIndices), numberIndexReadonly) : undefined);
|
||||
}
|
||||
|
||||
function inferFromContext(usageContext: UsageContext, checker: TypeChecker) {
|
||||
const types = [];
|
||||
if (usageContext.isNumber) {
|
||||
types.push(checker.getNumberType());
|
||||
}
|
||||
else if (usageContext.properties && hasCallContext(usageContext.properties.get("then" as __String))) {
|
||||
if (usageContext.isString) {
|
||||
types.push(checker.getStringType());
|
||||
}
|
||||
|
||||
types.push(...(usageContext.candidateTypes || []).map(t => checker.getBaseTypeOfLiteralType(t)));
|
||||
|
||||
if (usageContext.properties && hasCallContext(usageContext.properties.get("then" as __String))) {
|
||||
const paramType = getParameterTypeFromCallContexts(0, usageContext.properties.get("then" as __String)!.callContexts!, /*isRestParameter*/ false, checker)!; // TODO: GH#18217
|
||||
const types = paramType.getCallSignatures().map(c => c.getReturnType());
|
||||
return checker.createPromiseType(types.length ? checker.getUnionType(types, UnionReduction.Subtype) : checker.getAnyType());
|
||||
types.push(checker.createPromiseType(types.length ? checker.getUnionType(types, UnionReduction.Subtype) : checker.getAnyType()));
|
||||
}
|
||||
else if (usageContext.properties && hasCallContext(usageContext.properties.get("push" as __String))) {
|
||||
return checker.createArrayType(getParameterTypeFromCallContexts(0, usageContext.properties.get("push" as __String)!.callContexts!, /*isRestParameter*/ false, checker)!);
|
||||
types.push(checker.createArrayType(getParameterTypeFromCallContexts(0, usageContext.properties.get("push" as __String)!.callContexts!, /*isRestParameter*/ false, checker)!));
|
||||
}
|
||||
else if (usageContext.numberIndexContext) {
|
||||
return checker.createArrayType(recur(usageContext.numberIndexContext));
|
||||
|
||||
if (usageContext.numberIndexContext) {
|
||||
return [checker.createArrayType(recur(usageContext.numberIndexContext))];
|
||||
}
|
||||
else if (usageContext.properties || usageContext.callContexts || usageContext.constructContexts || usageContext.stringIndexContext) {
|
||||
const members = createUnderscoreEscapedMap<Symbol>();
|
||||
@@ -665,14 +782,12 @@ namespace ts.codefix {
|
||||
stringIndexInfo = checker.createIndexInfo(recur(usageContext.stringIndexContext), /*isReadonly*/ false);
|
||||
}
|
||||
|
||||
return checker.createAnonymousType(/*symbol*/ undefined!, members, callSignatures, constructSignatures, stringIndexInfo, /*numberIndexInfo*/ undefined); // TODO: GH#18217
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
types.push(checker.createAnonymousType(/*symbol*/ undefined!, members, callSignatures, constructSignatures, stringIndexInfo, /*numberIndexInfo*/ undefined)); // TODO: GH#18217
|
||||
}
|
||||
return types;
|
||||
|
||||
function recur(innerContext: UsageContext): Type {
|
||||
return getTypeFromUsageContext(innerContext, checker) || checker.getAnyType();
|
||||
return unifyFromContext(inferFromContext(innerContext, checker), checker);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -705,7 +820,7 @@ namespace ts.codefix {
|
||||
symbol.type = checker.getWidenedType(checker.getBaseTypeOfLiteralType(callContext.argumentTypes[i]));
|
||||
parameters.push(symbol);
|
||||
}
|
||||
const returnType = getTypeFromUsageContext(callContext.returnType, checker) || checker.getVoidType();
|
||||
const returnType = unifyFromContext(inferFromContext(callContext.returnType, checker), checker, checker.getVoidType());
|
||||
// TODO: GH#18217
|
||||
return checker.createSignature(/*declaration*/ undefined!, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, callContext.argumentTypes.length, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
|
||||
}
|
||||
|
||||
+26
-291
@@ -37,18 +37,13 @@ namespace ts.Completions {
|
||||
export function getCompletionsAtPosition(host: LanguageServiceHost, program: Program, log: Log, sourceFile: SourceFile, position: number, preferences: UserPreferences, triggerCharacter: CompletionsTriggerCharacter | undefined): CompletionInfo | undefined {
|
||||
const typeChecker = program.getTypeChecker();
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
if (isInReferenceComment(sourceFile, position)) {
|
||||
const entries = PathCompletions.getTripleSlashReferenceCompletion(sourceFile, position, compilerOptions, host);
|
||||
return entries && convertPathCompletions(entries);
|
||||
}
|
||||
|
||||
const contextToken = findPrecedingToken(position, sourceFile);
|
||||
if (triggerCharacter && !isValidTrigger(sourceFile, triggerCharacter, contextToken, position)) return undefined;
|
||||
|
||||
if (isInString(sourceFile, position, contextToken)) {
|
||||
return !contextToken || !isStringLiteralLike(contextToken)
|
||||
? undefined
|
||||
: convertStringLiteralCompletions(getStringLiteralCompletionEntries(sourceFile, contextToken, position, typeChecker, compilerOptions, host), sourceFile, typeChecker, log, preferences);
|
||||
const stringCompletions = StringCompletions.getStringLiteralCompletions(sourceFile, position, contextToken, typeChecker, compilerOptions, host, log, preferences);
|
||||
if (stringCompletions) {
|
||||
return stringCompletions;
|
||||
}
|
||||
|
||||
if (contextToken && isBreakOrContinueStatement(contextToken.parent)
|
||||
@@ -77,34 +72,6 @@ namespace ts.Completions {
|
||||
}
|
||||
}
|
||||
|
||||
function convertStringLiteralCompletions(completion: StringLiteralCompletion | undefined, sourceFile: SourceFile, checker: TypeChecker, log: Log, preferences: UserPreferences): CompletionInfo | undefined {
|
||||
if (completion === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
switch (completion.kind) {
|
||||
case StringLiteralCompletionKind.Paths:
|
||||
return convertPathCompletions(completion.paths);
|
||||
case StringLiteralCompletionKind.Properties: {
|
||||
const entries: CompletionEntry[] = [];
|
||||
getCompletionEntriesFromSymbols(completion.symbols, entries, sourceFile, sourceFile, checker, ScriptTarget.ESNext, log, CompletionKind.String, preferences); // Target will not be used, so arbitrary
|
||||
return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: completion.hasIndexSignature, entries };
|
||||
}
|
||||
case StringLiteralCompletionKind.Types: {
|
||||
const entries = completion.types.map(type => ({ name: type.value, kindModifiers: ScriptElementKindModifier.none, kind: ScriptElementKind.string, sortText: "0" }));
|
||||
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: completion.isNewIdentifier, entries };
|
||||
}
|
||||
default:
|
||||
return Debug.assertNever(completion);
|
||||
}
|
||||
}
|
||||
|
||||
function convertPathCompletions(pathCompletions: ReadonlyArray<PathCompletions.PathCompletion>): CompletionInfo {
|
||||
const isGlobalCompletion = false; // We don't want the editor to offer any other completions, such as snippets, inside a comment.
|
||||
const isNewIdentifierLocation = true; // The user may type in a path that doesn't yet exist, creating a "new identifier" with respect to the collection of identifiers the server is aware of.
|
||||
const entries = pathCompletions.map(({ name, kind, span }) => ({ name, kind, kindModifiers: ScriptElementKindModifier.none, sortText: "0", replacementSpan: span }));
|
||||
return { isGlobalCompletion, isMemberCompletion: false, isNewIdentifierLocation, entries };
|
||||
}
|
||||
|
||||
function jsdocCompletionInfo(entries: CompletionEntry[]): CompletionInfo {
|
||||
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries };
|
||||
}
|
||||
@@ -198,8 +165,9 @@ namespace ts.Completions {
|
||||
});
|
||||
}
|
||||
|
||||
const completionNameForLiteral = JSON.stringify;
|
||||
function createCompletionEntryForLiteral(literal: string | number): CompletionEntry {
|
||||
const completionNameForLiteral = (literal: string | number | PseudoBigInt) =>
|
||||
typeof literal === "object" ? pseudoBigIntToString(literal) + "n" : JSON.stringify(literal);
|
||||
function createCompletionEntryForLiteral(literal: string | number | PseudoBigInt): CompletionEntry {
|
||||
return { name: completionNameForLiteral(literal), kind: ScriptElementKind.string, kindModifiers: ScriptElementKindModifier.none, sortText: "0" };
|
||||
}
|
||||
|
||||
@@ -270,22 +238,6 @@ namespace ts.Completions {
|
||||
};
|
||||
}
|
||||
|
||||
function quote(text: string, preferences: UserPreferences): string {
|
||||
if (/^\d+$/.test(text)) {
|
||||
return text;
|
||||
}
|
||||
const quoted = JSON.stringify(text);
|
||||
switch (preferences.quotePreference) {
|
||||
case undefined:
|
||||
case "double":
|
||||
return quoted;
|
||||
case "single":
|
||||
return `'${stripQuotes(quoted).replace("'", "\\'").replace('\\"', '"')}'`;
|
||||
default:
|
||||
return Debug.assertNever(preferences.quotePreference);
|
||||
}
|
||||
}
|
||||
|
||||
function isRecommendedCompletionMatch(localSymbol: Symbol, recommendedCompletion: Symbol | undefined, checker: TypeChecker): boolean {
|
||||
return localSymbol === recommendedCompletion ||
|
||||
!!(localSymbol.flags & SymbolFlags.ExportValue) && checker.getExportSymbolOfSymbol(localSymbol) === recommendedCompletion;
|
||||
@@ -299,7 +251,7 @@ namespace ts.Completions {
|
||||
return origin && originIsExport(origin) ? stripQuotes(origin.moduleSymbol.name) : undefined;
|
||||
}
|
||||
|
||||
function getCompletionEntriesFromSymbols(
|
||||
export function getCompletionEntriesFromSymbols(
|
||||
symbols: ReadonlyArray<Symbol>,
|
||||
entries: Push<CompletionEntry>,
|
||||
location: Node | undefined,
|
||||
@@ -377,145 +329,6 @@ namespace ts.Completions {
|
||||
return entries;
|
||||
}
|
||||
|
||||
const enum StringLiteralCompletionKind { Paths, Properties, Types }
|
||||
interface StringLiteralCompletionsFromProperties {
|
||||
readonly kind: StringLiteralCompletionKind.Properties;
|
||||
readonly symbols: ReadonlyArray<Symbol>;
|
||||
readonly hasIndexSignature: boolean;
|
||||
}
|
||||
interface StringLiteralCompletionsFromTypes {
|
||||
readonly kind: StringLiteralCompletionKind.Types;
|
||||
readonly types: ReadonlyArray<StringLiteralType>;
|
||||
readonly isNewIdentifier: boolean;
|
||||
}
|
||||
type StringLiteralCompletion = { readonly kind: StringLiteralCompletionKind.Paths, readonly paths: ReadonlyArray<PathCompletions.PathCompletion> } | StringLiteralCompletionsFromProperties | StringLiteralCompletionsFromTypes;
|
||||
function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringLiteralLike, position: number, typeChecker: TypeChecker, compilerOptions: CompilerOptions, host: LanguageServiceHost): StringLiteralCompletion | undefined {
|
||||
const { parent } = node;
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.LiteralType:
|
||||
switch (parent.parent.kind) {
|
||||
case SyntaxKind.TypeReference:
|
||||
return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(parent as LiteralTypeNode)), isNewIdentifier: false };
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
// Get all apparent property names
|
||||
// i.e. interface Foo {
|
||||
// foo: string;
|
||||
// bar: string;
|
||||
// }
|
||||
// let x: Foo["/*completion position*/"]
|
||||
return stringLiteralCompletionsFromProperties(typeChecker.getTypeFromTypeNode((parent.parent as IndexedAccessTypeNode).objectType));
|
||||
case SyntaxKind.ImportType:
|
||||
return { kind: StringLiteralCompletionKind.Paths, paths: PathCompletions.getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker) };
|
||||
case SyntaxKind.UnionType: {
|
||||
if (!isTypeReferenceNode(parent.parent.parent)) return undefined;
|
||||
const alreadyUsedTypes = getAlreadyUsedTypesInStringLiteralUnion(parent.parent as UnionTypeNode, parent as LiteralTypeNode);
|
||||
const types = getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(parent.parent as UnionTypeNode)).filter(t => !contains(alreadyUsedTypes, t.value));
|
||||
return { kind: StringLiteralCompletionKind.Types, types, isNewIdentifier: false };
|
||||
}
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
if (isObjectLiteralExpression(parent.parent) && (<PropertyAssignment>parent).name === node) {
|
||||
// Get quoted name of properties of the object literal expression
|
||||
// i.e. interface ConfigFiles {
|
||||
// 'jspm:dev': string
|
||||
// }
|
||||
// let files: ConfigFiles = {
|
||||
// '/*completion position*/'
|
||||
// }
|
||||
//
|
||||
// function foo(c: ConfigFiles) {}
|
||||
// foo({
|
||||
// '/*completion position*/'
|
||||
// });
|
||||
return stringLiteralCompletionsFromProperties(typeChecker.getContextualType(parent.parent));
|
||||
}
|
||||
return fromContextualType();
|
||||
|
||||
case SyntaxKind.ElementAccessExpression: {
|
||||
const { expression, argumentExpression } = parent as ElementAccessExpression;
|
||||
if (node === argumentExpression) {
|
||||
// Get all names of properties on the expression
|
||||
// i.e. interface A {
|
||||
// 'prop1': string
|
||||
// }
|
||||
// let a: A;
|
||||
// a['/*completion position*/']
|
||||
return stringLiteralCompletionsFromProperties(typeChecker.getTypeAtLocation(expression));
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
if (!isRequireCall(parent, /*checkArgumentIsStringLiteralLike*/ false) && !isImportCall(parent)) {
|
||||
const argumentInfo = SignatureHelp.getArgumentInfoForCompletions(node, position, sourceFile);
|
||||
// Get string literal completions from specialized signatures of the target
|
||||
// i.e. declare function f(a: 'A');
|
||||
// f("/*completion position*/")
|
||||
return argumentInfo ? getStringLiteralCompletionsFromSignature(argumentInfo, typeChecker) : fromContextualType();
|
||||
}
|
||||
// falls through (is `require("")` or `import("")`)
|
||||
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
case SyntaxKind.ExternalModuleReference:
|
||||
// Get all known external module names or complete a path to a module
|
||||
// i.e. import * as ns from "/*completion position*/";
|
||||
// var y = import("/*completion position*/");
|
||||
// import x = require("/*completion position*/");
|
||||
// var y = require("/*completion position*/");
|
||||
// export * from "/*completion position*/";
|
||||
return { kind: StringLiteralCompletionKind.Paths, paths: PathCompletions.getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker) };
|
||||
|
||||
default:
|
||||
return fromContextualType();
|
||||
}
|
||||
|
||||
function fromContextualType(): StringLiteralCompletion {
|
||||
// Get completion for string literal from string literal type
|
||||
// i.e. var x: "hi" | "hello" = "/*completion position*/"
|
||||
return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(getContextualTypeFromParent(node, typeChecker)), isNewIdentifier: false };
|
||||
}
|
||||
}
|
||||
|
||||
function getAlreadyUsedTypesInStringLiteralUnion(union: UnionTypeNode, current: LiteralTypeNode): ReadonlyArray<string> {
|
||||
return mapDefined(union.types, type =>
|
||||
type !== current && isLiteralTypeNode(type) && isStringLiteral(type.literal) ? type.literal.text : undefined);
|
||||
}
|
||||
|
||||
function getStringLiteralCompletionsFromSignature(argumentInfo: SignatureHelp.ArgumentInfoForCompletions, checker: TypeChecker): StringLiteralCompletionsFromTypes {
|
||||
let isNewIdentifier = false;
|
||||
|
||||
const uniques = createMap<true>();
|
||||
const candidates: Signature[] = [];
|
||||
checker.getResolvedSignature(argumentInfo.invocation, candidates, argumentInfo.argumentCount);
|
||||
const types = flatMap(candidates, candidate => {
|
||||
if (!candidate.hasRestParameter && argumentInfo.argumentCount > candidate.parameters.length) return;
|
||||
const type = checker.getParameterType(candidate, argumentInfo.argumentIndex);
|
||||
isNewIdentifier = isNewIdentifier || !!(type.flags & TypeFlags.String);
|
||||
return getStringLiteralTypes(type, uniques);
|
||||
});
|
||||
|
||||
return { kind: StringLiteralCompletionKind.Types, types, isNewIdentifier };
|
||||
}
|
||||
|
||||
function stringLiteralCompletionsFromProperties(type: Type | undefined): StringLiteralCompletionsFromProperties | undefined {
|
||||
return type && { kind: StringLiteralCompletionKind.Properties, symbols: type.getApparentProperties(), hasIndexSignature: hasIndexSignature(type) };
|
||||
}
|
||||
|
||||
function getStringLiteralTypes(type: Type | undefined, uniques = createMap<true>()): ReadonlyArray<StringLiteralType> {
|
||||
if (!type) return emptyArray;
|
||||
type = skipConstraint(type);
|
||||
return type.isUnion()
|
||||
? flatMap(type.types, t => getStringLiteralTypes(t, uniques))
|
||||
: type.isStringLiteral() && !(type.flags & TypeFlags.EnumLiteral) && addToSeen(uniques, type.value)
|
||||
? [type]
|
||||
: emptyArray;
|
||||
}
|
||||
|
||||
interface SymbolCompletion {
|
||||
type: "symbol";
|
||||
symbol: Symbol;
|
||||
@@ -525,7 +338,7 @@ namespace ts.Completions {
|
||||
readonly isJsxInitializer: IsJsxInitializer;
|
||||
}
|
||||
function getSymbolCompletionFromEntryId(program: Program, log: Log, sourceFile: SourceFile, position: number, entryId: CompletionEntryIdentifier,
|
||||
): SymbolCompletion | { type: "request", request: Request } | { type: "literal", literal: string | number } | { type: "none" } {
|
||||
): SymbolCompletion | { type: "request", request: Request } | { type: "literal", literal: string | number | PseudoBigInt } | { type: "none" } {
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
const completionData = getCompletionData(program, log, sourceFile, isUncheckedFile(sourceFile, compilerOptions), position, { includeCompletionsForModuleExports: true, includeCompletionsWithInsertText: true }, entryId);
|
||||
if (!completionData) {
|
||||
@@ -583,10 +396,7 @@ namespace ts.Completions {
|
||||
|
||||
const contextToken = findPrecedingToken(position, sourceFile);
|
||||
if (isInString(sourceFile, position, contextToken)) {
|
||||
const stringLiteralCompletions = !contextToken || !isStringLiteralLike(contextToken)
|
||||
? undefined
|
||||
: getStringLiteralCompletionEntries(sourceFile, contextToken, position, typeChecker, compilerOptions, host);
|
||||
return stringLiteralCompletions && stringLiteralCompletionDetails(name, contextToken!, stringLiteralCompletions, sourceFile, typeChecker, cancellationToken); // TODO: GH#18217
|
||||
return StringCompletions.getStringLiteralCompletionDetails(name, sourceFile, position, contextToken, typeChecker, compilerOptions, host, cancellationToken);
|
||||
}
|
||||
|
||||
// Compute all the completion symbols again.
|
||||
@@ -626,7 +436,7 @@ namespace ts.Completions {
|
||||
return createCompletionDetails(name, ScriptElementKindModifier.none, kind, [displayPart(name, kind2)]);
|
||||
}
|
||||
|
||||
function createCompletionDetailsForSymbol(symbol: Symbol, checker: TypeChecker, sourceFile: SourceFile, location: Node, cancellationToken: CancellationToken, codeActions?: CodeAction[], sourceDisplay?: SymbolDisplayPart[]): CompletionEntryDetails {
|
||||
export function createCompletionDetailsForSymbol(symbol: Symbol, checker: TypeChecker, sourceFile: SourceFile, location: Node, cancellationToken: CancellationToken, codeActions?: CodeAction[], sourceDisplay?: SymbolDisplayPart[]): CompletionEntryDetails {
|
||||
const { displayParts, documentation, symbolKind, tags } =
|
||||
checker.runWithCancellationToken(cancellationToken, checker =>
|
||||
SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(checker, symbol, sourceFile, location, location, SemanticMeaning.All)
|
||||
@@ -634,24 +444,7 @@ namespace ts.Completions {
|
||||
return createCompletionDetails(symbol.name, SymbolDisplay.getSymbolModifiers(symbol), symbolKind, displayParts, documentation, tags, codeActions, sourceDisplay);
|
||||
}
|
||||
|
||||
function stringLiteralCompletionDetails(name: string, location: Node, completion: StringLiteralCompletion, sourceFile: SourceFile, checker: TypeChecker, cancellationToken: CancellationToken): CompletionEntryDetails | undefined {
|
||||
switch (completion.kind) {
|
||||
case StringLiteralCompletionKind.Paths: {
|
||||
const match = find(completion.paths, p => p.name === name);
|
||||
return match && createCompletionDetails(name, ScriptElementKindModifier.none, match.kind, [textPart(name)]);
|
||||
}
|
||||
case StringLiteralCompletionKind.Properties: {
|
||||
const match = find(completion.symbols, s => s.name === name);
|
||||
return match && createCompletionDetailsForSymbol(match, checker, sourceFile, location, cancellationToken);
|
||||
}
|
||||
case StringLiteralCompletionKind.Types:
|
||||
return find(completion.types, t => t.value === name) ? createCompletionDetails(name, ScriptElementKindModifier.none, ScriptElementKind.typeElement, [textPart(name)]) : undefined;
|
||||
default:
|
||||
return Debug.assertNever(completion);
|
||||
}
|
||||
}
|
||||
|
||||
function createCompletionDetails(name: string, kindModifiers: string, kind: ScriptElementKind, displayParts: SymbolDisplayPart[], documentation?: SymbolDisplayPart[], tags?: JSDocTagInfo[], codeActions?: CodeAction[], source?: SymbolDisplayPart[]): CompletionEntryDetails {
|
||||
export function createCompletionDetails(name: string, kindModifiers: string, kind: ScriptElementKind, displayParts: SymbolDisplayPart[], documentation?: SymbolDisplayPart[], tags?: JSDocTagInfo[], codeActions?: CodeAction[], source?: SymbolDisplayPart[]): CompletionEntryDetails {
|
||||
return { name, kindModifiers, kind, displayParts, documentation, tags, codeActions, source };
|
||||
}
|
||||
|
||||
@@ -710,7 +503,7 @@ namespace ts.Completions {
|
||||
readonly isNewIdentifierLocation: boolean;
|
||||
readonly location: Node | undefined;
|
||||
readonly keywordFilters: KeywordCompletionFilters;
|
||||
readonly literals: ReadonlyArray<string | number>;
|
||||
readonly literals: ReadonlyArray<string | number | PseudoBigInt>;
|
||||
readonly symbolToOriginInfoMap: SymbolOriginInfoMap;
|
||||
readonly recommendedCompletion: Symbol | undefined;
|
||||
readonly previousToken: Node | undefined;
|
||||
@@ -718,7 +511,7 @@ namespace ts.Completions {
|
||||
}
|
||||
type Request = { readonly kind: CompletionDataKind.JsDocTagName | CompletionDataKind.JsDocTag } | { readonly kind: CompletionDataKind.JsDocParameterName, tag: JSDocParameterTag };
|
||||
|
||||
const enum CompletionKind {
|
||||
export const enum CompletionKind {
|
||||
ObjectPropertyDeclaration,
|
||||
Global,
|
||||
PropertyAccess,
|
||||
@@ -772,28 +565,6 @@ namespace ts.Completions {
|
||||
}
|
||||
}
|
||||
|
||||
function getContextualTypeFromParent(node: Expression, checker: TypeChecker): Type | undefined {
|
||||
const { parent } = node;
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.NewExpression:
|
||||
return checker.getContextualType(parent as NewExpression);
|
||||
case SyntaxKind.BinaryExpression: {
|
||||
const { left, operatorToken, right } = parent as BinaryExpression;
|
||||
return isEqualityOperatorKind(operatorToken.kind)
|
||||
? checker.getTypeAtLocation(node === right ? left : right)
|
||||
: checker.getContextualType(node);
|
||||
}
|
||||
case SyntaxKind.CaseClause:
|
||||
return (parent as CaseClause).expression === node ? getSwitchedType(parent as CaseClause, checker) : undefined;
|
||||
default:
|
||||
return checker.getContextualType(node);
|
||||
}
|
||||
}
|
||||
|
||||
function getSwitchedType(caseClause: CaseClause, checker: TypeChecker): Type | undefined {
|
||||
return checker.getTypeAtLocation(caseClause.parent.parent.expression);
|
||||
}
|
||||
|
||||
function getFirstSymbolInChain(symbol: Symbol, enclosingDeclaration: Node, checker: TypeChecker): Symbol | undefined {
|
||||
const chain = checker.getAccessibleSymbolChain(symbol, enclosingDeclaration, /*meaning*/ SymbolFlags.All, /*useOnlyExternalAliasing*/ false);
|
||||
if (chain) return first(chain);
|
||||
@@ -1358,23 +1129,13 @@ namespace ts.Completions {
|
||||
return false;
|
||||
}
|
||||
|
||||
function symbolCanBeReferencedAtTypeLocation(symbol: Symbol): boolean {
|
||||
symbol = symbol.exportSymbol || symbol;
|
||||
|
||||
// This is an alias, follow what it aliases
|
||||
symbol = skipAlias(symbol, typeChecker);
|
||||
|
||||
if (symbol.flags & SymbolFlags.Type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (symbol.flags & SymbolFlags.Module) {
|
||||
const exportedSymbols = typeChecker.getExportsOfModule(symbol);
|
||||
// If the exported symbols contains type,
|
||||
// symbol can be referenced at locations where type is allowed
|
||||
return exportedSymbols.some(symbolCanBeReferencedAtTypeLocation);
|
||||
}
|
||||
return false;
|
||||
/** True if symbol is a type or a module containing at least one type. */
|
||||
function symbolCanBeReferencedAtTypeLocation(symbol: Symbol, seenModules = createMap<true>()): boolean {
|
||||
const sym = skipAlias(symbol.exportSymbol || symbol, typeChecker);
|
||||
return !!(sym.flags & SymbolFlags.Type) ||
|
||||
!!(sym.flags & SymbolFlags.Module) &&
|
||||
addToSeen(seenModules, getSymbolId(sym)) &&
|
||||
typeChecker.getExportsOfModule(sym).some(e => symbolCanBeReferencedAtTypeLocation(e, seenModules));
|
||||
}
|
||||
|
||||
function getSymbolsFromOtherSourceFileExports(symbols: Symbol[], tokenText: string, target: ScriptTarget): void {
|
||||
@@ -1407,14 +1168,16 @@ namespace ts.Completions {
|
||||
// The actual import fix might end up coming from a re-export -- we don't compute that until getting completion details.
|
||||
// This is just to avoid adding duplicate completion entries.
|
||||
//
|
||||
// If `symbol.parent !== ...`, this comes from an `export * from "foo"` re-export. Those don't create new symbols.
|
||||
// If `some(...)`, this comes from an `export { foo } from "foo"` re-export, which creates a new symbol (thus isn't caught by the first check).
|
||||
// If `symbol.parent !== ...`, this is an `export * from "foo"` re-export. Those don't create new symbols.
|
||||
if (typeChecker.getMergedSymbol(symbol.parent!) !== resolvedModuleSymbol
|
||||
|| some(symbol.declarations, d => isExportSpecifier(d) && !d.propertyName && !!d.parent.parent.moduleSpecifier)) {
|
||||
|| some(symbol.declarations, d =>
|
||||
// If `!!d.name.originalKeywordKind`, this is `export { _break as break };` -- skip this and prefer the keyword completion.
|
||||
// If `!!d.parent.parent.moduleSpecifier`, this is `export { foo } from "foo"` re-export, which creates a new symbol (thus isn't caught by the first check).
|
||||
isExportSpecifier(d) && (d.propertyName ? isIdentifierANonContextualKeyword(d.name) : !!d.parent.parent.moduleSpecifier))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const isDefaultExport = symbol.name === InternalSymbolName.Default;
|
||||
const isDefaultExport = symbol.escapedName === InternalSymbolName.Default;
|
||||
if (isDefaultExport) {
|
||||
symbol = getLocalSymbolForExportDefault(symbol) || symbol;
|
||||
}
|
||||
@@ -2193,18 +1956,6 @@ namespace ts.Completions {
|
||||
return isIdentifier(node) ? node.originalKeywordKind || SyntaxKind.Unknown : node.kind;
|
||||
}
|
||||
|
||||
function isEqualityOperatorKind(kind: SyntaxKind): kind is EqualityOperator {
|
||||
switch (kind) {
|
||||
case SyntaxKind.EqualsEqualsEqualsToken:
|
||||
case SyntaxKind.EqualsEqualsToken:
|
||||
case SyntaxKind.ExclamationEqualsEqualsToken:
|
||||
case SyntaxKind.ExclamationEqualsToken:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the corresponding JSDocTag node if the position is in a jsDoc comment */
|
||||
function getJsDocTagAtPosition(node: Node, position: number): JSDocTag | undefined {
|
||||
const jsdoc = findAncestor(node, isJSDoc);
|
||||
@@ -2272,10 +2023,6 @@ namespace ts.Completions {
|
||||
return node.parent && isClassOrTypeElement(node.parent) && isObjectTypeDeclaration(node.parent.parent);
|
||||
}
|
||||
|
||||
function hasIndexSignature(type: Type): boolean {
|
||||
return !!type.getStringIndexType() || !!type.getNumberIndexType();
|
||||
}
|
||||
|
||||
function isValidTrigger(sourceFile: SourceFile, triggerCharacter: CompletionsTriggerCharacter, contextToken: Node | undefined, position: number): boolean {
|
||||
switch (triggerCharacter) {
|
||||
case ".":
|
||||
@@ -2301,16 +2048,4 @@ namespace ts.Completions {
|
||||
function binaryExpressionMayBeOpenTag({ left }: BinaryExpression): boolean {
|
||||
return nodeIsMissing(left);
|
||||
}
|
||||
|
||||
function isStringLiteralOrTemplate(node: Node): node is StringLiteralLike | TemplateExpression | TaggedTemplateExpression {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.TemplateExpression:
|
||||
case SyntaxKind.TaggedTemplateExpression:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* @internal */
|
||||
namespace ts.FindAllReferences {
|
||||
export interface SymbolAndEntries {
|
||||
definition: Definition | undefined;
|
||||
references: Entry[];
|
||||
readonly definition: Definition | undefined;
|
||||
readonly references: ReadonlyArray<Entry>;
|
||||
}
|
||||
|
||||
export const enum DefinitionKind { Symbol, Label, Keyword, This, String }
|
||||
@@ -60,7 +60,7 @@ namespace ts.FindAllReferences {
|
||||
return map(referenceEntries, entry => toImplementationLocation(entry, checker));
|
||||
}
|
||||
|
||||
function getImplementationReferenceEntries(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, node: Node, position: number): Entry[] | undefined {
|
||||
function getImplementationReferenceEntries(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, node: Node, position: number): ReadonlyArray<Entry> | undefined {
|
||||
if (node.kind === SyntaxKind.SourceFile) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -94,11 +94,19 @@ namespace ts.FindAllReferences {
|
||||
|
||||
export type ToReferenceOrRenameEntry<T> = (entry: Entry, originalNode: Node) => T;
|
||||
|
||||
export function getReferenceEntriesForNode(position: number, node: Node, program: Program, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken, options: Options = {}, sourceFilesSet: ReadonlyMap<true> = arrayToSet(sourceFiles, f => f.fileName)): Entry[] | undefined {
|
||||
export function getReferenceEntriesForNode(
|
||||
position: number,
|
||||
node: Node,
|
||||
program: Program,
|
||||
sourceFiles: ReadonlyArray<SourceFile>,
|
||||
cancellationToken: CancellationToken,
|
||||
options: Options = {},
|
||||
sourceFilesSet: ReadonlyMap<true> = arrayToSet(sourceFiles, f => f.fileName),
|
||||
): ReadonlyArray<Entry> | undefined {
|
||||
return flattenEntries(Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options, sourceFilesSet));
|
||||
}
|
||||
|
||||
function flattenEntries(referenceSymbols: SymbolAndEntries[] | undefined): Entry[] | undefined {
|
||||
function flattenEntries(referenceSymbols: SymbolAndEntries[] | undefined): ReadonlyArray<Entry> | undefined {
|
||||
return referenceSymbols && flatMap(referenceSymbols, r => r.references);
|
||||
}
|
||||
|
||||
@@ -360,6 +368,10 @@ namespace ts.FindAllReferences.Core {
|
||||
return !options.implementations && isStringLiteral(node) ? getReferencesForStringLiteral(node, sourceFiles, cancellationToken) : undefined;
|
||||
}
|
||||
|
||||
if (symbol.escapedName === InternalSymbolName.ExportEquals) {
|
||||
return getReferencedSymbolsForModule(program, symbol.parent!, /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet);
|
||||
}
|
||||
|
||||
let moduleReferences: SymbolAndEntries[] = emptyArray;
|
||||
const moduleSourceFile = isModuleSymbol(symbol);
|
||||
let referencedNode: Node | undefined = node;
|
||||
@@ -419,6 +431,22 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
}
|
||||
|
||||
const exported = symbol.exports!.get(InternalSymbolName.ExportEquals);
|
||||
if (exported) {
|
||||
for (const decl of exported.declarations) {
|
||||
const sourceFile = decl.getSourceFile();
|
||||
if (sourceFilesSet.has(sourceFile.fileName)) {
|
||||
// At `module.exports = ...`, reference node is `module`
|
||||
const node = isBinaryExpression(decl) && isPropertyAccessExpression(decl.left)
|
||||
? decl.left.expression
|
||||
: isExportAssignment(decl)
|
||||
? Debug.assertDefined(findChildOfKind(decl, SyntaxKind.ExportKeyword, sourceFile))
|
||||
: getNameOfDeclaration(decl) || decl;
|
||||
references.push(nodeEntry(node));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return references.length ? [{ definition: { type: DefinitionKind.Symbol, symbol }, references }] : emptyArray;
|
||||
}
|
||||
|
||||
@@ -831,7 +859,9 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
export function eachSymbolReferenceInFile<T>(definition: Identifier, checker: TypeChecker, sourceFile: SourceFile, cb: (token: Identifier) => T): T | undefined {
|
||||
const symbol = checker.getSymbolAtLocation(definition);
|
||||
const symbol = isParameterPropertyDeclaration(definition.parent)
|
||||
? first(checker.getSymbolsOfParameterPropertyDeclaration(definition.parent, definition.text))
|
||||
: checker.getSymbolAtLocation(definition);
|
||||
if (!symbol) return undefined;
|
||||
for (const token of getPossibleSymbolReferenceNodes(sourceFile, symbol.name)) {
|
||||
if (!isIdentifier(token) || token === definition || token.escapedText !== definition.escapedText) continue;
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace ts.formatting {
|
||||
* the first token in line so it should be indented
|
||||
*/
|
||||
interface DynamicIndentation {
|
||||
getIndentationForToken(tokenLine: number, tokenKind: SyntaxKind, container: Node): number;
|
||||
getIndentationForToken(tokenLine: number, tokenKind: SyntaxKind, container: Node, suppressDelta: boolean): number;
|
||||
getIndentationForComment(owningToken: SyntaxKind, tokenIndentation: number, container: Node): number;
|
||||
/**
|
||||
* Indentation for open and close tokens of the node if it is block or another node that needs special indentation
|
||||
@@ -334,7 +334,6 @@ namespace ts.formatting {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function formatNodeGivenIndentation(node: Node, sourceFileLike: SourceFileLike, languageVariant: LanguageVariant, initialIndentation: number, delta: number, formatContext: FormatContext): TextChange[] {
|
||||
const range = { pos: 0, end: sourceFileLike.text.length };
|
||||
return getFormattingScanner(sourceFileLike.text, languageVariant, range.pos, range.end, scanner => formatSpanWorker(
|
||||
@@ -399,7 +398,7 @@ namespace ts.formatting {
|
||||
let previousRangeStartLine: number;
|
||||
|
||||
let lastIndentedLine: number;
|
||||
let indentationOnLastIndentedLine: number;
|
||||
let indentationOnLastIndentedLine = Constants.Unknown;
|
||||
|
||||
const edits: TextChange[] = [];
|
||||
|
||||
@@ -540,8 +539,18 @@ namespace ts.formatting {
|
||||
}
|
||||
return tokenIndentation !== Constants.Unknown ? tokenIndentation : indentation;
|
||||
},
|
||||
getIndentationForToken: (line, kind, container) =>
|
||||
shouldAddDelta(line, kind, container) ? indentation + getDelta(container) : indentation,
|
||||
// if list end token is LessThanToken '>' then its delta should be explicitly suppressed
|
||||
// so that LessThanToken as a binary operator can still be indented.
|
||||
// foo.then
|
||||
// <
|
||||
// number,
|
||||
// string,
|
||||
// >();
|
||||
// vs
|
||||
// var a = xValue
|
||||
// > yValue;
|
||||
getIndentationForToken: (line, kind, container, suppressDelta) =>
|
||||
!suppressDelta && shouldAddDelta(line, kind, container) ? indentation + getDelta(container) : indentation,
|
||||
getIndentation: () => indentation,
|
||||
getDelta,
|
||||
recomputeIndentation: lineAdded => {
|
||||
@@ -557,7 +566,6 @@ namespace ts.formatting {
|
||||
// open and close brace, 'else' and 'while' (in do statement) tokens has indentation of the parent
|
||||
case SyntaxKind.OpenBraceToken:
|
||||
case SyntaxKind.CloseBraceToken:
|
||||
case SyntaxKind.OpenParenToken:
|
||||
case SyntaxKind.CloseParenToken:
|
||||
case SyntaxKind.ElseKeyword:
|
||||
case SyntaxKind.WhileKeyword:
|
||||
@@ -738,11 +746,23 @@ namespace ts.formatting {
|
||||
else if (tokenInfo.token.kind === listStartToken) {
|
||||
// consume list start token
|
||||
startLine = sourceFile.getLineAndCharacterOfPosition(tokenInfo.token.pos).line;
|
||||
const indentation =
|
||||
computeIndentation(tokenInfo.token, startLine, Constants.Unknown, parent, parentDynamicIndentation, parentStartLine);
|
||||
|
||||
listDynamicIndentation = getDynamicIndentation(parent, parentStartLine, indentation.indentation, indentation.delta);
|
||||
consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation, parent);
|
||||
consumeTokenAndAdvanceScanner(tokenInfo, parent, parentDynamicIndentation, parent);
|
||||
|
||||
let indentationOnListStartToken: number;
|
||||
if (indentationOnLastIndentedLine !== Constants.Unknown) {
|
||||
// scanner just processed list start token so consider last indentation as list indentation
|
||||
// function foo(): { // last indentation was 0, list item will be indented based on this value
|
||||
// foo: number;
|
||||
// }: {};
|
||||
indentationOnListStartToken = indentationOnLastIndentedLine;
|
||||
}
|
||||
else {
|
||||
const startLinePosition = getLineStartPositionForPosition(tokenInfo.token.pos, sourceFile);
|
||||
indentationOnListStartToken = SmartIndenter.findFirstNonWhitespaceColumn(startLinePosition, tokenInfo.token.pos, sourceFile, options);
|
||||
}
|
||||
|
||||
listDynamicIndentation = getDynamicIndentation(parent, parentStartLine, indentationOnListStartToken, options.indentSize!); // TODO: GH#18217
|
||||
}
|
||||
else {
|
||||
// consume any tokens that precede the list as child elements of 'node' using its indentation scope
|
||||
@@ -771,12 +791,12 @@ namespace ts.formatting {
|
||||
// without this check close paren will be interpreted as list end token for function expression which is wrong
|
||||
if (tokenInfo && tokenInfo.token.kind === listEndToken && rangeContainsRange(parent, tokenInfo.token)) {
|
||||
// consume list end token
|
||||
consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation, parent);
|
||||
consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation, parent, /*isListEndToken*/ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation, container: Node): void {
|
||||
function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation, container: Node, isListEndToken?: boolean): void {
|
||||
Debug.assert(rangeContainsRange(parent, currentTokenInfo.token));
|
||||
|
||||
const lastTriviaWasNewLine = formattingScanner.lastTrailingTriviaWasNewLine();
|
||||
@@ -814,7 +834,7 @@ namespace ts.formatting {
|
||||
|
||||
if (indentToken) {
|
||||
const tokenIndentation = (isTokenInRange && !rangeContainsError(currentTokenInfo.token)) ?
|
||||
dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind, container) :
|
||||
dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind, container, !!isListEndToken) :
|
||||
Constants.Unknown;
|
||||
|
||||
let indentNextTokenOrTrivia = true;
|
||||
@@ -1228,6 +1248,9 @@ namespace ts.formatting {
|
||||
if ((<TypeReferenceNode>node).typeArguments === list) {
|
||||
return SyntaxKind.LessThanToken;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.TypeLiteral:
|
||||
return SyntaxKind.OpenBraceToken;
|
||||
}
|
||||
|
||||
return SyntaxKind.Unknown;
|
||||
@@ -1239,6 +1262,8 @@ namespace ts.formatting {
|
||||
return SyntaxKind.CloseParenToken;
|
||||
case SyntaxKind.LessThanToken:
|
||||
return SyntaxKind.GreaterThanToken;
|
||||
case SyntaxKind.OpenBraceToken:
|
||||
return SyntaxKind.CloseBraceToken;
|
||||
}
|
||||
|
||||
return SyntaxKind.Unknown;
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace ts.formatting {
|
||||
const binaryKeywordOperators = [SyntaxKind.InKeyword, SyntaxKind.InstanceOfKeyword, SyntaxKind.OfKeyword, SyntaxKind.AsKeyword, SyntaxKind.IsKeyword];
|
||||
const unaryPrefixOperators = [SyntaxKind.PlusPlusToken, SyntaxKind.MinusMinusToken, SyntaxKind.TildeToken, SyntaxKind.ExclamationToken];
|
||||
const unaryPrefixExpressions = [
|
||||
SyntaxKind.NumericLiteral, SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken,
|
||||
SyntaxKind.OpenBraceToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword];
|
||||
SyntaxKind.NumericLiteral, SyntaxKind.BigIntLiteral, SyntaxKind.Identifier, SyntaxKind.OpenParenToken,
|
||||
SyntaxKind.OpenBracketToken, SyntaxKind.OpenBraceToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword];
|
||||
const unaryPreincrementExpressions = [SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword];
|
||||
const unaryPostincrementExpressions = [SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword];
|
||||
const unaryPredecrementExpressions = [SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword];
|
||||
|
||||
@@ -66,6 +66,12 @@ namespace ts.formatting {
|
||||
}
|
||||
}
|
||||
|
||||
const containerList = getListByPosition(position, precedingToken.parent, sourceFile);
|
||||
// use list position if the preceding token is before any list items
|
||||
if (containerList && !rangeContainsRange(containerList, precedingToken)) {
|
||||
return getActualIndentationForListStartLine(containerList, sourceFile, options) + options.indentSize!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
return getSmartIndent(sourceFile, position, precedingToken, lineAtPosition, assumeNewLineBeforeCloseBrace, options);
|
||||
}
|
||||
|
||||
@@ -124,14 +130,13 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
// check if current node is a list item - if yes, take indentation from it
|
||||
let actualIndentation = getActualIndentationForListItem(current, sourceFile, options);
|
||||
// do not consider parent-child line sharing yet:
|
||||
// function foo(a
|
||||
// | preceding node 'a' does share line with its parent but indentation is expected
|
||||
const actualIndentation = getActualIndentationForListItem(current, sourceFile, options, /*listIndentsChild*/ true);
|
||||
if (actualIndentation !== Value.Unknown) {
|
||||
return actualIndentation;
|
||||
}
|
||||
actualIndentation = getLineIndentationWhenExpressionIsInMultiLine(current, sourceFile, options);
|
||||
if (actualIndentation !== Value.Unknown) {
|
||||
return actualIndentation + options.indentSize!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
previous = current;
|
||||
current = current.parent;
|
||||
@@ -169,26 +174,20 @@ namespace ts.formatting {
|
||||
useActualIndentation = start < ignoreActualIndentationRange.pos || start > ignoreActualIndentationRange.end;
|
||||
}
|
||||
|
||||
if (useActualIndentation) {
|
||||
// check if current node is a list item - if yes, take indentation from it
|
||||
const actualIndentation = getActualIndentationForListItem(current, sourceFile, options);
|
||||
if (actualIndentation !== Value.Unknown) {
|
||||
return actualIndentation + indentationDelta;
|
||||
}
|
||||
}
|
||||
|
||||
const containingListOrParentStart = getContainingListOrParentStart(parent, current, sourceFile);
|
||||
const parentAndChildShareLine =
|
||||
containingListOrParentStart.line === currentStart.line ||
|
||||
childStartsOnTheSameLineWithElseInIfStatement(parent, current, currentStart.line, sourceFile);
|
||||
|
||||
if (useActualIndentation) {
|
||||
// try to fetch actual indentation for current node from source text
|
||||
let actualIndentation = getActualIndentationForNode(current, parent, currentStart, parentAndChildShareLine, sourceFile, options);
|
||||
// check if current node is a list item - if yes, take indentation from it
|
||||
let actualIndentation = getActualIndentationForListItem(current, sourceFile, options, !parentAndChildShareLine);
|
||||
if (actualIndentation !== Value.Unknown) {
|
||||
return actualIndentation + indentationDelta;
|
||||
}
|
||||
actualIndentation = getLineIndentationWhenExpressionIsInMultiLine(current, sourceFile, options);
|
||||
|
||||
// try to fetch actual indentation for current node from source text
|
||||
actualIndentation = getActualIndentationForNode(current, parent, currentStart, parentAndChildShareLine, sourceFile, options);
|
||||
if (actualIndentation !== Value.Unknown) {
|
||||
return actualIndentation + indentationDelta;
|
||||
}
|
||||
@@ -323,112 +322,109 @@ namespace ts.formatting {
|
||||
return false;
|
||||
}
|
||||
|
||||
function getListIfVisualStartEndIsInListRange(list: NodeArray<Node> | undefined, start: number, end: number, node: Node, sourceFile: SourceFile) {
|
||||
return list && rangeContainsVisualStartEnd(list) ? list : undefined;
|
||||
|
||||
// Assumes a list is wrapped by list tokens
|
||||
function rangeContainsVisualStartEnd(textRange: TextRange): boolean {
|
||||
const children = node.getChildren();
|
||||
for (let i = 1; i < children.length - 1; i++) {
|
||||
if (children[i].pos === textRange.pos && children[i].end === textRange.end) {
|
||||
return rangeContainsStartEnd({ pos: children[i - 1].end, end: children[i + 1].getStart(sourceFile) }, start, end);
|
||||
}
|
||||
}
|
||||
return rangeContainsStartEnd(textRange, start, end);
|
||||
}
|
||||
}
|
||||
|
||||
function getListIfStartEndIsInListRange(list: NodeArray<Node> | undefined, start: number, end: number) {
|
||||
return list && rangeContainsStartEnd(list, start, end) ? list : undefined;
|
||||
}
|
||||
|
||||
export function getContainingList(node: Node, sourceFile: SourceFile): NodeArray<Node> | undefined {
|
||||
if (node.parent) {
|
||||
const { end } = node;
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.TypeReference:
|
||||
return getListIfStartEndIsInListRange((<TypeReferenceNode>node.parent).typeArguments, node.getStart(sourceFile), end);
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
return (<ObjectLiteralExpression>node.parent).properties;
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
return (<ArrayLiteralExpression>node.parent).elements;
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.ConstructSignature: {
|
||||
const start = node.getStart(sourceFile);
|
||||
return getListIfStartEndIsInListRange((<SignatureDeclaration>node.parent).typeParameters, start, end) ||
|
||||
getListIfStartEndIsInListRange((<SignatureDeclaration>node.parent).parameters, start, end);
|
||||
}
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ClassExpression:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.JSDocTemplateTag: {
|
||||
const { typeParameters } = <ClassDeclaration | ClassExpression | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag>node.parent;
|
||||
return getListIfStartEndIsInListRange(typeParameters, node.getStart(sourceFile), end);
|
||||
}
|
||||
case SyntaxKind.NewExpression:
|
||||
case SyntaxKind.CallExpression: {
|
||||
const start = node.getStart(sourceFile);
|
||||
return getListIfStartEndIsInListRange((<CallExpression | NewExpression>node.parent).typeArguments, start, end) ||
|
||||
getListIfStartEndIsInListRange((<CallExpression | NewExpression>node.parent).arguments, start, end);
|
||||
}
|
||||
case SyntaxKind.VariableDeclarationList:
|
||||
return getListIfStartEndIsInListRange((<VariableDeclarationList>node.parent).declarations, node.getStart(sourceFile), end);
|
||||
case SyntaxKind.NamedImports:
|
||||
case SyntaxKind.NamedExports:
|
||||
return getListIfStartEndIsInListRange((<NamedImportsOrExports>node.parent).elements, node.getStart(sourceFile), end);
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
case SyntaxKind.ArrayBindingPattern:
|
||||
return getListIfStartEndIsInListRange((<ObjectBindingPattern | ArrayBindingPattern>node.parent).elements, node.getStart(sourceFile), end);
|
||||
}
|
||||
return getListByRange(node.getStart(sourceFile), node.getEnd(), node.parent, sourceFile);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: EditorSettings): number {
|
||||
function getListByPosition(pos: number, node: Node, sourceFile: SourceFile): NodeArray<Node> | undefined {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
return getListByRange(pos, pos, node, sourceFile);
|
||||
}
|
||||
|
||||
function getListByRange(start: number, end: number, node: Node, sourceFile: SourceFile): NodeArray<Node> | undefined {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.TypeReference:
|
||||
return getListIfVisualStartEndIsInListRange((<TypeReferenceNode>node).typeArguments, start, end, node, sourceFile);
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
return getListIfVisualStartEndIsInListRange((<ObjectLiteralExpression>node).properties, start, end, node, sourceFile);
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
return getListIfVisualStartEndIsInListRange((<ArrayLiteralExpression>node).elements, start, end, node, sourceFile);
|
||||
case SyntaxKind.TypeLiteral:
|
||||
return getListIfVisualStartEndIsInListRange((<TypeLiteralNode>node).members, start, end, node, sourceFile);
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.ConstructSignature: {
|
||||
return getListIfVisualStartEndIsInListRange((<SignatureDeclaration>node).typeParameters, start, end, node, sourceFile) ||
|
||||
getListIfVisualStartEndIsInListRange((<SignatureDeclaration>node).parameters, start, end, node, sourceFile);
|
||||
}
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ClassExpression:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.JSDocTemplateTag: {
|
||||
const { typeParameters } = <ClassDeclaration | ClassExpression | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag>node;
|
||||
return getListIfVisualStartEndIsInListRange(typeParameters, start, end, node, sourceFile);
|
||||
}
|
||||
case SyntaxKind.NewExpression:
|
||||
case SyntaxKind.CallExpression: {
|
||||
return getListIfVisualStartEndIsInListRange((<CallExpression>node).typeArguments, start, end, node, sourceFile) ||
|
||||
getListIfVisualStartEndIsInListRange((<CallExpression>node).arguments, start, end, node, sourceFile);
|
||||
}
|
||||
case SyntaxKind.VariableDeclarationList:
|
||||
return getListIfStartEndIsInListRange((<VariableDeclarationList>node).declarations, start, end);
|
||||
case SyntaxKind.NamedImports:
|
||||
case SyntaxKind.NamedExports:
|
||||
return getListIfVisualStartEndIsInListRange((<NamedImportsOrExports>node).elements, start, end, node, sourceFile);
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
case SyntaxKind.ArrayBindingPattern:
|
||||
return getListIfVisualStartEndIsInListRange((<ObjectBindingPattern | ArrayBindingPattern>node).elements, start, end, node, sourceFile);
|
||||
}
|
||||
}
|
||||
|
||||
function getActualIndentationForListStartLine(list: NodeArray<Node>, sourceFile: SourceFile, options: EditorSettings): number {
|
||||
if (!list) {
|
||||
return Value.Unknown;
|
||||
}
|
||||
return findColumnForFirstNonWhitespaceCharacterInLine(sourceFile.getLineAndCharacterOfPosition(list.pos), sourceFile, options);
|
||||
}
|
||||
|
||||
function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: EditorSettings, listIndentsChild: boolean): number {
|
||||
if (node.parent && node.parent.kind === SyntaxKind.VariableDeclarationList) {
|
||||
// VariableDeclarationList has no wrapping tokens
|
||||
return Value.Unknown;
|
||||
}
|
||||
const containingList = getContainingList(node, sourceFile);
|
||||
if (containingList) {
|
||||
const index = containingList.indexOf(node);
|
||||
if (index !== -1) {
|
||||
return deriveActualIndentationFromList(containingList, index, sourceFile, options);
|
||||
}
|
||||
}
|
||||
return Value.Unknown;
|
||||
}
|
||||
|
||||
function getLineIndentationWhenExpressionIsInMultiLine(node: Node, sourceFile: SourceFile, options: EditorSettings): number {
|
||||
// actual indentation should not be used when:
|
||||
// - node is close parenthesis - this is the end of the expression
|
||||
if (node.kind === SyntaxKind.CloseParenToken) {
|
||||
return Value.Unknown;
|
||||
}
|
||||
|
||||
if (node.parent && isCallOrNewExpression(node.parent) && node.parent.expression !== node) {
|
||||
const fullCallOrNewExpression = node.parent.expression;
|
||||
const startingExpression = getStartingExpression(fullCallOrNewExpression);
|
||||
|
||||
if (fullCallOrNewExpression === startingExpression) {
|
||||
return Value.Unknown;
|
||||
}
|
||||
|
||||
const fullCallOrNewExpressionEnd = sourceFile.getLineAndCharacterOfPosition(fullCallOrNewExpression.end);
|
||||
const startingExpressionEnd = sourceFile.getLineAndCharacterOfPosition(startingExpression.end);
|
||||
|
||||
if (fullCallOrNewExpressionEnd.line === startingExpressionEnd.line) {
|
||||
return Value.Unknown;
|
||||
}
|
||||
|
||||
return findColumnForFirstNonWhitespaceCharacterInLine(fullCallOrNewExpressionEnd, sourceFile, options);
|
||||
}
|
||||
|
||||
return Value.Unknown;
|
||||
|
||||
function getStartingExpression(node: Expression) {
|
||||
while (true) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
node = (<PropertyAccessExpression | CallExpression | NewExpression | ElementAccessExpression | PropertyAccessExpression>node).expression;
|
||||
break;
|
||||
default:
|
||||
return node;
|
||||
const result = deriveActualIndentationFromList(containingList, index, sourceFile, options);
|
||||
if (result !== Value.Unknown) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return getActualIndentationForListStartLine(containingList, sourceFile, options) + (listIndentsChild ? options.indentSize! : 0); // TODO: GH#18217
|
||||
}
|
||||
return Value.Unknown;
|
||||
}
|
||||
|
||||
function deriveActualIndentationFromList(list: ReadonlyArray<Node>, index: number, sourceFile: SourceFile, options: EditorSettings): number {
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace ts {
|
||||
const oldToNew = getPathUpdater(oldFileOrDirPath, newFileOrDirPath, getCanonicalFileName, sourceMapper);
|
||||
const newToOld = getPathUpdater(newFileOrDirPath, oldFileOrDirPath, getCanonicalFileName, sourceMapper);
|
||||
return textChanges.ChangeTracker.with({ host, formatContext }, changeTracker => {
|
||||
updateTsconfigFiles(program, changeTracker, oldToNew, newFileOrDirPath, host.getCurrentDirectory(), useCaseSensitiveFileNames);
|
||||
updateTsconfigFiles(program, changeTracker, oldToNew, oldFileOrDirPath, newFileOrDirPath, host.getCurrentDirectory(), useCaseSensitiveFileNames);
|
||||
updateImports(program, changeTracker, oldToNew, newToOld, host, getCanonicalFileName);
|
||||
});
|
||||
}
|
||||
@@ -25,7 +25,7 @@ namespace ts {
|
||||
export function getPathUpdater(oldFileOrDirPath: string, newFileOrDirPath: string, getCanonicalFileName: GetCanonicalFileName, sourceMapper: SourceMapper | undefined): PathUpdater {
|
||||
const canonicalOldPath = getCanonicalFileName(oldFileOrDirPath);
|
||||
return path => {
|
||||
const originalPath = sourceMapper && sourceMapper.tryGetOriginalLocation({ fileName: path, position: 0 });
|
||||
const originalPath = sourceMapper && sourceMapper.tryGetSourcePosition({ fileName: path, pos: 0 });
|
||||
const updatedPath = getUpdatedPath(originalPath ? originalPath.fileName : path);
|
||||
return originalPath
|
||||
? updatedPath === undefined ? undefined : makeCorrespondingRelativeChange(originalPath.fileName, updatedPath, path, getCanonicalFileName)
|
||||
@@ -45,7 +45,7 @@ namespace ts {
|
||||
return combinePathsSafe(getDirectoryPath(a1), rel);
|
||||
}
|
||||
|
||||
function updateTsconfigFiles(program: Program, changeTracker: textChanges.ChangeTracker, oldToNew: PathUpdater, newFileOrDirPath: string, currentDirectory: string, useCaseSensitiveFileNames: boolean): void {
|
||||
function updateTsconfigFiles(program: Program, changeTracker: textChanges.ChangeTracker, oldToNew: PathUpdater, oldFileOrDirPath: string, newFileOrDirPath: string, currentDirectory: string, useCaseSensitiveFileNames: boolean): void {
|
||||
const { configFile } = program.getCompilerOptions();
|
||||
if (!configFile) return;
|
||||
const configDir = getDirectoryPath(configFile.fileName);
|
||||
@@ -63,7 +63,8 @@ namespace ts {
|
||||
const includes = mapDefined(property.initializer.elements, e => isStringLiteral(e) ? e.text : undefined);
|
||||
const matchers = getFileMatcherPatterns(configDir, /*excludes*/ [], includes, useCaseSensitiveFileNames, currentDirectory);
|
||||
// If there isn't some include for this, add a new one.
|
||||
if (!getRegexFromPattern(Debug.assertDefined(matchers.includeFilePattern), useCaseSensitiveFileNames).test(newFileOrDirPath)) {
|
||||
if (getRegexFromPattern(Debug.assertDefined(matchers.includeFilePattern), useCaseSensitiveFileNames).test(oldFileOrDirPath) &&
|
||||
!getRegexFromPattern(Debug.assertDefined(matchers.includeFilePattern), useCaseSensitiveFileNames).test(newFileOrDirPath)) {
|
||||
changeTracker.insertNodeAfter(configFile, last(property.initializer.elements), createStringLiteral(relativePath(newFileOrDirPath)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* @internal */
|
||||
namespace ts.GoToDefinition {
|
||||
export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile, position: number): DefinitionInfo[] | undefined {
|
||||
export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile, position: number): ReadonlyArray<DefinitionInfo> | undefined {
|
||||
const reference = getReferenceAtPosition(sourceFile, position, program);
|
||||
if (reference) {
|
||||
return [getDefinitionInfoForFileReference(reference.fileName, reference.file.fileName)];
|
||||
@@ -129,7 +129,7 @@ namespace ts.GoToDefinition {
|
||||
}
|
||||
|
||||
/// Goto type
|
||||
export function getTypeDefinitionAtPosition(typeChecker: TypeChecker, sourceFile: SourceFile, position: number): DefinitionInfo[] | undefined {
|
||||
export function getTypeDefinitionAtPosition(typeChecker: TypeChecker, sourceFile: SourceFile, position: number): ReadonlyArray<DefinitionInfo> | undefined {
|
||||
const node = getTouchingPropertyName(sourceFile, position);
|
||||
if (node === sourceFile) {
|
||||
return undefined;
|
||||
@@ -145,7 +145,7 @@ namespace ts.GoToDefinition {
|
||||
return fromReturnType && fromReturnType.length !== 0 ? fromReturnType : definitionFromType(typeAtLocation, typeChecker, node);
|
||||
}
|
||||
|
||||
function definitionFromType(type: Type, checker: TypeChecker, node: Node): DefinitionInfo[] {
|
||||
function definitionFromType(type: Type, checker: TypeChecker, node: Node): ReadonlyArray<DefinitionInfo> {
|
||||
return flatMap(type.isUnion() && !(type.flags & TypeFlags.Enum) ? type.types : [type], t =>
|
||||
t.symbol && getDefinitionFromSymbol(checker, t.symbol, node));
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ namespace ts.OrganizeImports {
|
||||
: undefined;
|
||||
}
|
||||
|
||||
/* @internal */ // Internal for testing
|
||||
// Internal for testing
|
||||
/**
|
||||
* @param importGroup a list of ImportDeclarations, all with the same module name.
|
||||
*/
|
||||
@@ -266,7 +266,7 @@ namespace ts.OrganizeImports {
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */ // Internal for testing
|
||||
// Internal for testing
|
||||
/**
|
||||
* @param exportGroup a list of ExportDeclarations, all with the same module name.
|
||||
*/
|
||||
|
||||
@@ -461,11 +461,11 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
/* @internal */ export function breakIntoCharacterSpans(identifier: string): TextSpan[] {
|
||||
export function breakIntoCharacterSpans(identifier: string): TextSpan[] {
|
||||
return breakIntoSpans(identifier, /*word:*/ false);
|
||||
}
|
||||
|
||||
/* @internal */ export function breakIntoWordSpans(identifier: string): TextSpan[] {
|
||||
export function breakIntoWordSpans(identifier: string): TextSpan[] {
|
||||
return breakIntoSpans(identifier, /*word:*/ true);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace ts {
|
||||
getEditsForAction(context: RefactorContext, actionName: string): RefactorEditInfo | undefined;
|
||||
|
||||
/** Compute (quickly) which actions are available here */
|
||||
getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined;
|
||||
getAvailableActions(context: RefactorContext): ReadonlyArray<ApplicableRefactorInfo>;
|
||||
}
|
||||
|
||||
export interface RefactorContext extends textChanges.TextChangesContext {
|
||||
|
||||
@@ -15,10 +15,10 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction {
|
||||
addBraces: boolean;
|
||||
}
|
||||
|
||||
function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined {
|
||||
function getAvailableActions(context: RefactorContext): ReadonlyArray<ApplicableRefactorInfo> {
|
||||
const { file, startPosition } = context;
|
||||
const info = getConvertibleArrowFunctionAtPosition(file, startPosition);
|
||||
if (!info) return undefined;
|
||||
if (!info) return emptyArray;
|
||||
|
||||
return [{
|
||||
name: refactorName,
|
||||
|
||||
@@ -4,9 +4,9 @@ namespace ts.refactor {
|
||||
const actionNameDefaultToNamed = "Convert default export to named export";
|
||||
const actionNameNamedToDefault = "Convert named export to default export";
|
||||
registerRefactor(refactorName, {
|
||||
getAvailableActions(context): ApplicableRefactorInfo[] | undefined {
|
||||
getAvailableActions(context): ReadonlyArray<ApplicableRefactorInfo> {
|
||||
const info = getInfo(context);
|
||||
if (!info) return undefined;
|
||||
if (!info) return emptyArray;
|
||||
const description = info.wasDefault ? Diagnostics.Convert_default_export_to_named_export.message : Diagnostics.Convert_named_export_to_default_export.message;
|
||||
const actionName = info.wasDefault ? actionNameDefaultToNamed : actionNameNamedToDefault;
|
||||
return [{ name: refactorName, description, actions: [{ name: actionName, description }] }];
|
||||
@@ -166,38 +166,35 @@ namespace ts.refactor {
|
||||
}
|
||||
|
||||
function changeNamedToDefaultImport(importingSourceFile: SourceFile, ref: Identifier, changes: textChanges.ChangeTracker): void {
|
||||
const { parent } = ref;
|
||||
const parent = ref.parent as PropertyAccessExpression | ImportSpecifier | ExportSpecifier;
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
// `a.foo` --> `a.default`
|
||||
changes.replaceNode(importingSourceFile, ref, createIdentifier("default"));
|
||||
break;
|
||||
case SyntaxKind.ImportSpecifier:
|
||||
case SyntaxKind.ExportSpecifier: {
|
||||
const spec = parent as ImportSpecifier | ExportSpecifier;
|
||||
if (spec.kind === SyntaxKind.ImportSpecifier) {
|
||||
// `import { foo } from "./a";` --> `import foo from "./a";`
|
||||
// `import { foo as bar } from "./a";` --> `import bar from "./a";`
|
||||
const defaultImport = createIdentifier(spec.name.text);
|
||||
if (spec.parent.elements.length === 1) {
|
||||
changes.replaceNode(importingSourceFile, spec.parent, defaultImport);
|
||||
}
|
||||
else {
|
||||
changes.delete(importingSourceFile, spec);
|
||||
changes.insertNodeBefore(importingSourceFile, spec.parent, defaultImport);
|
||||
}
|
||||
case SyntaxKind.ImportSpecifier: {
|
||||
// `import { foo } from "./a";` --> `import foo from "./a";`
|
||||
// `import { foo as bar } from "./a";` --> `import bar from "./a";`
|
||||
const defaultImport = createIdentifier(parent.name.text);
|
||||
if (parent.parent.elements.length === 1) {
|
||||
changes.replaceNode(importingSourceFile, parent.parent, defaultImport);
|
||||
}
|
||||
else {
|
||||
// `export { foo } from "./a";` --> `export { default as foo } from "./a";`
|
||||
// `export { foo as bar } from "./a";` --> `export { default as bar } from "./a";`
|
||||
// `export { foo as default } from "./a";` --> `export { default } from "./a";`
|
||||
// (Because `export foo from "./a";` isn't valid syntax.)
|
||||
changes.replaceNode(importingSourceFile, spec, makeExportSpecifier("default", spec.name.text));
|
||||
changes.delete(importingSourceFile, parent);
|
||||
changes.insertNodeBefore(importingSourceFile, parent.parent, defaultImport);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.ExportSpecifier: {
|
||||
// `export { foo } from "./a";` --> `export { default as foo } from "./a";`
|
||||
// `export { foo as bar } from "./a";` --> `export { default as bar } from "./a";`
|
||||
// `export { foo as default } from "./a";` --> `export { default } from "./a";`
|
||||
// (Because `export foo from "./a";` isn't valid syntax.)
|
||||
changes.replaceNode(importingSourceFile, parent, makeExportSpecifier("default", parent.name.text));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Debug.failBadSyntaxKind(parent);
|
||||
Debug.assertNever(parent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ namespace ts.refactor {
|
||||
const actionNameNamespaceToNamed = "Convert namespace import to named imports";
|
||||
const actionNameNamedToNamespace = "Convert named imports to namespace import";
|
||||
registerRefactor(refactorName, {
|
||||
getAvailableActions(context): ApplicableRefactorInfo[] | undefined {
|
||||
getAvailableActions(context): ReadonlyArray<ApplicableRefactorInfo> {
|
||||
const i = getImportToConvert(context);
|
||||
if (!i) return undefined;
|
||||
if (!i) return emptyArray;
|
||||
const description = i.kind === SyntaxKind.NamespaceImport ? Diagnostics.Convert_namespace_import_to_named_imports.message : Diagnostics.Convert_named_imports_to_namespace_import.message;
|
||||
const actionName = i.kind === SyntaxKind.NamespaceImport ? actionNameNamespaceToNamed : actionNameNamedToNamespace;
|
||||
return [{ name: refactorName, description, actions: [{ name: actionName, description }] }];
|
||||
|
||||
@@ -7,18 +7,18 @@ namespace ts.refactor.extractSymbol {
|
||||
* Compute the associated code actions
|
||||
* Exported for tests.
|
||||
*/
|
||||
export function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined {
|
||||
export function getAvailableActions(context: RefactorContext): ReadonlyArray<ApplicableRefactorInfo> {
|
||||
const rangeToExtract = getRangeToExtract(context.file, getRefactorContextSpan(context));
|
||||
|
||||
const targetRange = rangeToExtract.targetRange;
|
||||
if (targetRange === undefined) {
|
||||
return undefined;
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
const extractions = getPossibleExtractions(targetRange, context);
|
||||
if (extractions === undefined) {
|
||||
// No extractions possible
|
||||
return undefined;
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
const functionActions: RefactorActionInfo[] = [];
|
||||
@@ -82,7 +82,7 @@ namespace ts.refactor.extractSymbol {
|
||||
});
|
||||
}
|
||||
|
||||
return infos.length ? infos : undefined;
|
||||
return infos.length ? infos : emptyArray;
|
||||
}
|
||||
|
||||
/* Exported for tests */
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
|
||||
readonly renameAccessor: boolean;
|
||||
}
|
||||
|
||||
function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined {
|
||||
if (!getConvertibleFieldAtPosition(context)) return undefined;
|
||||
function getAvailableActions(context: RefactorContext): ReadonlyArray<ApplicableRefactorInfo> {
|
||||
if (!getConvertibleFieldAtPosition(context)) return emptyArray;
|
||||
|
||||
return [{
|
||||
name: actionName,
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
namespace ts.refactor {
|
||||
const refactorName = "Move to a new file";
|
||||
registerRefactor(refactorName, {
|
||||
getAvailableActions(context): ApplicableRefactorInfo[] | undefined {
|
||||
if (!context.preferences.allowTextChangesInNewFiles || getStatementsToMove(context) === undefined) return undefined;
|
||||
getAvailableActions(context): ReadonlyArray<ApplicableRefactorInfo> {
|
||||
if (!context.preferences.allowTextChangesInNewFiles || getStatementsToMove(context) === undefined) return emptyArray;
|
||||
const description = getLocaleSpecificMessage(Diagnostics.Move_to_a_new_file);
|
||||
return [{ name: refactorName, description, actions: [{ name: refactorName, description }] }];
|
||||
},
|
||||
|
||||
@@ -1139,7 +1139,7 @@ namespace ts {
|
||||
const useCaseSensitiveFileNames = hostUsesCaseSensitiveFileNames(host);
|
||||
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
|
||||
const sourceMapper = getSourceMapper(getCanonicalFileName, currentDirectory, log, host, () => program);
|
||||
const sourceMapper = getSourceMapper(useCaseSensitiveFileNames, currentDirectory, log, host, () => program);
|
||||
|
||||
function getValidSourceFile(fileName: string): SourceFile {
|
||||
const sourceFile = program.getSourceFile(fileName);
|
||||
@@ -1496,7 +1496,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/// Goto definition
|
||||
function getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] | undefined {
|
||||
function getDefinitionAtPosition(fileName: string, position: number): ReadonlyArray<DefinitionInfo> | undefined {
|
||||
synchronizeHostData();
|
||||
return GoToDefinition.getDefinitionAtPosition(program, getValidSourceFile(fileName), position);
|
||||
}
|
||||
@@ -1506,7 +1506,7 @@ namespace ts {
|
||||
return GoToDefinition.getDefinitionAndBoundSpan(program, getValidSourceFile(fileName), position);
|
||||
}
|
||||
|
||||
function getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] | undefined {
|
||||
function getTypeDefinitionAtPosition(fileName: string, position: number): ReadonlyArray<DefinitionInfo> | undefined {
|
||||
synchronizeHostData();
|
||||
return GoToDefinition.getTypeDefinitionAtPosition(program.getTypeChecker(), getValidSourceFile(fileName), position);
|
||||
}
|
||||
@@ -1519,7 +1519,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/// References and Occurrences
|
||||
function getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[] | undefined {
|
||||
function getOccurrencesAtPosition(fileName: string, position: number): ReadonlyArray<ReferenceEntry> | undefined {
|
||||
return flatMap(getDocumentHighlights(fileName, position, [fileName]), entry => entry.highlightSpans.map<ReferenceEntry>(highlightSpan => ({
|
||||
fileName: entry.fileName,
|
||||
textSpan: highlightSpan.textSpan,
|
||||
@@ -1533,7 +1533,7 @@ namespace ts {
|
||||
const normalizedFileName = normalizePath(fileName);
|
||||
Debug.assert(filesToSearch.some(f => normalizePath(f) === normalizedFileName));
|
||||
synchronizeHostData();
|
||||
const sourceFilesToSearch = map(filesToSearch, f => Debug.assertDefined(program.getSourceFile(f)));
|
||||
const sourceFilesToSearch = filesToSearch.map(getValidSourceFile);
|
||||
const sourceFile = getValidSourceFile(fileName);
|
||||
return DocumentHighlights.getDocumentHighlights(program, cancellationToken, sourceFile, position, sourceFilesToSearch);
|
||||
}
|
||||
|
||||
+76
-46
@@ -1,69 +1,64 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
// Sometimes tools can sometimes see the following line as a source mapping url comment, so we mangle it a bit (the [M])
|
||||
const sourceMapCommentRegExp = /^\/\/[@#] source[M]appingURL=(.+)\s*$/;
|
||||
const whitespaceOrMapCommentRegExp = /^\s*(\/\/[@#] .*)?$/;
|
||||
const base64UrlRegExp = /^data:(?:application\/json(?:;charset=[uU][tT][fF]-8);base64,([A-Za-z0-9+\/=]+)$)?/;
|
||||
|
||||
export interface SourceMapper {
|
||||
toLineColumnOffset(fileName: string, position: number): LineAndCharacter;
|
||||
tryGetOriginalLocation(info: sourcemaps.SourceMappableLocation): sourcemaps.SourceMappableLocation | undefined;
|
||||
tryGetGeneratedLocation(info: sourcemaps.SourceMappableLocation): sourcemaps.SourceMappableLocation | undefined;
|
||||
tryGetSourcePosition(info: DocumentPosition): DocumentPosition | undefined;
|
||||
tryGetGeneratedPosition(info: DocumentPosition): DocumentPosition | undefined;
|
||||
clearCache(): void;
|
||||
}
|
||||
|
||||
export function getSourceMapper(
|
||||
getCanonicalFileName: GetCanonicalFileName,
|
||||
useCaseSensitiveFileNames: boolean,
|
||||
currentDirectory: string,
|
||||
log: (message: string) => void,
|
||||
host: LanguageServiceHost,
|
||||
getProgram: () => Program,
|
||||
): SourceMapper {
|
||||
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
let sourcemappedFileCache: SourceFileLikeCache;
|
||||
return { tryGetOriginalLocation, tryGetGeneratedLocation, toLineColumnOffset, clearCache };
|
||||
return { tryGetSourcePosition, tryGetGeneratedPosition, toLineColumnOffset, clearCache };
|
||||
|
||||
function toPath(fileName: string) {
|
||||
return ts.toPath(fileName, currentDirectory, getCanonicalFileName);
|
||||
}
|
||||
|
||||
function scanForSourcemapURL(fileName: string) {
|
||||
const mappedFile = sourcemappedFileCache.get(toPath(fileName, currentDirectory, getCanonicalFileName));
|
||||
const mappedFile = sourcemappedFileCache.get(toPath(fileName));
|
||||
if (!mappedFile) {
|
||||
return;
|
||||
}
|
||||
const starts = getLineStarts(mappedFile);
|
||||
for (let index = starts.length - 1; index >= 0; index--) {
|
||||
const lineText = mappedFile.text.substring(starts[index], starts[index + 1]);
|
||||
const comment = sourceMapCommentRegExp.exec(lineText);
|
||||
if (comment) {
|
||||
return comment[1];
|
||||
}
|
||||
// If we see a non-whitespace/map comment-like line, break, to avoid scanning up the entire file
|
||||
else if (!lineText.match(whitespaceOrMapCommentRegExp)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return tryGetSourceMappingURL(mappedFile.text, getLineStarts(mappedFile));
|
||||
}
|
||||
|
||||
function convertDocumentToSourceMapper(file: { sourceMapper?: sourcemaps.SourceMapper }, contents: string, mapFileName: string) {
|
||||
let maps: sourcemaps.SourceMapData | undefined;
|
||||
try {
|
||||
maps = JSON.parse(contents);
|
||||
}
|
||||
catch {
|
||||
// swallow error
|
||||
}
|
||||
if (!maps || !maps.sources || !maps.file || !maps.mappings) {
|
||||
function convertDocumentToSourceMapper(file: { sourceMapper?: DocumentPositionMapper }, contents: string, mapFileName: string) {
|
||||
const map = tryParseRawSourceMap(contents);
|
||||
if (!map || !map.sources || !map.file || !map.mappings) {
|
||||
// obviously invalid map
|
||||
return file.sourceMapper = sourcemaps.identitySourceMapper;
|
||||
return file.sourceMapper = identitySourceMapConsumer;
|
||||
}
|
||||
return file.sourceMapper = sourcemaps.decode({
|
||||
readFile: s => host.readFile!(s), // TODO: GH#18217
|
||||
fileExists: s => host.fileExists!(s), // TODO: GH#18217
|
||||
const program = getProgram();
|
||||
return file.sourceMapper = createDocumentPositionMapper({
|
||||
getSourceFileLike: s => {
|
||||
// Lookup file in program, if provided
|
||||
const file = program && program.getSourceFileByPath(s);
|
||||
// file returned here could be .d.ts when asked for .ts file if projectReferences and module resolution created this source file
|
||||
if (file === undefined || file.resolvedPath !== s) {
|
||||
// Otherwise check the cache (which may hit disk)
|
||||
return sourcemappedFileCache.get(s);
|
||||
}
|
||||
return file;
|
||||
},
|
||||
getCanonicalFileName,
|
||||
log,
|
||||
}, mapFileName, maps, getProgram(), sourcemappedFileCache);
|
||||
}, map, mapFileName);
|
||||
}
|
||||
|
||||
function getSourceMapper(fileName: string, file: SourceFileLike): sourcemaps.SourceMapper {
|
||||
function getSourceMapper(fileName: string, file: SourceFileLike): DocumentPositionMapper {
|
||||
if (!host.readFile || !host.fileExists) {
|
||||
return file.sourceMapper = sourcemaps.identitySourceMapper;
|
||||
return file.sourceMapper = identitySourceMapConsumer;
|
||||
}
|
||||
if (file.sourceMapper) {
|
||||
return file.sourceMapper;
|
||||
@@ -86,26 +81,30 @@ namespace ts {
|
||||
}
|
||||
possibleMapLocations.push(fileName + ".map");
|
||||
for (const location of possibleMapLocations) {
|
||||
const mapPath = toPath(location, getDirectoryPath(fileName), getCanonicalFileName);
|
||||
const mapPath = ts.toPath(location, getDirectoryPath(fileName), getCanonicalFileName);
|
||||
if (host.fileExists(mapPath)) {
|
||||
return convertDocumentToSourceMapper(file, host.readFile(mapPath)!, mapPath); // TODO: GH#18217
|
||||
}
|
||||
}
|
||||
return file.sourceMapper = sourcemaps.identitySourceMapper;
|
||||
return file.sourceMapper = identitySourceMapConsumer;
|
||||
}
|
||||
|
||||
function tryGetOriginalLocation(info: sourcemaps.SourceMappableLocation): sourcemaps.SourceMappableLocation | undefined {
|
||||
function tryGetSourcePosition(info: DocumentPosition): DocumentPosition | undefined {
|
||||
if (!isDeclarationFileName(info.fileName)) return undefined;
|
||||
|
||||
const file = getFile(info.fileName);
|
||||
if (!file) return undefined;
|
||||
const newLoc = getSourceMapper(info.fileName, file).getOriginalPosition(info);
|
||||
return newLoc === info ? undefined : tryGetOriginalLocation(newLoc) || newLoc;
|
||||
const newLoc = getSourceMapper(info.fileName, file).getSourcePosition(info);
|
||||
return newLoc === info ? undefined : tryGetSourcePosition(newLoc) || newLoc;
|
||||
}
|
||||
|
||||
function tryGetGeneratedLocation(info: sourcemaps.SourceMappableLocation): sourcemaps.SourceMappableLocation | undefined {
|
||||
function tryGetGeneratedPosition(info: DocumentPosition): DocumentPosition | undefined {
|
||||
const program = getProgram();
|
||||
const declarationPath = getDeclarationEmitOutputFilePathWorker(info.fileName, program.getCompilerOptions(), currentDirectory, program.getCommonSourceDirectory(), getCanonicalFileName);
|
||||
const options = program.getCompilerOptions();
|
||||
const outPath = options.outFile || options.out;
|
||||
const declarationPath = outPath ?
|
||||
removeFileExtension(outPath) + Extension.Dts :
|
||||
getDeclarationEmitOutputFilePathWorker(info.fileName, program.getCompilerOptions(), currentDirectory, program.getCommonSourceDirectory(), getCanonicalFileName);
|
||||
if (declarationPath === undefined) return undefined;
|
||||
const declarationFile = getFile(declarationPath);
|
||||
if (!declarationFile) return undefined;
|
||||
@@ -114,12 +113,16 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getFile(fileName: string): SourceFileLike | undefined {
|
||||
return getProgram().getSourceFile(fileName) || sourcemappedFileCache.get(toPath(fileName, currentDirectory, getCanonicalFileName));
|
||||
const path = toPath(fileName);
|
||||
const file = getProgram().getSourceFileByPath(path);
|
||||
if (file && file.resolvedPath === path) {
|
||||
return file;
|
||||
}
|
||||
return sourcemappedFileCache.get(path);
|
||||
}
|
||||
|
||||
function toLineColumnOffset(fileName: string, position: number): LineAndCharacter {
|
||||
const path = toPath(fileName, currentDirectory, getCanonicalFileName);
|
||||
const file = getProgram().getSourceFile(path) || sourcemappedFileCache.get(path)!; // TODO: GH#18217
|
||||
const file = getFile(fileName)!; // TODO: GH#18217
|
||||
return file.getLineAndCharacterOfPosition(position);
|
||||
}
|
||||
|
||||
@@ -127,4 +130,31 @@ namespace ts {
|
||||
sourcemappedFileCache = createSourceFileLikeCache(host);
|
||||
}
|
||||
}
|
||||
|
||||
interface SourceFileLikeCache {
|
||||
get(path: Path): SourceFileLike | undefined;
|
||||
}
|
||||
|
||||
function createSourceFileLikeCache(host: { readFile?: (path: string) => string | undefined, fileExists?: (path: string) => boolean }): SourceFileLikeCache {
|
||||
const cached = createMap<SourceFileLike>();
|
||||
return {
|
||||
get(path: Path) {
|
||||
if (cached.has(path)) {
|
||||
return cached.get(path);
|
||||
}
|
||||
if (!host.fileExists || !host.readFile || !host.fileExists(path)) return;
|
||||
// And failing that, check the disk
|
||||
const text = host.readFile(path)!; // TODO: GH#18217
|
||||
const file = {
|
||||
text,
|
||||
lineMap: undefined,
|
||||
getLineAndCharacterOfPosition(pos: number) {
|
||||
return computeLineAndCharacterOfPosition(getLineStarts(this), pos);
|
||||
}
|
||||
} as SourceFileLike;
|
||||
cached.set(path, file);
|
||||
return file;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,243 @@
|
||||
/* @internal */
|
||||
namespace ts.Completions.PathCompletions {
|
||||
export interface NameAndKind {
|
||||
namespace ts.Completions.StringCompletions {
|
||||
export function getStringLiteralCompletions(sourceFile: SourceFile, position: number, contextToken: Node | undefined, checker: TypeChecker, options: CompilerOptions, host: LanguageServiceHost, log: Log, preferences: UserPreferences): CompletionInfo | undefined {
|
||||
if (isInReferenceComment(sourceFile, position)) {
|
||||
const entries = getTripleSlashReferenceCompletion(sourceFile, position, options, host);
|
||||
return entries && convertPathCompletions(entries);
|
||||
}
|
||||
if (isInString(sourceFile, position, contextToken)) {
|
||||
return !contextToken || !isStringLiteralLike(contextToken)
|
||||
? undefined
|
||||
: convertStringLiteralCompletions(getStringLiteralCompletionEntries(sourceFile, contextToken, position, checker, options, host), sourceFile, checker, log, preferences);
|
||||
}
|
||||
}
|
||||
|
||||
function convertStringLiteralCompletions(completion: StringLiteralCompletion | undefined, sourceFile: SourceFile, checker: TypeChecker, log: Log, preferences: UserPreferences): CompletionInfo | undefined {
|
||||
if (completion === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
switch (completion.kind) {
|
||||
case StringLiteralCompletionKind.Paths:
|
||||
return convertPathCompletions(completion.paths);
|
||||
case StringLiteralCompletionKind.Properties: {
|
||||
const entries: CompletionEntry[] = [];
|
||||
getCompletionEntriesFromSymbols(completion.symbols, entries, sourceFile, sourceFile, checker, ScriptTarget.ESNext, log, CompletionKind.String, preferences); // Target will not be used, so arbitrary
|
||||
return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: completion.hasIndexSignature, entries };
|
||||
}
|
||||
case StringLiteralCompletionKind.Types: {
|
||||
const entries = completion.types.map(type => ({ name: type.value, kindModifiers: ScriptElementKindModifier.none, kind: ScriptElementKind.string, sortText: "0" }));
|
||||
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: completion.isNewIdentifier, entries };
|
||||
}
|
||||
default:
|
||||
return Debug.assertNever(completion);
|
||||
}
|
||||
}
|
||||
|
||||
export function getStringLiteralCompletionDetails(name: string, sourceFile: SourceFile, position: number, contextToken: Node | undefined, checker: TypeChecker, options: CompilerOptions, host: LanguageServiceHost, cancellationToken: CancellationToken) {
|
||||
if (!contextToken || !isStringLiteralLike(contextToken)) return undefined;
|
||||
const completions = getStringLiteralCompletionEntries(sourceFile, contextToken, position, checker, options, host);
|
||||
return completions && stringLiteralCompletionDetails(name, contextToken, completions, sourceFile, checker, cancellationToken);
|
||||
}
|
||||
|
||||
function stringLiteralCompletionDetails(name: string, location: Node, completion: StringLiteralCompletion, sourceFile: SourceFile, checker: TypeChecker, cancellationToken: CancellationToken): CompletionEntryDetails | undefined {
|
||||
switch (completion.kind) {
|
||||
case StringLiteralCompletionKind.Paths: {
|
||||
const match = find(completion.paths, p => p.name === name);
|
||||
return match && createCompletionDetails(name, kindModifiersFromExtension(match.extension), match.kind, [textPart(name)]);
|
||||
}
|
||||
case StringLiteralCompletionKind.Properties: {
|
||||
const match = find(completion.symbols, s => s.name === name);
|
||||
return match && createCompletionDetailsForSymbol(match, checker, sourceFile, location, cancellationToken);
|
||||
}
|
||||
case StringLiteralCompletionKind.Types:
|
||||
return find(completion.types, t => t.value === name) ? createCompletionDetails(name, ScriptElementKindModifier.none, ScriptElementKind.typeElement, [textPart(name)]) : undefined;
|
||||
default:
|
||||
return Debug.assertNever(completion);
|
||||
}
|
||||
}
|
||||
|
||||
function convertPathCompletions(pathCompletions: ReadonlyArray<PathCompletion>): CompletionInfo {
|
||||
const isGlobalCompletion = false; // We don't want the editor to offer any other completions, such as snippets, inside a comment.
|
||||
const isNewIdentifierLocation = true; // The user may type in a path that doesn't yet exist, creating a "new identifier" with respect to the collection of identifiers the server is aware of.
|
||||
const entries = pathCompletions.map(({ name, kind, span, extension }): CompletionEntry =>
|
||||
({ name, kind, kindModifiers: kindModifiersFromExtension(extension), sortText: "0", replacementSpan: span }));
|
||||
return { isGlobalCompletion, isMemberCompletion: false, isNewIdentifierLocation, entries };
|
||||
}
|
||||
function kindModifiersFromExtension(extension: Extension | undefined): ScriptElementKindModifier {
|
||||
switch (extension) {
|
||||
case Extension.Dts: return ScriptElementKindModifier.dtsModifier;
|
||||
case Extension.Js: return ScriptElementKindModifier.jsModifier;
|
||||
case Extension.Json: return ScriptElementKindModifier.jsonModifier;
|
||||
case Extension.Jsx: return ScriptElementKindModifier.jsxModifier;
|
||||
case Extension.Ts: return ScriptElementKindModifier.tsModifier;
|
||||
case Extension.Tsx: return ScriptElementKindModifier.tsxModifier;
|
||||
case undefined: return ScriptElementKindModifier.none;
|
||||
default:
|
||||
return Debug.assertNever(extension);
|
||||
}
|
||||
}
|
||||
|
||||
const enum StringLiteralCompletionKind { Paths, Properties, Types }
|
||||
interface StringLiteralCompletionsFromProperties {
|
||||
readonly kind: StringLiteralCompletionKind.Properties;
|
||||
readonly symbols: ReadonlyArray<Symbol>;
|
||||
readonly hasIndexSignature: boolean;
|
||||
}
|
||||
interface StringLiteralCompletionsFromTypes {
|
||||
readonly kind: StringLiteralCompletionKind.Types;
|
||||
readonly types: ReadonlyArray<StringLiteralType>;
|
||||
readonly isNewIdentifier: boolean;
|
||||
}
|
||||
type StringLiteralCompletion = { readonly kind: StringLiteralCompletionKind.Paths, readonly paths: ReadonlyArray<PathCompletion> } | StringLiteralCompletionsFromProperties | StringLiteralCompletionsFromTypes;
|
||||
function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringLiteralLike, position: number, typeChecker: TypeChecker, compilerOptions: CompilerOptions, host: LanguageServiceHost): StringLiteralCompletion | undefined {
|
||||
const { parent } = node;
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.LiteralType:
|
||||
switch (parent.parent.kind) {
|
||||
case SyntaxKind.TypeReference:
|
||||
return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(parent as LiteralTypeNode)), isNewIdentifier: false };
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
// Get all apparent property names
|
||||
// i.e. interface Foo {
|
||||
// foo: string;
|
||||
// bar: string;
|
||||
// }
|
||||
// let x: Foo["/*completion position*/"]
|
||||
return stringLiteralCompletionsFromProperties(typeChecker.getTypeFromTypeNode((parent.parent as IndexedAccessTypeNode).objectType));
|
||||
case SyntaxKind.ImportType:
|
||||
return { kind: StringLiteralCompletionKind.Paths, paths: getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker) };
|
||||
case SyntaxKind.UnionType: {
|
||||
if (!isTypeReferenceNode(parent.parent.parent)) return undefined;
|
||||
const alreadyUsedTypes = getAlreadyUsedTypesInStringLiteralUnion(parent.parent as UnionTypeNode, parent as LiteralTypeNode);
|
||||
const types = getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(parent.parent as UnionTypeNode)).filter(t => !contains(alreadyUsedTypes, t.value));
|
||||
return { kind: StringLiteralCompletionKind.Types, types, isNewIdentifier: false };
|
||||
}
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
if (isObjectLiteralExpression(parent.parent) && (<PropertyAssignment>parent).name === node) {
|
||||
// Get quoted name of properties of the object literal expression
|
||||
// i.e. interface ConfigFiles {
|
||||
// 'jspm:dev': string
|
||||
// }
|
||||
// let files: ConfigFiles = {
|
||||
// '/*completion position*/'
|
||||
// }
|
||||
//
|
||||
// function foo(c: ConfigFiles) {}
|
||||
// foo({
|
||||
// '/*completion position*/'
|
||||
// });
|
||||
return stringLiteralCompletionsFromProperties(typeChecker.getContextualType(parent.parent));
|
||||
}
|
||||
return fromContextualType();
|
||||
|
||||
case SyntaxKind.ElementAccessExpression: {
|
||||
const { expression, argumentExpression } = parent as ElementAccessExpression;
|
||||
if (node === argumentExpression) {
|
||||
// Get all names of properties on the expression
|
||||
// i.e. interface A {
|
||||
// 'prop1': string
|
||||
// }
|
||||
// let a: A;
|
||||
// a['/*completion position*/']
|
||||
return stringLiteralCompletionsFromProperties(typeChecker.getTypeAtLocation(expression));
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
if (!isRequireCall(parent, /*checkArgumentIsStringLiteralLike*/ false) && !isImportCall(parent)) {
|
||||
const argumentInfo = SignatureHelp.getArgumentInfoForCompletions(node, position, sourceFile);
|
||||
// Get string literal completions from specialized signatures of the target
|
||||
// i.e. declare function f(a: 'A');
|
||||
// f("/*completion position*/")
|
||||
return argumentInfo ? getStringLiteralCompletionsFromSignature(argumentInfo, typeChecker) : fromContextualType();
|
||||
}
|
||||
// falls through (is `require("")` or `import("")`)
|
||||
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
case SyntaxKind.ExternalModuleReference:
|
||||
// Get all known external module names or complete a path to a module
|
||||
// i.e. import * as ns from "/*completion position*/";
|
||||
// var y = import("/*completion position*/");
|
||||
// import x = require("/*completion position*/");
|
||||
// var y = require("/*completion position*/");
|
||||
// export * from "/*completion position*/";
|
||||
return { kind: StringLiteralCompletionKind.Paths, paths: getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker) };
|
||||
|
||||
default:
|
||||
return fromContextualType();
|
||||
}
|
||||
|
||||
function fromContextualType(): StringLiteralCompletion {
|
||||
// Get completion for string literal from string literal type
|
||||
// i.e. var x: "hi" | "hello" = "/*completion position*/"
|
||||
return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(getContextualTypeFromParent(node, typeChecker)), isNewIdentifier: false };
|
||||
}
|
||||
}
|
||||
|
||||
function getAlreadyUsedTypesInStringLiteralUnion(union: UnionTypeNode, current: LiteralTypeNode): ReadonlyArray<string> {
|
||||
return mapDefined(union.types, type =>
|
||||
type !== current && isLiteralTypeNode(type) && isStringLiteral(type.literal) ? type.literal.text : undefined);
|
||||
}
|
||||
|
||||
function getStringLiteralCompletionsFromSignature(argumentInfo: SignatureHelp.ArgumentInfoForCompletions, checker: TypeChecker): StringLiteralCompletionsFromTypes {
|
||||
let isNewIdentifier = false;
|
||||
|
||||
const uniques = createMap<true>();
|
||||
const candidates: Signature[] = [];
|
||||
checker.getResolvedSignature(argumentInfo.invocation, candidates, argumentInfo.argumentCount);
|
||||
const types = flatMap(candidates, candidate => {
|
||||
if (!candidate.hasRestParameter && argumentInfo.argumentCount > candidate.parameters.length) return;
|
||||
const type = checker.getParameterType(candidate, argumentInfo.argumentIndex);
|
||||
isNewIdentifier = isNewIdentifier || !!(type.flags & TypeFlags.String);
|
||||
return getStringLiteralTypes(type, uniques);
|
||||
});
|
||||
|
||||
return { kind: StringLiteralCompletionKind.Types, types, isNewIdentifier };
|
||||
}
|
||||
|
||||
function stringLiteralCompletionsFromProperties(type: Type | undefined): StringLiteralCompletionsFromProperties | undefined {
|
||||
return type && { kind: StringLiteralCompletionKind.Properties, symbols: type.getApparentProperties(), hasIndexSignature: hasIndexSignature(type) };
|
||||
}
|
||||
|
||||
function getStringLiteralTypes(type: Type | undefined, uniques = createMap<true>()): ReadonlyArray<StringLiteralType> {
|
||||
if (!type) return emptyArray;
|
||||
type = skipConstraint(type);
|
||||
return type.isUnion()
|
||||
? flatMap(type.types, t => getStringLiteralTypes(t, uniques))
|
||||
: type.isStringLiteral() && !(type.flags & TypeFlags.EnumLiteral) && addToSeen(uniques, type.value)
|
||||
? [type]
|
||||
: emptyArray;
|
||||
}
|
||||
|
||||
interface NameAndKind {
|
||||
readonly name: string;
|
||||
readonly kind: ScriptElementKind.scriptElement | ScriptElementKind.directory | ScriptElementKind.externalModuleName;
|
||||
readonly extension: Extension | undefined;
|
||||
}
|
||||
export interface PathCompletion extends NameAndKind {
|
||||
interface PathCompletion extends NameAndKind {
|
||||
readonly span: TextSpan | undefined;
|
||||
}
|
||||
|
||||
function nameAndKind(name: string, kind: NameAndKind["kind"]): NameAndKind {
|
||||
return { name, kind };
|
||||
function nameAndKind(name: string, kind: NameAndKind["kind"], extension: Extension | undefined): NameAndKind {
|
||||
return { name, kind, extension };
|
||||
}
|
||||
function addReplacementSpans(text: string, textStart: number, names: ReadonlyArray<NameAndKind>): ReadonlyArray<PathCompletion> {
|
||||
const span = getDirectoryFragmentTextSpan(text, textStart);
|
||||
return names.map(({ name, kind }): PathCompletion => ({ name, kind, span }));
|
||||
function directoryResult(name: string): NameAndKind {
|
||||
return nameAndKind(name, ScriptElementKind.directory, /*extension*/ undefined);
|
||||
}
|
||||
|
||||
export function getStringLiteralCompletionsFromModuleNames(sourceFile: SourceFile, node: LiteralExpression, compilerOptions: CompilerOptions, host: LanguageServiceHost, typeChecker: TypeChecker): ReadonlyArray<PathCompletion> {
|
||||
function addReplacementSpans(text: string, textStart: number, names: ReadonlyArray<NameAndKind>): ReadonlyArray<PathCompletion> {
|
||||
const span = getDirectoryFragmentTextSpan(text, textStart);
|
||||
return names.map(({ name, kind, extension }): PathCompletion => ({ name, kind, extension, span }));
|
||||
}
|
||||
|
||||
function getStringLiteralCompletionsFromModuleNames(sourceFile: SourceFile, node: LiteralExpression, compilerOptions: CompilerOptions, host: LanguageServiceHost, typeChecker: TypeChecker): ReadonlyArray<PathCompletion> {
|
||||
return addReplacementSpans(node.text, node.getStart(sourceFile) + 1, getStringLiteralCompletionsFromModuleNamesWorker(sourceFile, node, compilerOptions, host, typeChecker));
|
||||
}
|
||||
|
||||
@@ -26,19 +247,9 @@ namespace ts.Completions.PathCompletions {
|
||||
const scriptPath = sourceFile.path;
|
||||
const scriptDirectory = getDirectoryPath(scriptPath);
|
||||
|
||||
const extensionOptions = getExtensionOptions(compilerOptions);
|
||||
if (isPathRelativeToScript(literalValue) || isRootedDiskPath(literalValue)) {
|
||||
if (compilerOptions.rootDirs) {
|
||||
return getCompletionEntriesForDirectoryFragmentWithRootDirs(
|
||||
compilerOptions.rootDirs, literalValue, scriptDirectory, extensionOptions, compilerOptions, host, scriptPath);
|
||||
}
|
||||
else {
|
||||
return getCompletionEntriesForDirectoryFragment(literalValue, scriptDirectory, extensionOptions, host, scriptPath);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, compilerOptions, host, typeChecker);
|
||||
}
|
||||
return isPathRelativeToScript(literalValue) || !compilerOptions.baseUrl && (isRootedDiskPath(literalValue) || isUrl(literalValue))
|
||||
? getCompletionEntriesForRelativeModules(literalValue, scriptDirectory, compilerOptions, host, scriptPath)
|
||||
: getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, compilerOptions, host, typeChecker);
|
||||
}
|
||||
|
||||
interface ExtensionOptions {
|
||||
@@ -48,6 +259,17 @@ namespace ts.Completions.PathCompletions {
|
||||
function getExtensionOptions(compilerOptions: CompilerOptions, includeExtensions = false): ExtensionOptions {
|
||||
return { extensions: getSupportedExtensionsForModuleResolution(compilerOptions), includeExtensions };
|
||||
}
|
||||
function getCompletionEntriesForRelativeModules(literalValue: string, scriptDirectory: string, compilerOptions: CompilerOptions, host: LanguageServiceHost, scriptPath: Path) {
|
||||
const extensionOptions = getExtensionOptions(compilerOptions);
|
||||
if (compilerOptions.rootDirs) {
|
||||
return getCompletionEntriesForDirectoryFragmentWithRootDirs(
|
||||
compilerOptions.rootDirs, literalValue, scriptDirectory, extensionOptions, compilerOptions, host, scriptPath);
|
||||
}
|
||||
else {
|
||||
return getCompletionEntriesForDirectoryFragment(literalValue, scriptDirectory, extensionOptions, host, scriptPath);
|
||||
}
|
||||
}
|
||||
|
||||
function getSupportedExtensionsForModuleResolution(compilerOptions: CompilerOptions): ReadonlyArray<Extension> {
|
||||
const extensions = getSupportedExtensions(compilerOptions);
|
||||
return compilerOptions.resolveJsonModule && getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeJs ?
|
||||
@@ -129,7 +351,7 @@ namespace ts.Completions.PathCompletions {
|
||||
*
|
||||
* both foo.ts and foo.tsx become foo
|
||||
*/
|
||||
const foundFiles = createMap<true>();
|
||||
const foundFiles = createMap<Extension | undefined>(); // maps file to its extension
|
||||
for (let filePath of files) {
|
||||
filePath = normalizePath(filePath);
|
||||
if (exclude && comparePaths(filePath, exclude, scriptPath, ignoreCase) === Comparison.EqualTo) {
|
||||
@@ -137,14 +359,11 @@ namespace ts.Completions.PathCompletions {
|
||||
}
|
||||
|
||||
const foundFileName = includeExtensions || fileExtensionIs(filePath, Extension.Json) ? getBaseFileName(filePath) : removeFileExtension(getBaseFileName(filePath));
|
||||
|
||||
if (!foundFiles.has(foundFileName)) {
|
||||
foundFiles.set(foundFileName, true);
|
||||
}
|
||||
foundFiles.set(foundFileName, tryGetExtensionFromPath(filePath));
|
||||
}
|
||||
|
||||
forEachKey(foundFiles, foundFile => {
|
||||
result.push(nameAndKind(foundFile, ScriptElementKind.scriptElement));
|
||||
foundFiles.forEach((ext, foundFile) => {
|
||||
result.push(nameAndKind(foundFile, ScriptElementKind.scriptElement, ext));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -155,7 +374,7 @@ namespace ts.Completions.PathCompletions {
|
||||
for (const directory of directories) {
|
||||
const directoryName = getBaseFileName(normalizePath(directory));
|
||||
if (directoryName !== "@types") {
|
||||
result.push(nameAndKind(directoryName, ScriptElementKind.directory));
|
||||
result.push(directoryResult(directoryName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,10 +402,10 @@ namespace ts.Completions.PathCompletions {
|
||||
if (!hasProperty(paths, path)) continue;
|
||||
const patterns = paths[path];
|
||||
if (patterns) {
|
||||
for (const { name, kind } of getCompletionsForPathMapping(path, patterns, fragment, baseDirectory, fileExtensions, host)) {
|
||||
for (const { name, kind, extension } of getCompletionsForPathMapping(path, patterns, fragment, baseDirectory, fileExtensions, host)) {
|
||||
// Path mappings may provide a duplicate way to get to something we've already added, so don't add again.
|
||||
if (!result.some(entry => entry.name === name)) {
|
||||
result.push(nameAndKind(name, kind));
|
||||
result.push(nameAndKind(name, kind, extension));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,7 +419,7 @@ namespace ts.Completions.PathCompletions {
|
||||
* Modules from node_modules (i.e. those listed in package.json)
|
||||
* This includes all files that are found in node_modules/moduleName/ with acceptable file extensions
|
||||
*/
|
||||
function getCompletionEntriesForNonRelativeModules(fragment: string, scriptPath: string, compilerOptions: CompilerOptions, host: LanguageServiceHost, typeChecker: TypeChecker): NameAndKind[] {
|
||||
function getCompletionEntriesForNonRelativeModules(fragment: string, scriptPath: string, compilerOptions: CompilerOptions, host: LanguageServiceHost, typeChecker: TypeChecker): ReadonlyArray<NameAndKind> {
|
||||
const { baseUrl, paths } = compilerOptions;
|
||||
|
||||
const result: NameAndKind[] = [];
|
||||
@@ -217,7 +436,7 @@ namespace ts.Completions.PathCompletions {
|
||||
|
||||
const fragmentDirectory = getFragmentDirectory(fragment);
|
||||
for (const ambientName of getAmbientModuleCompletions(fragment, fragmentDirectory, typeChecker)) {
|
||||
result.push(nameAndKind(ambientName, ScriptElementKind.externalModuleName));
|
||||
result.push(nameAndKind(ambientName, ScriptElementKind.externalModuleName, /*extension*/ undefined));
|
||||
}
|
||||
|
||||
getCompletionEntriesFromTypings(host, compilerOptions, scriptPath, fragmentDirectory, extensionOptions, result);
|
||||
@@ -230,7 +449,7 @@ namespace ts.Completions.PathCompletions {
|
||||
for (const moduleName of enumerateNodeModulesVisibleToScript(host, scriptPath)) {
|
||||
if (!result.some(entry => entry.name === moduleName)) {
|
||||
foundGlobal = true;
|
||||
result.push(nameAndKind(moduleName, ScriptElementKind.externalModuleName));
|
||||
result.push(nameAndKind(moduleName, ScriptElementKind.externalModuleName, /*extension*/ undefined));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -265,7 +484,7 @@ namespace ts.Completions.PathCompletions {
|
||||
getModulesForPathsPattern(remainingFragment, baseUrl, pattern, fileExtensions, host));
|
||||
|
||||
function justPathMappingName(name: string): ReadonlyArray<NameAndKind> {
|
||||
return startsWith(name, fragment) ? [{ name, kind: ScriptElementKind.directory }] : emptyArray;
|
||||
return startsWith(name, fragment) ? [directoryResult(name)] : emptyArray;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,15 +520,21 @@ namespace ts.Completions.PathCompletions {
|
||||
// doesn't support. For now, this is safer but slower
|
||||
const includeGlob = normalizedSuffix ? "**/*" : "./*";
|
||||
|
||||
const matches = tryReadDirectory(host, baseDirectory, fileExtensions, /*exclude*/ undefined, [includeGlob]).map<NameAndKind>(name => ({ name, kind: ScriptElementKind.scriptElement }));
|
||||
const directories = tryGetDirectories(host, baseDirectory).map(d => combinePaths(baseDirectory, d)).map<NameAndKind>(name => ({ name, kind: ScriptElementKind.directory }));
|
||||
|
||||
// Trim away prefix and suffix
|
||||
return mapDefined<NameAndKind, NameAndKind>(concatenate(matches, directories), ({ name, kind }) => {
|
||||
const normalizedMatch = normalizePath(name);
|
||||
const inner = withoutStartAndEnd(normalizedMatch, completePrefix, normalizedSuffix);
|
||||
return inner !== undefined ? { name: removeLeadingDirectorySeparator(removeFileExtension(inner)), kind } : undefined;
|
||||
const matches = mapDefined(tryReadDirectory(host, baseDirectory, fileExtensions, /*exclude*/ undefined, [includeGlob]), match => {
|
||||
const extension = tryGetExtensionFromPath(match);
|
||||
const name = trimPrefixAndSuffix(match);
|
||||
return name === undefined ? undefined : nameAndKind(removeFileExtension(name), ScriptElementKind.scriptElement, extension);
|
||||
});
|
||||
const directories = mapDefined(tryGetDirectories(host, baseDirectory).map(d => combinePaths(baseDirectory, d)), dir => {
|
||||
const name = trimPrefixAndSuffix(dir);
|
||||
return name === undefined ? undefined : directoryResult(name);
|
||||
});
|
||||
return [...matches, ...directories];
|
||||
|
||||
function trimPrefixAndSuffix(path: string): string | undefined {
|
||||
const inner = withoutStartAndEnd(normalizePath(path), completePrefix, normalizedSuffix);
|
||||
return inner === undefined ? undefined : removeLeadingDirectorySeparator(inner);
|
||||
}
|
||||
}
|
||||
|
||||
function withoutStartAndEnd(s: string, start: string, end: string): string | undefined {
|
||||
@@ -335,7 +560,7 @@ namespace ts.Completions.PathCompletions {
|
||||
return nonRelativeModuleNames;
|
||||
}
|
||||
|
||||
export function getTripleSlashReferenceCompletion(sourceFile: SourceFile, position: number, compilerOptions: CompilerOptions, host: LanguageServiceHost): ReadonlyArray<PathCompletion> | undefined {
|
||||
function getTripleSlashReferenceCompletion(sourceFile: SourceFile, position: number, compilerOptions: CompilerOptions, host: LanguageServiceHost): ReadonlyArray<PathCompletion> | undefined {
|
||||
const token = getTokenAtPosition(sourceFile, position);
|
||||
const commentRanges = getLeadingCommentRanges(sourceFile.text, token.pos);
|
||||
const range = commentRanges && find(commentRanges, commentRange => position >= commentRange.pos && position <= commentRange.end);
|
||||
@@ -382,7 +607,10 @@ namespace ts.Completions.PathCompletions {
|
||||
if (options.types && !contains(options.types, packageName)) continue;
|
||||
|
||||
if (fragmentDirectory === undefined) {
|
||||
pushResult(packageName);
|
||||
if (!seen.has(packageName)) {
|
||||
result.push(nameAndKind(packageName, ScriptElementKind.externalModuleName, /*extension*/ undefined));
|
||||
seen.set(packageName, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const baseDirectory = combinePaths(directory, typeDirectoryName);
|
||||
@@ -393,13 +621,6 @@ namespace ts.Completions.PathCompletions {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pushResult(moduleName: string) {
|
||||
if (!seen.has(moduleName)) {
|
||||
result.push(nameAndKind(moduleName, ScriptElementKind.externalModuleName));
|
||||
seen.set(moduleName, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findPackageJsons(directory: string, host: LanguageServiceHost): string[] {
|
||||
@@ -140,13 +140,11 @@ namespace ts {
|
||||
return !!forEachReturnStatement(body, isReturnStatementWithFixablePromiseHandler);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isReturnStatementWithFixablePromiseHandler(node: Node): node is ReturnStatement {
|
||||
return isReturnStatement(node) && !!node.expression && isFixablePromiseHandler(node.expression);
|
||||
}
|
||||
|
||||
// Should be kept up to date with transformExpression in convertToAsyncFunction.ts
|
||||
/* @internal */
|
||||
export function isFixablePromiseHandler(node: Node): boolean {
|
||||
// ensure outermost call exists and is a promise handler
|
||||
if (!isPromiseHandler(node) || !node.arguments.every(isFixablePromiseArgument)) {
|
||||
|
||||
+17
-21
@@ -276,11 +276,15 @@ namespace ts.textChanges {
|
||||
return this.replaceRangeWithNodes(sourceFile, getAdjustedRange(sourceFile, oldNode, oldNode, options), newNodes, options);
|
||||
}
|
||||
|
||||
public replaceNodeWithText(sourceFile: SourceFile, oldNode: Node, text: string): void {
|
||||
this.replaceRangeWithText(sourceFile, getAdjustedRange(sourceFile, oldNode, oldNode, useNonAdjustedPositions), text);
|
||||
}
|
||||
|
||||
public replaceNodeRangeWithNodes(sourceFile: SourceFile, startNode: Node, endNode: Node, newNodes: ReadonlyArray<Node>, options: ReplaceWithMultipleNodesOptions & ConfigurableStartEnd = useNonAdjustedPositions) {
|
||||
return this.replaceRangeWithNodes(sourceFile, getAdjustedRange(sourceFile, startNode, endNode, options), newNodes, options);
|
||||
}
|
||||
|
||||
private nextCommaToken (sourceFile: SourceFile, node: Node): Node | undefined {
|
||||
private nextCommaToken(sourceFile: SourceFile, node: Node): Node | undefined {
|
||||
const next = findNextToken(node, node.parent, sourceFile);
|
||||
return next && next.kind === SyntaxKind.CommaToken ? next : undefined;
|
||||
}
|
||||
@@ -690,7 +694,7 @@ namespace ts.textChanges {
|
||||
}
|
||||
|
||||
private finishDeleteDeclarations(): void {
|
||||
const deletedNodesInLists = new NodeSet(); // Stores ids of nodes in lists that we already deleted. Used to avoid deleting `, ` twice in `a, b`.
|
||||
const deletedNodesInLists = new NodeSet(); // Stores nodes in lists that we already deleted. Used to avoid deleting `, ` twice in `a, b`.
|
||||
for (const { sourceFile, node } of this.deletedNodes) {
|
||||
if (!this.deletedNodes.some(d => d.sourceFile === sourceFile && rangeContainsRangeExclusive(d.node, node))) {
|
||||
if (isArray(node)) {
|
||||
@@ -921,6 +925,9 @@ namespace ts.textChanges {
|
||||
this.writer.write(s);
|
||||
this.setLastNonTriviaPosition(s, /*force*/ false);
|
||||
}
|
||||
writeComment(s: string): void {
|
||||
this.writer.writeComment(s);
|
||||
}
|
||||
writeKeyword(s: string): void {
|
||||
this.writer.writeKeyword(s);
|
||||
this.setLastNonTriviaPosition(s, /*force*/ false);
|
||||
@@ -933,6 +940,10 @@ namespace ts.textChanges {
|
||||
this.writer.writePunctuation(s);
|
||||
this.setLastNonTriviaPosition(s, /*force*/ false);
|
||||
}
|
||||
writeTrailingSemicolon(s: string): void {
|
||||
this.writer.writeTrailingSemicolon(s);
|
||||
this.setLastNonTriviaPosition(s, /*force*/ false);
|
||||
}
|
||||
writeParameter(s: string): void {
|
||||
this.writer.writeParameter(s);
|
||||
this.setLastNonTriviaPosition(s, /*force*/ false);
|
||||
@@ -953,9 +964,6 @@ namespace ts.textChanges {
|
||||
this.writer.writeSymbol(s, sym);
|
||||
this.setLastNonTriviaPosition(s, /*force*/ false);
|
||||
}
|
||||
writeTextOfNode(text: string, node: Node): void {
|
||||
this.writer.writeTextOfNode(text, node);
|
||||
}
|
||||
writeLine(): void {
|
||||
this.writer.writeLine();
|
||||
}
|
||||
@@ -1053,25 +1061,13 @@ namespace ts.textChanges {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Parameter: {
|
||||
const oldFunction = node.parent;
|
||||
if (isArrowFunction(oldFunction) && oldFunction.parameters.length === 1) {
|
||||
if (isArrowFunction(oldFunction) &&
|
||||
oldFunction.parameters.length === 1 &&
|
||||
!findChildOfKind(oldFunction, SyntaxKind.OpenParenToken, sourceFile)) {
|
||||
// Lambdas with exactly one parameter are special because, after removal, there
|
||||
// must be an empty parameter list (i.e. `()`) and this won't necessarily be the
|
||||
// case if the parameter is simply removed (e.g. in `x => 1`).
|
||||
const newFunction = updateArrowFunction(
|
||||
oldFunction,
|
||||
oldFunction.modifiers,
|
||||
oldFunction.typeParameters,
|
||||
/*parameters*/ undefined!, // TODO: GH#18217
|
||||
oldFunction.type,
|
||||
oldFunction.equalsGreaterThanToken,
|
||||
oldFunction.body);
|
||||
|
||||
// Drop leading and trailing trivia of the new function because we're only going
|
||||
// to replace the span (vs the full span) of the old function - the old leading
|
||||
// and trailing trivia will remain.
|
||||
suppressLeadingAndTrailingTrivia(newFunction);
|
||||
|
||||
changes.replaceNode(sourceFile, oldFunction, newFunction);
|
||||
changes.replaceNodeWithText(sourceFile, node, "()");
|
||||
}
|
||||
else {
|
||||
deleteNodeInList(changes, deletedNodesInLists, sourceFile, node);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"types.ts",
|
||||
"utilities.ts",
|
||||
"classifier.ts",
|
||||
"pathCompletions.ts",
|
||||
"stringCompletions.ts",
|
||||
"completions.ts",
|
||||
"documentHighlights.ts",
|
||||
"documentRegistry.ts",
|
||||
@@ -43,8 +43,10 @@
|
||||
"textChanges.ts",
|
||||
"codeFixProvider.ts",
|
||||
"refactorProvider.ts",
|
||||
"codefixes/addConvertToUnknownForNonOverlappingTypes.ts",
|
||||
"codefixes/addMissingInvocationForDecorator.ts",
|
||||
"codefixes/annotateWithTypeFromJSDoc.ts",
|
||||
"codefixes/inferFromUsage.ts",
|
||||
"codefixes/convertFunctionToEs6Class.ts",
|
||||
"codefixes/convertToAsyncFunction.ts",
|
||||
"codefixes/convertToEs6Module.ts",
|
||||
@@ -67,7 +69,6 @@
|
||||
"codefixes/fixAwaitInSyncFunction.ts",
|
||||
"codefixes/disableJsDiagnostics.ts",
|
||||
"codefixes/helpers.ts",
|
||||
"codefixes/inferFromUsage.ts",
|
||||
"codefixes/fixInvalidImportSyntax.ts",
|
||||
"codefixes/fixStrictClassInitialization.ts",
|
||||
"codefixes/generateTypes.ts",
|
||||
|
||||
+21
-9
@@ -86,12 +86,12 @@ namespace ts {
|
||||
getPositionOfLineAndCharacter(line: number, character: number): number;
|
||||
update(newText: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
|
||||
/* @internal */ sourceMapper?: sourcemaps.SourceMapper;
|
||||
/* @internal */ sourceMapper?: DocumentPositionMapper;
|
||||
}
|
||||
|
||||
export interface SourceFileLike {
|
||||
getLineAndCharacterOfPosition(pos: number): LineAndCharacter;
|
||||
/*@internal*/ sourceMapper?: sourcemaps.SourceMapper;
|
||||
/*@internal*/ sourceMapper?: DocumentPositionMapper;
|
||||
}
|
||||
|
||||
export interface SourceMapSource {
|
||||
@@ -238,6 +238,8 @@ namespace ts {
|
||||
/* @internal */
|
||||
export const emptyOptions = {};
|
||||
|
||||
export type WithMetadata<T> = T & { metadata?: unknown; };
|
||||
|
||||
//
|
||||
// Public services of a language service instance associated
|
||||
// with a language service host instance
|
||||
@@ -268,7 +270,7 @@ namespace ts {
|
||||
getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications;
|
||||
getEncodedSemanticClassifications(fileName: string, span: TextSpan): Classifications;
|
||||
|
||||
getCompletionsAtPosition(fileName: string, position: number, options: GetCompletionsAtPositionOptions | undefined): CompletionInfo | undefined;
|
||||
getCompletionsAtPosition(fileName: string, position: number, options: GetCompletionsAtPositionOptions | undefined): WithMetadata<CompletionInfo> | undefined;
|
||||
// "options" and "source" are optional only for backwards-compatibility
|
||||
getCompletionEntryDetails(
|
||||
fileName: string,
|
||||
@@ -289,19 +291,19 @@ namespace ts {
|
||||
getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): SignatureHelpItems | undefined;
|
||||
|
||||
getRenameInfo(fileName: string, position: number): RenameInfo;
|
||||
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[] | undefined;
|
||||
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReadonlyArray<RenameLocation> | undefined;
|
||||
|
||||
getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] | undefined;
|
||||
getDefinitionAtPosition(fileName: string, position: number): ReadonlyArray<DefinitionInfo> | undefined;
|
||||
getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan | undefined;
|
||||
getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] | undefined;
|
||||
getImplementationAtPosition(fileName: string, position: number): ImplementationLocation[] | undefined;
|
||||
getTypeDefinitionAtPosition(fileName: string, position: number): ReadonlyArray<DefinitionInfo> | undefined;
|
||||
getImplementationAtPosition(fileName: string, position: number): ReadonlyArray<ImplementationLocation> | undefined;
|
||||
|
||||
getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] | undefined;
|
||||
findReferences(fileName: string, position: number): ReferencedSymbol[] | undefined;
|
||||
getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[] | undefined;
|
||||
|
||||
/** @deprecated */
|
||||
getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[] | undefined;
|
||||
getOccurrencesAtPosition(fileName: string, position: number): ReadonlyArray<ReferenceEntry> | undefined;
|
||||
|
||||
getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles?: boolean): NavigateToItem[];
|
||||
getNavigationBarItems(fileName: string): NavigationBarItem[];
|
||||
@@ -978,6 +980,7 @@ namespace ts {
|
||||
Whitespace,
|
||||
Identifier,
|
||||
NumberLiteral,
|
||||
BigIntLiteral,
|
||||
StringLiteral,
|
||||
RegExpLiteral,
|
||||
}
|
||||
@@ -1126,7 +1129,14 @@ namespace ts {
|
||||
ambientModifier = "declare",
|
||||
staticModifier = "static",
|
||||
abstractModifier = "abstract",
|
||||
optionalModifier = "optional"
|
||||
optionalModifier = "optional",
|
||||
|
||||
dtsModifier = ".d.ts",
|
||||
tsModifier = ".ts",
|
||||
tsxModifier = ".tsx",
|
||||
jsModifier = ".js",
|
||||
jsxModifier = ".jsx",
|
||||
jsonModifier = ".json",
|
||||
}
|
||||
|
||||
export const enum ClassificationTypeNames {
|
||||
@@ -1134,6 +1144,7 @@ namespace ts {
|
||||
identifier = "identifier",
|
||||
keyword = "keyword",
|
||||
numericLiteral = "number",
|
||||
bigintLiteral = "bigint",
|
||||
operator = "operator",
|
||||
stringLiteral = "string",
|
||||
whiteSpace = "whitespace",
|
||||
@@ -1182,5 +1193,6 @@ namespace ts {
|
||||
jsxAttribute = 22,
|
||||
jsxText = 23,
|
||||
jsxAttributeStringLiteralValue = 24,
|
||||
bigintLiteral = 25,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1028,6 +1028,7 @@ namespace ts {
|
||||
case SyntaxKind.Identifier:
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.BigIntLiteral:
|
||||
case SyntaxKind.TrueKeyword:
|
||||
case SyntaxKind.FalseKeyword:
|
||||
|
||||
@@ -1409,7 +1410,6 @@ namespace ts {
|
||||
return node.modifiers && find(node.modifiers, m => m.kind === kind);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function insertImport(changes: textChanges.ChangeTracker, sourceFile: SourceFile, importDecl: Statement): void {
|
||||
const lastImportDeclaration = findLast(sourceFile.statements, isAnyImportSyntax);
|
||||
if (lastImportDeclaration) {
|
||||
@@ -1459,6 +1459,7 @@ namespace ts {
|
||||
writeKeyword: text => writeKind(text, SymbolDisplayPartKind.keyword),
|
||||
writeOperator: text => writeKind(text, SymbolDisplayPartKind.operator),
|
||||
writePunctuation: text => writeKind(text, SymbolDisplayPartKind.punctuation),
|
||||
writeTrailingSemicolon: text => writeKind(text, SymbolDisplayPartKind.punctuation),
|
||||
writeSpace: text => writeKind(text, SymbolDisplayPartKind.space),
|
||||
writeStringLiteral: text => writeKind(text, SymbolDisplayPartKind.stringLiteral),
|
||||
writeParameter: text => writeKind(text, SymbolDisplayPartKind.parameterName),
|
||||
@@ -1467,7 +1468,7 @@ namespace ts {
|
||||
writeSymbol,
|
||||
writeLine,
|
||||
write: unknownWrite,
|
||||
writeTextOfNode: unknownWrite,
|
||||
writeComment: unknownWrite,
|
||||
getText: () => "",
|
||||
getTextPos: () => 0,
|
||||
getColumn: () => 0,
|
||||
@@ -1597,7 +1598,6 @@ namespace ts {
|
||||
return displayPart("\n", SymbolDisplayPartKind.lineBreak);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function mapToDisplayParts(writeDisplayParts: (writer: DisplayPartsSymbolWriter) => void): SymbolDisplayPart[] {
|
||||
try {
|
||||
writeDisplayParts(displayPartWriter);
|
||||
@@ -1750,7 +1750,6 @@ namespace ts {
|
||||
/**
|
||||
* Sets EmitFlags to suppress leading and trailing trivia on the node.
|
||||
*/
|
||||
/* @internal */
|
||||
export function suppressLeadingAndTrailingTrivia(node: Node) {
|
||||
suppressLeadingTrivia(node);
|
||||
suppressTrailingTrivia(node);
|
||||
@@ -1759,7 +1758,6 @@ namespace ts {
|
||||
/**
|
||||
* Sets EmitFlags to suppress leading trivia on the node.
|
||||
*/
|
||||
/* @internal */
|
||||
export function suppressLeadingTrivia(node: Node) {
|
||||
addEmitFlagsRecursively(node, EmitFlags.NoLeadingComments, getFirstChild);
|
||||
}
|
||||
@@ -1767,7 +1765,6 @@ namespace ts {
|
||||
/**
|
||||
* Sets EmitFlags to suppress trailing trivia on the node.
|
||||
*/
|
||||
/* @internal */
|
||||
export function suppressTrailingTrivia(node: Node) {
|
||||
addEmitFlagsRecursively(node, EmitFlags.NoTrailingComments, getLastChild);
|
||||
}
|
||||
@@ -1782,7 +1779,6 @@ namespace ts {
|
||||
return node.forEachChild(child => child);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function getUniqueName(baseName: string, sourceFile: SourceFile): string {
|
||||
let nameText = baseName;
|
||||
for (let i = 1; !isFileLevelUniqueName(sourceFile, nameText); i++) {
|
||||
@@ -1796,7 +1792,6 @@ namespace ts {
|
||||
* to be on the reference, rather than the declaration, because it's closer to where the
|
||||
* user was before extracting it.
|
||||
*/
|
||||
/* @internal */
|
||||
export function getRenameLocation(edits: ReadonlyArray<FileTextChanges>, renameFilename: string, name: string, preferLastLocation: boolean): number {
|
||||
let delta = 0;
|
||||
let lastPos = -1;
|
||||
@@ -1847,4 +1842,70 @@ namespace ts {
|
||||
if (idx === -1) idx = change.indexOf('"' + name);
|
||||
return idx === -1 ? -1 : idx + 1;
|
||||
}
|
||||
|
||||
export function getContextualTypeFromParent(node: Expression, checker: TypeChecker): Type | undefined {
|
||||
const { parent } = node;
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.NewExpression:
|
||||
return checker.getContextualType(parent as NewExpression);
|
||||
case SyntaxKind.BinaryExpression: {
|
||||
const { left, operatorToken, right } = parent as BinaryExpression;
|
||||
return isEqualityOperatorKind(operatorToken.kind)
|
||||
? checker.getTypeAtLocation(node === right ? left : right)
|
||||
: checker.getContextualType(node);
|
||||
}
|
||||
case SyntaxKind.CaseClause:
|
||||
return (parent as CaseClause).expression === node ? getSwitchedType(parent as CaseClause, checker) : undefined;
|
||||
default:
|
||||
return checker.getContextualType(node);
|
||||
}
|
||||
}
|
||||
|
||||
export function quote(text: string, preferences: UserPreferences): string {
|
||||
if (/^\d+$/.test(text)) {
|
||||
return text;
|
||||
}
|
||||
const quoted = JSON.stringify(text);
|
||||
switch (preferences.quotePreference) {
|
||||
case undefined:
|
||||
case "double":
|
||||
return quoted;
|
||||
case "single":
|
||||
return `'${stripQuotes(quoted).replace("'", "\\'").replace('\\"', '"')}'`;
|
||||
default:
|
||||
return Debug.assertNever(preferences.quotePreference);
|
||||
}
|
||||
}
|
||||
|
||||
export function isEqualityOperatorKind(kind: SyntaxKind): kind is EqualityOperator {
|
||||
switch (kind) {
|
||||
case SyntaxKind.EqualsEqualsEqualsToken:
|
||||
case SyntaxKind.EqualsEqualsToken:
|
||||
case SyntaxKind.ExclamationEqualsEqualsToken:
|
||||
case SyntaxKind.ExclamationEqualsToken:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function isStringLiteralOrTemplate(node: Node): node is StringLiteralLike | TemplateExpression | TaggedTemplateExpression {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.TemplateExpression:
|
||||
case SyntaxKind.TaggedTemplateExpression:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function hasIndexSignature(type: Type): boolean {
|
||||
return !!type.getStringIndexType() || !!type.getNumberIndexType();
|
||||
}
|
||||
|
||||
export function getSwitchedType(caseClause: CaseClause, checker: TypeChecker): Type | undefined {
|
||||
return checker.getTypeAtLocation(caseClause.parent.parent.expression);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace project {
|
||||
program?: ts.Program;
|
||||
compilerOptions?: ts.CompilerOptions;
|
||||
errors: ReadonlyArray<ts.Diagnostic>;
|
||||
sourceMapData?: ReadonlyArray<ts.SourceMapData>;
|
||||
sourceMapData?: ReadonlyArray<ts.SourceMapEmitResult>;
|
||||
}
|
||||
|
||||
interface BatchCompileProjectTestCaseResult extends CompileProjectFilesResult {
|
||||
@@ -310,18 +310,16 @@ namespace project {
|
||||
const program = ts.createProgram(getInputFiles(), compilerOptions, compilerHost);
|
||||
const errors = ts.getPreEmitDiagnostics(program);
|
||||
|
||||
const emitResult = program.emit();
|
||||
ts.addRange(errors, emitResult.diagnostics);
|
||||
const sourceMapData = emitResult.sourceMaps;
|
||||
const { sourceMaps: sourceMapData, diagnostics: emitDiagnostics } = program.emit();
|
||||
|
||||
// Clean up source map data that will be used in baselining
|
||||
if (sourceMapData) {
|
||||
for (const data of sourceMapData) {
|
||||
for (let j = 0; j < data.sourceMapSources.length; j++) {
|
||||
data.sourceMapSources[j] = this.cleanProjectUrl(data.sourceMapSources[j]);
|
||||
}
|
||||
data.jsSourceMappingURL = this.cleanProjectUrl(data.jsSourceMappingURL);
|
||||
data.sourceMapSourceRoot = this.cleanProjectUrl(data.sourceMapSourceRoot);
|
||||
data.sourceMap = {
|
||||
...data.sourceMap,
|
||||
sources: data.sourceMap.sources.map(source => this.cleanProjectUrl(source)),
|
||||
sourceRoot: data.sourceMap.sourceRoot && this.cleanProjectUrl(data.sourceMap.sourceRoot)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,7 +327,7 @@ namespace project {
|
||||
configFileSourceFiles,
|
||||
moduleKind,
|
||||
program,
|
||||
errors,
|
||||
errors: ts.concatenate(errors, emitDiagnostics),
|
||||
sourceMapData
|
||||
};
|
||||
}
|
||||
@@ -427,6 +425,7 @@ namespace project {
|
||||
skipDefaultLibCheck: false,
|
||||
moduleResolution: ts.ModuleResolutionKind.Classic,
|
||||
module: moduleKind,
|
||||
newLine: ts.NewLineKind.CarriageReturnLineFeed,
|
||||
mapRoot: testCase.resolveMapRoot && testCase.mapRoot
|
||||
? vpath.resolve(vfs.srcFolder, testCase.mapRoot)
|
||||
: testCase.mapRoot,
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
"unittests/matchFiles.ts",
|
||||
"unittests/moduleResolution.ts",
|
||||
"unittests/organizeImports.ts",
|
||||
"unittests/parsePseudoBigInt.ts",
|
||||
"unittests/paths.ts",
|
||||
"unittests/printer.ts",
|
||||
"unittests/programMissingFiles.ts",
|
||||
@@ -75,6 +76,7 @@
|
||||
"unittests/reuseProgramStructure.ts",
|
||||
"unittests/session.ts",
|
||||
"unittests/semver.ts",
|
||||
"unittests/showConfig.ts",
|
||||
"unittests/symbolWalker.ts",
|
||||
"unittests/telemetry.ts",
|
||||
"unittests/textChanges.ts",
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace ts {
|
||||
assertParseResult(["--lib", "es5,invalidOption", "0.ts"],
|
||||
{
|
||||
errors: [{
|
||||
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl'.",
|
||||
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
|
||||
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
|
||||
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
|
||||
file: undefined,
|
||||
@@ -259,7 +259,7 @@ namespace ts {
|
||||
assertParseResult(["--lib", "es5,", "es7", "0.ts"],
|
||||
{
|
||||
errors: [{
|
||||
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl'.",
|
||||
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
|
||||
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
|
||||
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
|
||||
file: undefined,
|
||||
@@ -278,7 +278,7 @@ namespace ts {
|
||||
assertParseResult(["--lib", "es5, ", "es7", "0.ts"],
|
||||
{
|
||||
errors: [{
|
||||
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl'.",
|
||||
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
|
||||
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
|
||||
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
|
||||
file: undefined,
|
||||
|
||||
@@ -295,7 +295,7 @@ namespace ts {
|
||||
file: undefined,
|
||||
start: 0,
|
||||
length: 0,
|
||||
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl'.",
|
||||
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
|
||||
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
|
||||
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
|
||||
}]
|
||||
@@ -326,7 +326,7 @@ namespace ts {
|
||||
file: undefined,
|
||||
start: 0,
|
||||
length: 0,
|
||||
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl'.",
|
||||
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
|
||||
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
|
||||
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
|
||||
}]
|
||||
@@ -357,7 +357,7 @@ namespace ts {
|
||||
file: undefined,
|
||||
start: 0,
|
||||
length: 0,
|
||||
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl'.",
|
||||
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
|
||||
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
|
||||
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
|
||||
}]
|
||||
@@ -388,7 +388,7 @@ namespace ts {
|
||||
file: undefined,
|
||||
start: 0,
|
||||
length: 0,
|
||||
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl'.",
|
||||
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
|
||||
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
|
||||
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
|
||||
}]
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace ts {
|
||||
writeFile: (fileName, text) => outputs.set(fileName, text),
|
||||
};
|
||||
|
||||
const program = createProgram(arrayFrom(fileMap.keys()), options, host);
|
||||
const program = createProgram(arrayFrom(fileMap.keys()), { newLine: NewLineKind.LineFeed, ...options }, host);
|
||||
program.emit(/*targetSourceFile*/ undefined, host.writeFile, /*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ false, customTransformers);
|
||||
let content = "";
|
||||
for (const [file, text] of arrayFrom(outputs.entries())) {
|
||||
|
||||
@@ -107,7 +107,7 @@ namespace ts {
|
||||
};
|
||||
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromRange(selectionRange));
|
||||
assert.equal(rangeToExtract.errors, undefined, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText);
|
||||
const infos = refactor.extractSymbol.getAvailableActions(context)!;
|
||||
const infos = refactor.extractSymbol.getAvailableActions(context);
|
||||
const actions = find(infos, info => info.description === description.message)!.actions;
|
||||
|
||||
const data: string[] = [];
|
||||
@@ -169,7 +169,7 @@ namespace ts {
|
||||
};
|
||||
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromRange(selectionRange));
|
||||
assert.isUndefined(rangeToExtract.errors, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText);
|
||||
const infos = refactor.extractSymbol.getAvailableActions(context)!;
|
||||
const infos = refactor.extractSymbol.getAvailableActions(context);
|
||||
assert.isUndefined(find(infos, info => info.description === description.message));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -757,6 +757,9 @@ import b = require("./moduleB");
|
||||
],
|
||||
"somefolder/*": [
|
||||
"someanotherfolder/*"
|
||||
],
|
||||
"/rooted/*": [
|
||||
"generated/*"
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -773,6 +776,7 @@ import b = require("./moduleB");
|
||||
"/root/folder1/file2/index.d.ts",
|
||||
// then first attempt on 'generated/*' was successful
|
||||
]);
|
||||
check("/rooted/folder1/file2", file2, []);
|
||||
check("folder2/file3", file3, [
|
||||
// first try '*'
|
||||
"/root/folder2/file3.ts",
|
||||
@@ -900,6 +904,9 @@ import b = require("./moduleB");
|
||||
],
|
||||
"somefolder/*": [
|
||||
"someanotherfolder/*"
|
||||
],
|
||||
"/rooted/*": [
|
||||
"generated/*"
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -911,6 +918,7 @@ import b = require("./moduleB");
|
||||
"/root/folder1/file2.d.ts",
|
||||
// success when using 'generated/*'
|
||||
]);
|
||||
check("/rooted/folder1/file2", file2, []);
|
||||
check("folder1/file3", file3, [
|
||||
// first try '*'
|
||||
"/root/folder1/file3.ts",
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
namespace ts {
|
||||
describe("BigInt literal base conversions", () => {
|
||||
describe("parsePseudoBigInt", () => {
|
||||
const testNumbers: number[] = [];
|
||||
for (let i = 0; i < 1e3; i++) testNumbers.push(i);
|
||||
for (let bits = 0; bits <= 52; bits++) {
|
||||
testNumbers.push(2 ** bits, 2 ** bits - 1);
|
||||
}
|
||||
it("can strip base-10 strings", () => {
|
||||
for (const testNumber of testNumbers) {
|
||||
for (let leadingZeros = 0; leadingZeros < 10; leadingZeros++) {
|
||||
assert.equal(
|
||||
parsePseudoBigInt("0".repeat(leadingZeros) + testNumber + "n"),
|
||||
String(testNumber)
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
it("can parse binary literals", () => {
|
||||
for (const testNumber of testNumbers) {
|
||||
for (let leadingZeros = 0; leadingZeros < 10; leadingZeros++) {
|
||||
const binary = "0".repeat(leadingZeros) + testNumber.toString(2) + "n";
|
||||
for (const prefix of ["0b", "0B"]) {
|
||||
assert.equal(parsePseudoBigInt(prefix + binary), String(testNumber));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
it("can parse octal literals", () => {
|
||||
for (const testNumber of testNumbers) {
|
||||
for (let leadingZeros = 0; leadingZeros < 10; leadingZeros++) {
|
||||
const octal = "0".repeat(leadingZeros) + testNumber.toString(8) + "n";
|
||||
for (const prefix of ["0o", "0O"]) {
|
||||
assert.equal(parsePseudoBigInt(prefix + octal), String(testNumber));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
it("can parse hex literals", () => {
|
||||
for (const testNumber of testNumbers) {
|
||||
for (let leadingZeros = 0; leadingZeros < 10; leadingZeros++) {
|
||||
const hex = "0".repeat(leadingZeros) + testNumber.toString(16) + "n";
|
||||
for (const prefix of ["0x", "0X"]) {
|
||||
for (const hexCase of [hex.toLowerCase(), hex.toUpperCase()]) {
|
||||
assert.equal(parsePseudoBigInt(prefix + hexCase), String(testNumber));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
it("can parse large literals", () => {
|
||||
assert.equal(
|
||||
parsePseudoBigInt("123456789012345678901234567890n"),
|
||||
"123456789012345678901234567890"
|
||||
);
|
||||
assert.equal(
|
||||
parsePseudoBigInt("0b1100011101110100100001111111101101100001101110011111000001110111001001110001111110000101011010010n"),
|
||||
"123456789012345678901234567890"
|
||||
);
|
||||
assert.equal(
|
||||
parsePseudoBigInt("0o143564417755415637016711617605322n"),
|
||||
"123456789012345678901234567890"
|
||||
);
|
||||
assert.equal(
|
||||
parsePseudoBigInt("0x18ee90ff6c373e0ee4e3f0ad2n"),
|
||||
"123456789012345678901234567890"
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -147,7 +147,10 @@ namespace ts {
|
||||
},
|
||||
"/reference": {
|
||||
files: { "/secondary/b.ts": moduleImporting("../primary/a") },
|
||||
references: ["../primary"]
|
||||
references: ["../primary"],
|
||||
config: {
|
||||
files: ["b.ts"]
|
||||
}
|
||||
}
|
||||
};
|
||||
testProjectReferences(spec, "/reference/tsconfig.json", program => {
|
||||
@@ -156,6 +159,26 @@ namespace ts {
|
||||
});
|
||||
});
|
||||
|
||||
it("does not error when the referenced project doesn't have composite:true if its a container project", () => {
|
||||
const spec: TestSpecification = {
|
||||
"/primary": {
|
||||
files: { "/primary/a.ts": emptyModule },
|
||||
references: [],
|
||||
options: {
|
||||
composite: false
|
||||
}
|
||||
},
|
||||
"/reference": {
|
||||
files: { "/secondary/b.ts": moduleImporting("../primary/a") },
|
||||
references: ["../primary"],
|
||||
}
|
||||
};
|
||||
testProjectReferences(spec, "/reference/tsconfig.json", program => {
|
||||
const errs = program.getOptionsDiagnostics();
|
||||
assertNoErrors("Reports an error about 'composite' not being set", errs);
|
||||
});
|
||||
});
|
||||
|
||||
it("errors when the file list is not exhaustive", () => {
|
||||
const spec: TestSpecification = {
|
||||
"/primary": {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace ts {
|
||||
describe("showTSConfig", () => {
|
||||
function showTSConfigCorrectly(name: string, commandLinesArgs: string[]) {
|
||||
describe(name, () => {
|
||||
const commandLine = parseCommandLine(commandLinesArgs);
|
||||
const initResult = convertToTSConfig(commandLine, `/${name}/tsconfig.json`, { getCurrentDirectory() { return `/${name}`; }, useCaseSensitiveFileNames: true });
|
||||
const outputFileName = `showConfig/${name.replace(/[^a-z0-9\-. ]/ig, "")}/tsconfig.json`;
|
||||
|
||||
it(`Correct output for ${outputFileName}`, () => {
|
||||
// tslint:disable-next-line:no-null-keyword
|
||||
Harness.Baseline.runBaseline(outputFileName, JSON.stringify(initResult, null, 4) + "\n");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
showTSConfigCorrectly("Default initialized TSConfig", ["--showConfig"]);
|
||||
|
||||
showTSConfigCorrectly("Show TSConfig with files options", ["--showConfig", "file0.st", "file1.ts", "file2.ts"]);
|
||||
|
||||
showTSConfigCorrectly("Show TSConfig with boolean value compiler options", ["--showConfig", "--noUnusedLocals"]);
|
||||
|
||||
showTSConfigCorrectly("Show TSConfig with enum value compiler options", ["--showConfig", "--target", "es5", "--jsx", "react"]);
|
||||
|
||||
showTSConfigCorrectly("Show TSConfig with list compiler options", ["--showConfig", "--types", "jquery,mocha"]);
|
||||
|
||||
showTSConfigCorrectly("Show TSConfig with list compiler options with enum value", ["--showConfig", "--lib", "es5,es2015.core"]);
|
||||
|
||||
showTSConfigCorrectly("Show TSConfig with incorrect compiler option", ["--showConfig", "--someNonExistOption"]);
|
||||
|
||||
showTSConfigCorrectly("Show TSConfig with incorrect compiler option value", ["--showConfig", "--lib", "nonExistLib,es5,es2015.promise"]);
|
||||
|
||||
showTSConfigCorrectly("Show TSConfig with advanced options", ["--showConfig", "--declaration", "--declarationDir", "lib", "--skipLibCheck", "--noErrorTruncation"]);
|
||||
});
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
namespace ts.tscWatch {
|
||||
export import libFile = TestFSWithWatch.libFile;
|
||||
function createSolutionBuilder(system: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
|
||||
import projectsLocation = TestFSWithWatch.tsbuildProjectsLocation;
|
||||
import getFilePathInProject = TestFSWithWatch.getTsBuildProjectFilePath;
|
||||
import getFileFromProject = TestFSWithWatch.getTsBuildProjectFile;
|
||||
export function createSolutionBuilder(system: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
|
||||
const host = createSolutionBuilderWithWatchHost(system);
|
||||
return ts.createSolutionBuilder(host, rootNames, defaultOptions || { watch: true });
|
||||
}
|
||||
@@ -13,7 +16,6 @@ namespace ts.tscWatch {
|
||||
}
|
||||
|
||||
describe("tsbuild-watch program updates", () => {
|
||||
const projectsLocation = "/user/username/projects";
|
||||
const project = "sample1";
|
||||
const enum SubProject {
|
||||
core = "core",
|
||||
@@ -24,23 +26,10 @@ namespace ts.tscWatch {
|
||||
type ReadonlyFile = Readonly<File>;
|
||||
/** [tsconfig, index] | [tsconfig, index, anotherModule, someDecl] */
|
||||
type SubProjectFiles = [ReadonlyFile, ReadonlyFile] | [ReadonlyFile, ReadonlyFile, ReadonlyFile, ReadonlyFile];
|
||||
const root = Harness.IO.getWorkspaceRoot();
|
||||
|
||||
function getProjectPath(project: string) {
|
||||
return `${projectsLocation}/${project}`;
|
||||
}
|
||||
|
||||
function getFilePathInProject(project: string, file: string) {
|
||||
return `${projectsLocation}/${project}/${file}`;
|
||||
}
|
||||
|
||||
function getFileFromProject(project: string, file: string): File {
|
||||
return {
|
||||
path: getFilePathInProject(project, file),
|
||||
content: Harness.IO.readFile(`${root}/tests/projects/${project}/${file}`)!
|
||||
};
|
||||
}
|
||||
|
||||
function projectPath(subProject: SubProject) {
|
||||
return getFilePathInProject(project, subProject);
|
||||
}
|
||||
|
||||
@@ -34,8 +34,10 @@ namespace ts.tscWatch {
|
||||
return () => watch.getCurrentProgram().getProgram();
|
||||
}
|
||||
|
||||
function createWatchOfFilesAndCompilerOptions(rootFiles: string[], host: WatchedSystem, options: CompilerOptions = {}) {
|
||||
const watch = createWatchProgram(createWatchCompilerHostOfFilesAndCompilerOptions(rootFiles, options, host));
|
||||
function createWatchOfFilesAndCompilerOptions(rootFiles: string[], host: WatchedSystem, options: CompilerOptions = {}, maxNumberOfFilesToIterateForInvalidation?: number) {
|
||||
const compilerHost = createWatchCompilerHostOfFilesAndCompilerOptions(rootFiles, options, host);
|
||||
compilerHost.maxNumberOfFilesToIterateForInvalidation = maxNumberOfFilesToIterateForInvalidation;
|
||||
const watch = createWatchProgram(compilerHost);
|
||||
return () => watch.getCurrentProgram().getProgram();
|
||||
}
|
||||
|
||||
@@ -1072,7 +1074,10 @@ namespace ts.tscWatch {
|
||||
const host = createWatchedSystem([file1, configFile, libFile]);
|
||||
const watch = createWatchOfConfigFile(configFile.path, host);
|
||||
|
||||
checkProgramActualFiles(watch(), [libFile.path]);
|
||||
checkProgramActualFiles(watch(), emptyArray);
|
||||
checkOutputErrorsInitial(host, [
|
||||
"error TS18003: No inputs were found in config file '/a/b/tsconfig.json'. Specified 'include' paths were '[\"app/*\",\"test/**/*\",\"something\"]' and 'exclude' paths were '[]'.\n"
|
||||
]);
|
||||
});
|
||||
|
||||
it("non-existing directories listed in config file input array should be able to handle @types if input file list is empty", () => {
|
||||
@@ -1098,7 +1103,10 @@ namespace ts.tscWatch {
|
||||
const host = createWatchedSystem([f, config, t1, t2], { currentDirectory: getDirectoryPath(f.path) });
|
||||
const watch = createWatchOfConfigFile(config.path, host);
|
||||
|
||||
checkProgramActualFiles(watch(), [t1.path, t2.path]);
|
||||
checkProgramActualFiles(watch(), emptyArray);
|
||||
checkOutputErrorsInitial(host, [
|
||||
"tsconfig.json(1,24): error TS18002: The 'files' list in config file '/a/tsconfig.json' is empty.\n"
|
||||
]);
|
||||
});
|
||||
|
||||
it("should support files without extensions", () => {
|
||||
@@ -1290,7 +1298,7 @@ export default test;`;
|
||||
]);
|
||||
changeParameterType("y", "string", [
|
||||
getDiagnosticOfFileFromProgram(watch(), aFile.path, aFile.content.indexOf("5"), 1, Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1, "5", "string"),
|
||||
getDiagnosticOfFileFromProgram(watch(), bFile.path, bFile.content.indexOf("y /"), 1, Diagnostics.The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type)
|
||||
getDiagnosticOfFileFromProgram(watch(), bFile.path, bFile.content.indexOf("y /"), 1, Diagnostics.The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type)
|
||||
]);
|
||||
|
||||
function changeParameterType(parameterName: string, toType: string, expectedErrors: ReadonlyArray<Diagnostic>) {
|
||||
@@ -1464,6 +1472,98 @@ foo().hello`
|
||||
checkProgramActualFiles(watch(), [aFile.path, libFile.path]);
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
});
|
||||
|
||||
describe("updates errors when file transitively exported file changes", () => {
|
||||
const projectLocation = "/user/username/projects/myproject";
|
||||
const config: File = {
|
||||
path: `${projectLocation}/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
files: ["app.ts"],
|
||||
compilerOptions: { baseUrl: "." }
|
||||
})
|
||||
};
|
||||
const app: File = {
|
||||
path: `${projectLocation}/app.ts`,
|
||||
content: `import { Data } from "lib2/public";
|
||||
export class App {
|
||||
public constructor() {
|
||||
new Data().test();
|
||||
}
|
||||
}`
|
||||
};
|
||||
const lib2Public: File = {
|
||||
path: `${projectLocation}/lib2/public.ts`,
|
||||
content: `export * from "./data";`
|
||||
};
|
||||
const lib2Data: File = {
|
||||
path: `${projectLocation}/lib2/data.ts`,
|
||||
content: `import { ITest } from "lib1/public";
|
||||
export class Data {
|
||||
public test() {
|
||||
const result: ITest = {
|
||||
title: "title"
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}`
|
||||
};
|
||||
const lib1Public: File = {
|
||||
path: `${projectLocation}/lib1/public.ts`,
|
||||
content: `export * from "./tools/public";`
|
||||
};
|
||||
const lib1ToolsPublic: File = {
|
||||
path: `${projectLocation}/lib1/tools/public.ts`,
|
||||
content: `export * from "./tools.interface";`
|
||||
};
|
||||
const lib1ToolsInterface: File = {
|
||||
path: `${projectLocation}/lib1/tools/tools.interface.ts`,
|
||||
content: `export interface ITest {
|
||||
title: string;
|
||||
}`
|
||||
};
|
||||
|
||||
function verifyTransitiveExports(filesWithoutConfig: ReadonlyArray<File>) {
|
||||
const files = [config, ...filesWithoutConfig];
|
||||
const host = createWatchedSystem(files, { currentDirectory: projectLocation });
|
||||
const watch = createWatchOfConfigFile(config.path, host);
|
||||
checkProgramActualFiles(watch(), filesWithoutConfig.map(f => f.path));
|
||||
checkOutputErrorsInitial(host, emptyArray);
|
||||
|
||||
host.writeFile(lib1ToolsInterface.path, lib1ToolsInterface.content.replace("title", "title2"));
|
||||
host.checkTimeoutQueueLengthAndRun(1);
|
||||
checkProgramActualFiles(watch(), filesWithoutConfig.map(f => f.path));
|
||||
checkOutputErrorsIncremental(host, [
|
||||
"lib2/data.ts(5,13): error TS2322: Type '{ title: string; }' is not assignable to type 'ITest'.\n Object literal may only specify known properties, but 'title' does not exist in type 'ITest'. Did you mean to write 'title2'?\n"
|
||||
]);
|
||||
|
||||
}
|
||||
it("when there are no circular import and exports", () => {
|
||||
verifyTransitiveExports([libFile, app, lib2Public, lib2Data, lib1Public, lib1ToolsPublic, lib1ToolsInterface]);
|
||||
});
|
||||
|
||||
it("when there are circular import and exports", () => {
|
||||
const lib2Data: File = {
|
||||
path: `${projectLocation}/lib2/data.ts`,
|
||||
content: `import { ITest } from "lib1/public"; import { Data2 } from "./data2";
|
||||
export class Data {
|
||||
public dat?: Data2; public test() {
|
||||
const result: ITest = {
|
||||
title: "title"
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}`
|
||||
};
|
||||
const lib2Data2: File = {
|
||||
path: `${projectLocation}/lib2/data2.ts`,
|
||||
content: `import { Data } from "./data";
|
||||
export class Data2 {
|
||||
public dat?: Data;
|
||||
}`
|
||||
};
|
||||
verifyTransitiveExports([libFile, app, lib2Public, lib2Data, lib2Data2, lib1Public, lib1ToolsPublic, lib1ToolsInterface]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsc-watch emit with outFile or out setting", () => {
|
||||
@@ -2467,6 +2567,46 @@ declare module "fs" {
|
||||
checkProgramActualFiles(watch(), [file.path, libFile.path, `${currentDirectory}/node_modules/@types/qqq/index.d.ts`]);
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
});
|
||||
|
||||
describe("ignores files/folder changes in node_modules that start with '.'", () => {
|
||||
const projectPath = "/user/username/projects/project";
|
||||
const npmCacheFile: File = {
|
||||
path: `${projectPath}/node_modules/.cache/babel-loader/89c02171edab901b9926470ba6d5677e.ts`,
|
||||
content: JSON.stringify({ something: 10 })
|
||||
};
|
||||
const file1: File = {
|
||||
path: `${projectPath}/test.ts`,
|
||||
content: `import { x } from "somemodule";`
|
||||
};
|
||||
const file2: File = {
|
||||
path: `${projectPath}/node_modules/somemodule/index.d.ts`,
|
||||
content: `export const x = 10;`
|
||||
};
|
||||
const files = [libFile, file1, file2];
|
||||
const expectedFiles = files.map(f => f.path);
|
||||
it("when watching node_modules in inferred project for failed lookup", () => {
|
||||
const host = createWatchedSystem(files);
|
||||
const watch = createWatchOfFilesAndCompilerOptions([file1.path], host, {}, /*maxNumberOfFilesToIterateForInvalidation*/ 1);
|
||||
checkProgramActualFiles(watch(), expectedFiles);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
|
||||
host.ensureFileOrFolder(npmCacheFile);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
});
|
||||
it("when watching node_modules as part of wild card directories in config project", () => {
|
||||
const config: File = {
|
||||
path: `${projectPath}/tsconfig.json`,
|
||||
content: "{}"
|
||||
};
|
||||
const host = createWatchedSystem(files.concat(config));
|
||||
const watch = createWatchOfConfigFile(config.path, host);
|
||||
checkProgramActualFiles(watch(), expectedFiles);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
|
||||
host.ensureFileOrFolder(npmCacheFile);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsc-watch with when module emit is specified as node", () => {
|
||||
|
||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user