Merge branch 'main' into o-no-inode

This commit is contained in:
Jake Bailey
2023-09-27 12:49:13 -07:00
committed by GitHub
851 changed files with 96688 additions and 10817 deletions
+1 -1
View File
@@ -4,4 +4,4 @@
"include": ["src/**", "built/local/**"],
"exclude": ["**/node_modules/**"],
"mergeAsync": true
}
}
+3 -2
View File
@@ -18,9 +18,10 @@
}
},
"extensions": [
"dbaeumer.vscode-eslint"
"dbaeumer.vscode-eslint",
"dprint.dprint"
]
}
},
"remoteUser": "node"
}
}
+4 -2
View File
@@ -49,8 +49,10 @@
"**/*.generated.*",
"scripts/*.d.*"
],
// Note: if adding new languages, make sure settings.template.json is updated too.
"plugins": [
"https://plugins.dprint.dev/typescript-0.86.1.wasm",
"https://plugins.dprint.dev/prettier-0.27.0.json@3557a62b4507c55a47d8cde0683195b14d13c41dda66d0f0b0e111aed107e2fe"
"https://plugins.dprint.dev/typescript-0.87.1.wasm",
"https://plugins.dprint.dev/prettier-0.27.0.json@3557a62b4507c55a47d8cde0683195b14d13c41dda66d0f0b0e111aed107e2fe",
"https://plugins.dprint.dev/json-0.17.4.wasm"
]
}
+8 -4
View File
@@ -16,7 +16,10 @@
"plugin:@typescript-eslint/stylistic"
],
"plugins": [
"@typescript-eslint", "no-null", "eslint-plugin-local", "simple-import-sort"
"@typescript-eslint",
"no-null",
"eslint-plugin-local",
"simple-import-sort"
],
"ignorePatterns": [
"**/node_modules/**",
@@ -113,7 +116,7 @@
"local/only-arrow-functions": [
"error",
{
"allowNamedFunctions": true ,
"allowNamedFunctions": true,
"allowDeclarations": true
}
],
@@ -133,7 +136,7 @@
"overrides": [
// By default, the ESLint CLI only looks at .js files. But, it will also look at
// any files which are referenced in an override config. Most users of typescript-eslint
// get this behavior by default by extending a recommended typescript-eslint config, which
// get this behavior by default by extending a recommended typescript-eslint config, which
// just so happens to override some core ESLint rules. We don't extend from any config, so
// explicitly reference TS files here so the CLI picks them up.
//
@@ -146,7 +149,8 @@
"files": ["*.mjs", "*.mts"],
"rules": {
// These globals don't exist outside of CJS files.
"no-restricted-globals": ["error",
"no-restricted-globals": [
"error",
{ "name": "__filename" },
{ "name": "__dirname" },
{ "name": "require" },
+5 -5
View File
@@ -1,6 +1,6 @@
{
"project": "../../src/tsconfig.json",
"source": "../../package.json",
"package": "../../package.json",
"out": "../../typescript.lsif"
}
"project": "../../src/tsconfig.json",
"source": "../../package.json",
"package": "../../package.json",
"out": "../../typescript.lsif"
}
+8 -11
View File
@@ -76,15 +76,12 @@ jobs:
check-latest: true
- run: npm ci
# TODO: The cache fails when copied between GHA runners. See:
# https://github.com/dprint/dprint/issues/734
# https://github.com/dprint/dprint/issues/735
# - uses: actions/cache@v3
# with:
# path: ~/.cache/dprint
# key: ${{ runner.os }}-dprint-${{ hashFiles('package-lock.json', '.dprint.jsonc') }}
# restore-keys: |
# ${{ runner.os }}-dprint-
- uses: actions/cache@v3
with:
path: ~/.cache/dprint
key: ${{ runner.os }}-dprint-${{ hashFiles('package-lock.json', '.dprint.jsonc') }}
restore-keys: |
${{ runner.os }}-dprint-
- name: Check formatting
run: npx dprint check
@@ -100,8 +97,8 @@ jobs:
check-latest: true
- run: npm ci
- name: Adding playwright
run: npm install --no-save --no-package-lock playwright
- name: Installing browsers
run: npx playwright install --with-deps
- name: Validate the browser can import TypeScript
run: npx hereby test-browser-integration
+3 -3
View File
@@ -21,15 +21,15 @@ jobs:
contents: write
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 5
- uses: actions/setup-node@v3
- run: |
npm --version
# corepack enable npm
npm install -g $(jq -r '.packageManager' < package.json)
npm --version
- uses: actions/checkout@v3
with:
fetch-depth: 5
- run: |
git checkout -b ${{ github.event.client_payload.branch_name }}
sed -i -e 's/"version": ".*"/"version": "${{ github.event.client_payload.package_version }}"/g' package.json
@@ -30,8 +30,8 @@ jobs:
run: |
npm ci
npm test
- name: Adding playwright
run: npm install --no-save --no-package-lock playwright
- name: Installing browsers
run: npx playwright install --with-deps
- name: Validate the browser can import TypeScript
run: npx hereby test-browser-integration
- name: LKG, clean, and pack
+1 -1
View File
@@ -21,10 +21,10 @@ jobs:
contents: write
steps:
- uses: actions/setup-node@v3
- uses: actions/checkout@v3
with:
ref: ${{ github.event.client_payload.branch_name }}
- uses: actions/setup-node@v3
- run: |
npm --version
# corepack enable npm
+1 -1
View File
@@ -8,4 +8,4 @@
"unwantedRecommendations": [
"ms-vscode.vscode-typescript-tslint-plugin"
]
}
}
+49 -49
View File
@@ -1,4 +1,4 @@
/*
/*
Copy this file into '.vscode/launch.json' or merge its
contents into your existing configurations.
@@ -13,52 +13,52 @@
*/
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Mocha Tests (currently opened test)",
"runtimeArgs": ["--nolazy"],
"program": "${workspaceRoot}/node_modules/mocha/bin/_mocha",
"args": [
"-u",
"bdd",
"--no-timeouts",
"--colors",
"built/local/run.js",
"-f",
// You can change this to be the name of a specific test file (without the file extension)
// to consistently launch the same test
"${fileBasenameNoExtension}",
"--skip-percent",
"0"
],
"env": {
"NODE_ENV": "testing"
},
"outFiles": [
"${workspaceFolder}/built/**/*.js",
"${workspaceFolder}/built/**/*.mjs",
"${workspaceFolder}/built/**/*.cjs",
"!**/node_modules/**"
],
"sourceMaps": true,
"smartStep": true,
"preLaunchTask": "npm: build:tests",
"console": "integratedTerminal",
"customDescriptionGenerator": "'__tsDebuggerDisplay' in this ? this.__tsDebuggerDisplay(defaultValue) : defaultValue"
},
{
// See: https://github.com/microsoft/TypeScript/wiki/Debugging-Language-Service-in-VS-Code
"type": "node",
"request": "attach",
"name": "Attach to VS Code TS Server via Port",
"processId": "${command:PickProcess}",
"customDescriptionGenerator": "'__tsDebuggerDisplay' in this ? this.__tsDebuggerDisplay(defaultValue) : defaultValue"
}
]
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Mocha Tests (currently opened test)",
"runtimeArgs": ["--nolazy"],
"program": "${workspaceRoot}/node_modules/mocha/bin/_mocha",
"args": [
"-u",
"bdd",
"--no-timeouts",
"--colors",
"built/local/run.js",
"-f",
// You can change this to be the name of a specific test file (without the file extension)
// to consistently launch the same test
"${fileBasenameNoExtension}",
"--skip-percent",
"0"
],
"env": {
"NODE_ENV": "testing"
},
"outFiles": [
"${workspaceFolder}/built/**/*.js",
"${workspaceFolder}/built/**/*.mjs",
"${workspaceFolder}/built/**/*.cjs",
"!**/node_modules/**"
],
"sourceMaps": true,
"smartStep": true,
"preLaunchTask": "npm: build:tests",
"console": "integratedTerminal",
"customDescriptionGenerator": "'__tsDebuggerDisplay' in this ? this.__tsDebuggerDisplay(defaultValue) : defaultValue"
},
{
// See: https://github.com/microsoft/TypeScript/wiki/Debugging-Language-Service-in-VS-Code
"type": "node",
"request": "attach",
"name": "Attach to VS Code TS Server via Port",
"processId": "${command:PickProcess}",
"customDescriptionGenerator": "'__tsDebuggerDisplay' in this ? this.__tsDebuggerDisplay(defaultValue) : defaultValue"
}
]
}
+7 -5
View File
@@ -4,11 +4,13 @@
// To use the locally built compiler, after 'npm run build':
// "typescript.tsdk": "built/local"
// Enables dprint formatting on all supported files. Setting this as the
// default for all file types is safe as dprint will just ignore any file
// it doesn't support or has explicitly excluded in .dprint.jsonc.
"editor.defaultFormatter": "dprint.dprint",
"editor.formatOnSave": true,
// Enables dprint formatting on all supported files. We explicitly list
// languages here to ensure that these are more specific than those in a
// user's settings.json so take precedence.
"[typescript][typescriptreact][javascript][javascriptreact][json][jsonc][yaml][github-actions-workflow]": {
"editor.defaultFormatter": "dprint.dprint",
"editor.formatOnSave": true
},
// To ignore commits listed in .git-blame-ignore-revs in GitLens:
"gitlens.advanced.blame.customArguments": [
+1 -1
View File
@@ -49,6 +49,6 @@
"problemMatcher": [
"$tsc"
]
},
}
]
}
+7 -7
View File
@@ -1,18 +1,18 @@
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.5 BLOCK -->
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.9 BLOCK -->
## Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin).
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below.
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below.
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report).
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp).
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
@@ -28,7 +28,7 @@ Please include the requested information listed below (as much as you can provid
This information will help us triage your report more quickly.
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs.
## Preferred Languages
@@ -36,6 +36,6 @@ We prefer all communications to be in English.
## Policy
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd).
<!-- END MICROSOFT SECURITY.MD BLOCK -->
+491 -421
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -59,7 +59,7 @@
"chalk": "^4.1.2",
"chokidar": "^3.5.3",
"diff": "^5.1.0",
"dprint": "^0.40.2",
"dprint": "^0.41.0",
"esbuild": "^0.19.0",
"eslint": "^8.22.0",
"eslint-formatter-autolinkable-stylish": "^1.2.0",
@@ -75,6 +75,7 @@
"mocha-fivemat-progress-reporter": "^0.1.0",
"ms": "^2.1.3",
"node-fetch": "^3.2.10",
"playwright": "^1.38.0",
"source-map-support": "^0.5.21",
"tslib": "^2.5.0",
"typescript": "^5.0.2",
+1 -9
View File
@@ -5,15 +5,7 @@ import {
import {
join,
} from "path";
let playwright;
try {
// @ts-ignore-error
playwright = await import("playwright");
}
catch (error) {
throw new Error("Playwright is expected to be installed manually before running this script");
}
import playwright from "playwright";
// Turning this on will leave the Chromium browser open, giving you the
// chance to open up the web inspector.
+8 -2
View File
@@ -72,12 +72,18 @@ export class ExecError extends Error {
}
/**
* Reads JSON data with optional comments using the LKG TypeScript compiler
* Reads JSON data with optional comments
* @param {string} jsonPath
*/
export function readJson(jsonPath) {
const jsonText = fs.readFileSync(jsonPath, "utf8");
return JSONC.parse(jsonText);
/** @type {JSONC.ParseError[]} */
const errors = [];
const result = JSONC.parse(jsonText, errors);
if (errors.length) {
throw new Error(`Error parsing ${jsonPath}`);
}
return result;
}
/**
+1 -1
View File
@@ -1,2 +1,2 @@
#!/bin/sh
npm run npx hereby -- generate-diagnostics
./node_modules/.bin/hereby generate-diagnostics || true
+4
View File
@@ -0,0 +1,4 @@
#!/bin/sh
if git diff --name-only --cached --relative | xargs --no-run-if-empty ./node_modules/.bin/dprint fmt; then
git diff --name-only --cached --relative | xargs --no-run-if-empty git add
fi
+1
View File
@@ -11,6 +11,7 @@ const __dirname = path.dirname(__filename);
const hooks = [
"post-checkout",
"pre-commit",
];
hooks.forEach(hook => {
+2 -1
View File
@@ -23,6 +23,7 @@
},
"include": [
"**/*.mjs", "**/*.cjs"
"**/*.mjs",
"**/*.cjs"
]
}
+2 -1
View File
@@ -6,7 +6,8 @@
},
"rules": {
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"no-restricted-globals": ["error",
"no-restricted-globals": [
"error",
{ "name": "setTimeout" },
{ "name": "clearTimeout" },
{ "name": "setInterval" },
+4 -2
View File
@@ -136,6 +136,7 @@ import {
isBlock,
isBlockOrCatchScoped,
IsBlockScopedContainer,
isBooleanLiteral,
isCallExpression,
isClassStaticBlockDeclaration,
isConditionalTypeNode,
@@ -1279,7 +1280,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
case SyntaxKind.EqualsEqualsEqualsToken:
case SyntaxKind.ExclamationEqualsEqualsToken:
return isNarrowableOperand(expr.left) || isNarrowableOperand(expr.right) ||
isNarrowingTypeofOperands(expr.right, expr.left) || isNarrowingTypeofOperands(expr.left, expr.right);
isNarrowingTypeofOperands(expr.right, expr.left) || isNarrowingTypeofOperands(expr.left, expr.right) ||
(isBooleanLiteral(expr.right) && isNarrowingExpression(expr.left) || isBooleanLiteral(expr.left) && isNarrowingExpression(expr.right));
case SyntaxKind.InstanceOfKeyword:
return isNarrowableOperand(expr.left);
case SyntaxKind.InKeyword:
@@ -1680,7 +1682,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
function bindCaseBlock(node: CaseBlock): void {
const clauses = node.clauses;
const isNarrowingSwitch = isNarrowingExpression(node.parent.expression);
const isNarrowingSwitch = node.parent.expression.kind === SyntaxKind.TrueKeyword || isNarrowingExpression(node.parent.expression);
let fallthroughFlow = unreachableFlow;
for (let i = 0; i < clauses.length; i++) {
const clauseStart = i;
+8 -10
View File
@@ -238,17 +238,15 @@ export namespace BuilderState {
}
// Handle type reference directives
if (sourceFile.resolvedTypeReferenceDirectiveNames) {
sourceFile.resolvedTypeReferenceDirectiveNames.forEach(({ resolvedTypeReferenceDirective }) => {
if (!resolvedTypeReferenceDirective) {
return;
}
program.forEachResolvedTypeReferenceDirective(({ resolvedTypeReferenceDirective }) => {
if (!resolvedTypeReferenceDirective) {
return;
}
const fileName = resolvedTypeReferenceDirective.resolvedFileName!; // TODO: GH#18217
const typeFilePath = getReferencedFileFromFileName(program, fileName, sourceFileDirectory, getCanonicalFileName);
addReferencedFile(typeFilePath);
});
}
const fileName = resolvedTypeReferenceDirective.resolvedFileName!; // TODO: GH#18217
const typeFilePath = getReferencedFileFromFileName(program, fileName, sourceFileDirectory, getCanonicalFileName);
addReferencedFile(typeFilePath);
}, sourceFile);
// Add module augmentation as references
if (sourceFile.moduleAugmentations.length) {
+313 -166
View File
File diff suppressed because it is too large Load Diff
+16 -3
View File
@@ -553,6 +553,7 @@ export const moduleOptionDeclaration: CommandLineOptionOfCustomType = {
node16: ModuleKind.Node16,
nodenext: ModuleKind.NodeNext,
})),
affectsSourceFile: true,
affectsModuleResolution: true,
affectsEmit: true,
affectsBuildInfo: true,
@@ -647,7 +648,8 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
{
name: "allowJs",
type: "boolean",
affectsModuleResolution: true,
allowJsFlag: true,
affectsBuildInfo: true,
showInSimplifiedHelpView: true,
category: Diagnostics.JavaScript_Support,
description: Diagnostics.Allow_JavaScript_files_to_be_a_part_of_your_program_Use_the_checkJS_option_to_get_errors_from_these_files,
@@ -657,6 +659,8 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
name: "checkJs",
type: "boolean",
affectsModuleResolution: true,
affectsSemanticDiagnostics: true,
affectsBuildInfo: true,
showInSimplifiedHelpView: true,
category: Diagnostics.JavaScript_Support,
description: Diagnostics.Enable_error_reporting_in_type_checked_JavaScript_files,
@@ -669,6 +673,10 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
affectsEmit: true,
affectsBuildInfo: true,
affectsModuleResolution: true,
// The checker emits an error when it sees JSX but this option is not set in compilerOptions.
// This is effectively a semantic error, so mark this option as affecting semantic diagnostics
// so we know to refresh errors when this option is changed.
affectsSemanticDiagnostics: true,
paramType: Diagnostics.KIND,
showInSimplifiedHelpView: true,
category: Diagnostics.Language_and_Environment,
@@ -987,6 +995,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
bundler: ModuleResolutionKind.Bundler,
})),
deprecatedKeys: new Set(["node"]),
affectsSourceFile: true,
affectsModuleResolution: true,
paramType: Diagnostics.STRATEGY,
category: Diagnostics.Modules,
@@ -1533,6 +1542,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
legacy: ModuleDetectionKind.Legacy,
force: ModuleDetectionKind.Force,
})),
affectsSourceFile: true,
affectsModuleResolution: true,
description: Diagnostics.Control_what_method_is_used_to_detect_module_format_JS_files,
category: Diagnostics.Language_and_Environment,
@@ -1564,7 +1574,7 @@ export const affectsDeclarationPathOptionDeclarations: readonly CommandLineOptio
export const moduleResolutionOptionDeclarations: readonly CommandLineOption[] = optionDeclarations.filter(option => !!option.affectsModuleResolution);
/** @internal */
export const sourceFileAffectingCompilerOptions: readonly CommandLineOption[] = optionDeclarations.filter(option => !!option.affectsSourceFile || !!option.affectsModuleResolution || !!option.affectsBindDiagnostics);
export const sourceFileAffectingCompilerOptions: readonly CommandLineOption[] = optionDeclarations.filter(option => !!option.affectsSourceFile || !!option.affectsBindDiagnostics);
/** @internal */
export const optionsAffectingProgramStructure: readonly CommandLineOption[] = optionDeclarations.filter(option => !!option.affectsProgramStructure);
@@ -3849,7 +3859,10 @@ function hasFileWithHigherPriorityExtension(file: string, literalFiles: Map<stri
return false;
}
for (const ext of extensionGroup) {
if (fileExtensionIs(file, ext)) {
// d.ts files match with .ts extension and with case sensitive sorting the file order for same files with ts tsx and dts extension is
// d.ts, .ts, .tsx in that order so we need to handle tsx and dts of same same name case here and in remove files with same extensions
// So dont match .d.ts files with .ts extension
if (fileExtensionIs(file, ext) && (ext !== Extension.Ts || !fileExtensionIs(file, Extension.Dts))) {
return false;
}
const higherPriorityPath = keyMapper(changeExtension(file, ext));
+2 -2
View File
@@ -633,12 +633,12 @@ export namespace Debug {
// for use with vscode-js-debug's new customDescriptionGenerator in launch.json
__tsDebuggerDisplay: {
value(this: Type) {
const typeHeader = this.flags & TypeFlags.Nullable ? "NullableType" :
const typeHeader = this.flags & TypeFlags.Intrinsic ? `IntrinsicType ${(this as IntrinsicType).intrinsicName}${(this as IntrinsicType).debugIntrinsicName ? ` (${(this as IntrinsicType).debugIntrinsicName})` : ""}` :
this.flags & TypeFlags.Nullable ? "NullableType" :
this.flags & TypeFlags.StringOrNumberLiteral ? `LiteralType ${JSON.stringify((this as LiteralType).value)}` :
this.flags & TypeFlags.BigIntLiteral ? `LiteralType ${(this as BigIntLiteralType).value.negative ? "-" : ""}${(this as BigIntLiteralType).value.base10Value}n` :
this.flags & TypeFlags.UniqueESSymbol ? "UniqueESSymbolType" :
this.flags & TypeFlags.Enum ? "EnumType" :
this.flags & TypeFlags.Intrinsic ? `IntrinsicType ${(this as IntrinsicType).intrinsicName}` :
this.flags & TypeFlags.Union ? "UnionType" :
this.flags & TypeFlags.Intersection ? "IntersectionType" :
this.flags & TypeFlags.Index ? "IndexType" :
+43 -19
View File
@@ -1472,7 +1472,7 @@
"category": "Message",
"code": 1449
},
"Dynamic imports can only accept a module specifier and an optional assertion as arguments": {
"Dynamic imports can only accept a module specifier and an optional set of attributes as arguments": {
"category": "Message",
"code": 1450
},
@@ -1480,10 +1480,6 @@
"category": "Error",
"code": 1451
},
"'resolution-mode' assertions are only supported when `moduleResolution` is `node16` or `nodenext`.": {
"category": "Error",
"code": 1452
},
"`resolution-mode` should be either `require` or `import`.": {
"category": "Error",
"code": 1453
@@ -1520,6 +1516,14 @@
"category": "Message",
"code": 1461
},
"'resolution-mode' is the only valid key for type import attributes.": {
"category": "Error",
"code": 1463
},
"Type import attributes should have exactly one key - 'resolution-mode' - with value 'import' or 'require'.": {
"category": "Error",
"code": 1464
},
"The 'import.meta' meta-property is not allowed in files which will build into CommonJS output.": {
"category": "Error",
@@ -1625,6 +1629,10 @@
"category": "Error",
"code": 1495
},
"Identifier, string literal, or number literal expected.": {
"category": "Error",
"code": 1496
},
"The types of '{0}' are incompatible between these types.": {
"category": "Error",
@@ -3579,6 +3587,10 @@
"category": "Error",
"code": 2822
},
"Import attributes are only supported when the '--module' option is set to 'esnext' or 'nodenext'.": {
"category": "Error",
"code": 2823
},
"Cannot find namespace '{0}'. Did you mean '{1}'?": {
"category": "Error",
"code": 2833
@@ -3591,7 +3603,7 @@
"category": "Error",
"code": 2835
},
"Import assertions are not allowed on statements that transpile to CommonJS 'require' calls.": {
"Import assertions are not allowed on statements that compile to CommonJS 'require' calls.": {
"category": "Error",
"code": 2836
},
@@ -3611,10 +3623,6 @@
"category": "Error",
"code": 2840
},
"The type of this expression cannot be named without a 'resolution-mode' assertion, which is an unstable feature. Use nightly TypeScript to silence this error. Try updating with 'npm install -D typescript@next'.": {
"category": "Error",
"code": 2841
},
"'{0}' is an unused renaming of '{1}'. Did you intend to use it as a type annotation?": {
"category": "Error",
"code": 2842
@@ -3663,6 +3671,26 @@
"category": "Error",
"code": 2854
},
"Class field '{0}' defined by the parent class is not accessible in the child class via super.": {
"category": "Error",
"code": 2855
},
"Import attributes are not allowed on statements that compile to CommonJS 'require' calls.": {
"category": "Error",
"code": 2856
},
"Import attributes cannot be used with type-only imports or exports.": {
"category": "Error",
"code": 2857
},
"Import attribute values must be string literal expressions.": {
"category": "Error",
"code": 2858
},
"Excessive complexity comparing types '{0}' and '{1}'.": {
"category": "Error",
"code": 2859
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
@@ -4096,10 +4124,6 @@
"category": "Error",
"code": 4124
},
"'resolution-mode' assertions are unstable. Use nightly TypeScript to silence this error. Try updating with 'npm install -D typescript@next'.": {
"category": "Error",
"code": 4125
},
"The current host does not support the '{0}' option.": {
"category": "Error",
@@ -5294,7 +5318,7 @@
"category": "Error",
"code": 6258
},
"Found 1 error in {0}": {
"Found 1 error in {0}": {
"category": "Message",
"code": 6259
},
@@ -6276,9 +6300,9 @@
"category": "Message",
"code": 6930
},
"List of file name suffixes to search when resolving a module." : {
"category": "Error",
"code": 6931
"List of file name suffixes to search when resolving a module.": {
"category": "Error",
"code": 6931
},
"Variable '{0}' implicitly has an '{1}' type.": {
@@ -7564,7 +7588,7 @@
"category": "Message",
"code": 95153
},
"Can only convert string concatenation": {
"Can only convert string concatenations and string literals": {
"category": "Message",
"code": 95154
},
+37 -19
View File
@@ -7,8 +7,6 @@ import {
ArrayTypeNode,
ArrowFunction,
AsExpression,
AssertClause,
AssertEntry,
AwaitExpression,
base64encode,
BigIntLiteral,
@@ -191,6 +189,8 @@ import {
Identifier,
idText,
IfStatement,
ImportAttribute,
ImportAttributes,
ImportClause,
ImportDeclaration,
ImportEqualsDeclaration,
@@ -927,6 +927,7 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi
inlineSourceMap: compilerOptions.inlineSourceMap,
extendedDiagnostics: compilerOptions.extendedDiagnostics,
onlyPrintJsDocStyle: true,
omitBraceSourceMapPositions: true,
writeBundleFileInfo: !!bundleBuildInfo,
recordInternalSection: !!bundleBuildInfo,
relativeToBuildInfo,
@@ -1391,6 +1392,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
} = handlers;
var extendedDiagnostics = !!printerOptions.extendedDiagnostics;
var omitBraceSourcePositions = !!printerOptions.omitBraceSourceMapPositions;
var newLine = getNewLineCharacter(printerOptions);
var moduleKind = getEmitModuleKind(printerOptions);
var bundledHelpers = new Map<string, boolean>();
@@ -2053,10 +2055,10 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
return emitNamedExports(node as NamedExports);
case SyntaxKind.ExportSpecifier:
return emitExportSpecifier(node as ExportSpecifier);
case SyntaxKind.AssertClause:
return emitAssertClause(node as AssertClause);
case SyntaxKind.AssertEntry:
return emitAssertEntry(node as AssertEntry);
case SyntaxKind.ImportAttributes:
return emitImportAttributes(node as ImportAttributes);
case SyntaxKind.ImportAttribute:
return emitImportAttribute(node as ImportAttribute);
case SyntaxKind.MissingDeclaration:
return;
@@ -2946,16 +2948,16 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
writeKeyword("import");
writePunctuation("(");
emit(node.argument);
if (node.assertions) {
if (node.attributes) {
writePunctuation(",");
writeSpace();
writePunctuation("{");
writeSpace();
writeKeyword("assert");
writeKeyword(node.attributes.token === SyntaxKind.AssertKeyword ? "assert" : "with");
writePunctuation(":");
writeSpace();
const elements = node.assertions.assertClause.elements;
emitList(node.assertions.assertClause, elements, ListFormat.ImportClauseEntries);
const elements = node.attributes.elements;
emitList(node.attributes, elements, ListFormat.ImportAttributes);
writeSpace();
writePunctuation("}");
}
@@ -3578,7 +3580,18 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
decreaseIndent();
}
}
pos = writeTokenText(token, writer, pos);
// We don't emit source positions for most tokens as it tends to be quite noisy, however
// we need to emit source positions for open and close braces so that tools like istanbul
// can map branches for code coverage. However, we still omit brace source positions when
// the output is a declaration file.
if (!omitBraceSourcePositions && (token === SyntaxKind.OpenBraceToken || token === SyntaxKind.CloseBraceToken)) {
pos = writeToken(token, pos, writer, contextNode);
}
else {
pos = writeTokenText(token, writer, pos);
}
if (isSimilarNode && contextNode.end !== pos) {
const isJsxExprContext = contextNode.kind === SyntaxKind.JsxExpression;
emitTrailingCommentsOfPosition(pos, /*prefixSpace*/ !isJsxExprContext, /*forceNoNewline*/ isJsxExprContext);
@@ -3990,8 +4003,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
writeSpace();
}
emitExpression(node.moduleSpecifier);
if (node.assertClause) {
emitWithLeadingSpace(node.assertClause);
if (node.attributes) {
emitWithLeadingSpace(node.attributes);
}
writeTrailingSemicolon();
}
@@ -4065,20 +4078,20 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
writeSpace();
emitExpression(node.moduleSpecifier);
}
if (node.assertClause) {
emitWithLeadingSpace(node.assertClause);
if (node.attributes) {
emitWithLeadingSpace(node.attributes);
}
writeTrailingSemicolon();
}
function emitAssertClause(node: AssertClause) {
emitTokenWithComment(SyntaxKind.AssertKeyword, node.pos, writeKeyword, node);
function emitImportAttributes(node: ImportAttributes) {
emitTokenWithComment(node.token, node.pos, writeKeyword, node);
writeSpace();
const elements = node.elements;
emitList(node, elements, ListFormat.ImportClauseEntries);
emitList(node, elements, ListFormat.ImportAttributes);
}
function emitAssertEntry(node: AssertEntry) {
function emitImportAttribute(node: ImportAttribute) {
emit(node.name);
writePunctuation(":");
writeSpace();
@@ -5121,6 +5134,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
shouldDecreaseIndentAfterEmit = true;
}
if (shouldEmitInterveningComments && format & ListFormat.DelimitersMask && !positionIsSynthesized(child.pos)) {
const commentRange = getCommentRange(child);
emitTrailingCommentsOfPosition(commentRange.pos, /*prefixSpace*/ !!(format & ListFormat.SpaceBetweenSiblings), /*forceNoNewline*/ true);
}
writeLine(separatingLineTerminatorCount);
shouldEmitInterveningComments = false;
}
+65 -18
View File
@@ -137,6 +137,9 @@ import {
IfStatement,
ImmediatelyInvokedArrowFunction,
ImmediatelyInvokedFunctionExpression,
ImportAttribute,
ImportAttributeName,
ImportAttributes,
ImportClause,
ImportDeclaration,
ImportEqualsDeclaration,
@@ -791,6 +794,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
updateAssertEntry,
createImportTypeAssertionContainer,
updateImportTypeAssertionContainer,
createImportAttributes,
updateImportAttributes,
createImportAttribute,
updateImportAttribute,
createNamespaceImport,
updateNamespaceImport,
createNamespaceExport,
@@ -2643,14 +2650,17 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
// @api
function createImportTypeNode(
argument: TypeNode,
assertions?: ImportTypeAssertionContainer,
attributes?: ImportAttributes,
qualifier?: EntityName,
typeArguments?: readonly TypeNode[],
isTypeOf = false,
): ImportTypeNode {
const node = createBaseNode<ImportTypeNode>(SyntaxKind.ImportType);
node.argument = argument;
node.assertions = assertions;
node.attributes = attributes;
if (node.assertions && node.assertions.assertClause && node.attributes) {
(node.assertions as Mutable<ImportTypeAssertionContainer>).assertClause = node.attributes;
}
node.qualifier = qualifier;
node.typeArguments = typeArguments && parenthesizerRules().parenthesizeTypeArguments(typeArguments);
node.isTypeOf = isTypeOf;
@@ -2662,17 +2672,17 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
function updateImportTypeNode(
node: ImportTypeNode,
argument: TypeNode,
assertions: ImportTypeAssertionContainer | undefined,
attributes: ImportAttributes | undefined,
qualifier: EntityName | undefined,
typeArguments: readonly TypeNode[] | undefined,
isTypeOf: boolean = node.isTypeOf,
): ImportTypeNode {
return node.argument !== argument
|| node.assertions !== assertions
|| node.attributes !== attributes
|| node.qualifier !== qualifier
|| node.typeArguments !== typeArguments
|| node.isTypeOf !== isTypeOf
? update(createImportTypeNode(argument, assertions, qualifier, typeArguments, isTypeOf), node)
? update(createImportTypeNode(argument, attributes, qualifier, typeArguments, isTypeOf), node)
: node;
}
@@ -4696,13 +4706,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
modifiers: readonly ModifierLike[] | undefined,
importClause: ImportClause | undefined,
moduleSpecifier: Expression,
assertClause: AssertClause | undefined,
attributes: ImportAttributes | undefined,
): ImportDeclaration {
const node = createBaseNode<ImportDeclaration>(SyntaxKind.ImportDeclaration);
node.modifiers = asNodeArray(modifiers);
node.importClause = importClause;
node.moduleSpecifier = moduleSpecifier;
node.assertClause = assertClause;
node.attributes = node.assertClause = attributes;
node.transformFlags |= propagateChildFlags(node.importClause) |
propagateChildFlags(node.moduleSpecifier);
node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context
@@ -4717,13 +4727,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
modifiers: readonly ModifierLike[] | undefined,
importClause: ImportClause | undefined,
moduleSpecifier: Expression,
assertClause: AssertClause | undefined,
attributes: ImportAttributes | undefined,
) {
return node.modifiers !== modifiers
|| node.importClause !== importClause
|| node.moduleSpecifier !== moduleSpecifier
|| node.assertClause !== assertClause
? update(createImportDeclaration(modifiers, importClause, moduleSpecifier, assertClause), node)
|| node.attributes !== attributes
? update(createImportDeclaration(modifiers, importClause, moduleSpecifier, attributes), node)
: node;
}
@@ -4756,6 +4766,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
const node = createBaseNode<AssertClause>(SyntaxKind.AssertClause);
node.elements = createNodeArray(elements);
node.multiLine = multiLine;
node.token = SyntaxKind.AssertKeyword;
node.transformFlags |= TransformFlags.ContainsESNext;
return node;
}
@@ -4801,6 +4812,43 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
: node;
}
// @api
function createImportAttributes(elements: readonly ImportAttribute[], multiLine?: boolean): ImportAttributes;
function createImportAttributes(elements: readonly ImportAttribute[], multiLine?: boolean, token?: ImportAttributes["token"]): ImportAttributes;
function createImportAttributes(elements: readonly ImportAttribute[], multiLine?: boolean, token?: ImportAttributes["token"]): ImportAttributes {
const node = createBaseNode<ImportAttributes>(SyntaxKind.ImportAttributes);
node.token = token ?? SyntaxKind.WithKeyword;
node.elements = createNodeArray(elements);
node.multiLine = multiLine;
node.transformFlags |= TransformFlags.ContainsESNext;
return node;
}
// @api
function updateImportAttributes(node: ImportAttributes, elements: readonly ImportAttribute[], multiLine?: boolean): ImportAttributes {
return node.elements !== elements
|| node.multiLine !== multiLine
? update(createImportAttributes(elements, multiLine, node.token), node)
: node;
}
// @api
function createImportAttribute(name: ImportAttributeName, value: Expression): ImportAttribute {
const node = createBaseNode<ImportAttribute>(SyntaxKind.ImportAttribute);
node.name = name;
node.value = value;
node.transformFlags |= TransformFlags.ContainsESNext;
return node;
}
// @api
function updateImportAttribute(node: ImportAttribute, name: ImportAttributeName, value: Expression): ImportAttribute {
return node.name !== name
|| node.value !== value
? update(createImportAttribute(name, value), node)
: node;
}
// @api
function createNamespaceImport(name: Identifier): NamespaceImport {
const node = createBaseDeclaration<NamespaceImport>(SyntaxKind.NamespaceImport);
@@ -4908,14 +4956,14 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
isTypeOnly: boolean,
exportClause: NamedExportBindings | undefined,
moduleSpecifier?: Expression,
assertClause?: AssertClause,
attributes?: ImportAttributes,
) {
const node = createBaseDeclaration<ExportDeclaration>(SyntaxKind.ExportDeclaration);
node.modifiers = asNodeArray(modifiers);
node.isTypeOnly = isTypeOnly;
node.exportClause = exportClause;
node.moduleSpecifier = moduleSpecifier;
node.assertClause = assertClause;
node.attributes = node.assertClause = attributes;
node.transformFlags |= propagateChildrenFlags(node.modifiers) |
propagateChildFlags(node.exportClause) |
propagateChildFlags(node.moduleSpecifier);
@@ -4932,14 +4980,14 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
isTypeOnly: boolean,
exportClause: NamedExportBindings | undefined,
moduleSpecifier: Expression | undefined,
assertClause: AssertClause | undefined,
attributes: ImportAttributes | undefined,
) {
return node.modifiers !== modifiers
|| node.isTypeOnly !== isTypeOnly
|| node.exportClause !== exportClause
|| node.moduleSpecifier !== moduleSpecifier
|| node.assertClause !== assertClause
? finishUpdateExportDeclaration(createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause), node)
|| node.attributes !== attributes
? finishUpdateExportDeclaration(createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, attributes), node)
: node;
}
@@ -6026,7 +6074,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
node.imports = undefined!;
node.moduleAugmentations = undefined!;
node.ambientModuleNames = undefined!;
node.resolvedModules = undefined;
node.classifiableNames = undefined;
node.impliedNodeFormat = undefined;
return node;
@@ -7084,9 +7131,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
isEnumDeclaration(node) ? updateEnumDeclaration(node, modifierArray, node.name, node.members) :
isModuleDeclaration(node) ? updateModuleDeclaration(node, modifierArray, node.name, node.body) :
isImportEqualsDeclaration(node) ? updateImportEqualsDeclaration(node, modifierArray, node.isTypeOnly, node.name, node.moduleReference) :
isImportDeclaration(node) ? updateImportDeclaration(node, modifierArray, node.importClause, node.moduleSpecifier, node.assertClause) :
isImportDeclaration(node) ? updateImportDeclaration(node, modifierArray, node.importClause, node.moduleSpecifier, node.attributes) :
isExportAssignment(node) ? updateExportAssignment(node, modifierArray, node.expression) :
isExportDeclaration(node) ? updateExportDeclaration(node, modifierArray, node.isTypeOnly, node.exportClause, node.moduleSpecifier, node.assertClause) :
isExportDeclaration(node) ? updateExportDeclaration(node, modifierArray, node.isTypeOnly, node.exportClause, node.moduleSpecifier, node.attributes) :
Debug.assertNever(node);
}
+12
View File
@@ -67,6 +67,8 @@ import {
HeritageClause,
Identifier,
IfStatement,
ImportAttribute,
ImportAttributes,
ImportClause,
ImportDeclaration,
ImportEqualsDeclaration,
@@ -847,14 +849,24 @@ export function isImportTypeAssertionContainer(node: Node): node is ImportTypeAs
return node.kind === SyntaxKind.ImportTypeAssertionContainer;
}
/** @deprecated */
export function isAssertClause(node: Node): node is AssertClause {
return node.kind === SyntaxKind.AssertClause;
}
/** @deprecated */
export function isAssertEntry(node: Node): node is AssertEntry {
return node.kind === SyntaxKind.AssertEntry;
}
export function isImportAttributes(node: Node): node is ImportAttributes {
return node.kind === SyntaxKind.ImportAttributes;
}
export function isImportAttribute(node: Node): node is ImportAttribute {
return node.kind === SyntaxKind.ImportAttribute;
}
export function isNamespaceImport(node: Node): node is NamespaceImport {
return node.kind === SyntaxKind.NamespaceImport;
}
+1 -1
View File
@@ -754,7 +754,7 @@ export function createExternalHelpersImportDeclarationIfNeeded(nodeFactory: Node
/*modifiers*/ undefined,
nodeFactory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, namedBindings),
nodeFactory.createStringLiteral(externalHelpersModuleNameText),
/*assertClause*/ undefined,
/*attributes*/ undefined,
);
addInternalEmitFlags(externalHelpersImportDeclaration, InternalEmitFlags.NeverApplyImportHelper);
return externalHelpersImportDeclaration;
+76 -52
View File
@@ -91,14 +91,12 @@ import {
removeFileExtension,
removePrefix,
ResolutionMode,
ResolutionNameAndModeGetter,
ResolvedModuleWithFailedLookupLocations,
ResolvedProjectReference,
ResolvedTypeReferenceDirective,
ResolvedTypeReferenceDirectiveWithFailedLookupLocations,
some,
sort,
SourceFile,
startsWith,
supportedDeclarationExtensions,
supportedJSExtensionsFlat,
@@ -558,18 +556,21 @@ export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string
const failedLookupLocations: string[] = [];
const affectingLocations: string[] = [];
// Allow type reference directives to opt into `exports` resolution in any resolution mode
// when a `resolution-mode` override is present.
let features = getNodeResolutionFeatures(options);
// Unlike `import` statements, whose mode-calculating APIs are all guaranteed to return `undefined` if we're in an un-mode-ed module resolution
// setting, type references will return their target mode regardless of options because of how the parser works, so we guard against the mode being
// set in a non-modal module resolution setting here. Do note that our behavior is not particularly well defined when these mode-overriding imports
// are present in a non-modal project; while in theory we'd like to either ignore the mode or provide faithful modern resolution, depending on what we feel is best,
// in practice, not every cache has the options available to intelligently make the choice to ignore the mode request, and it's unclear how modern "faithful modern
// resolution" should be (`node16`? `nodenext`?). As such, witnessing a mode-overriding triple-slash reference in a non-modal module resolution
// context should _probably_ be an error - and that should likely be handled by the `Program` (which is what we do).
if (resolutionMode === ModuleKind.ESNext && (getEmitModuleResolutionKind(options) === ModuleResolutionKind.Node16 || getEmitModuleResolutionKind(options) === ModuleResolutionKind.NodeNext)) {
if (resolutionMode !== undefined) {
features |= NodeResolutionFeatures.AllFeatures;
}
const moduleResolution = getEmitModuleResolutionKind(options);
if (resolutionMode === ModuleKind.ESNext && (ModuleResolutionKind.Node16 <= moduleResolution && moduleResolution <= ModuleResolutionKind.NodeNext)) {
features |= NodeResolutionFeatures.EsmMode;
}
const conditions = features & NodeResolutionFeatures.Exports ? getConditions(options, !!(features & NodeResolutionFeatures.EsmMode)) : [];
// true: "import" / false: "require" / undefined: default based on settings
const useImportCondition = resolutionMode === ModuleKind.ESNext || (resolutionMode !== undefined ? false : undefined);
const conditions = (features & NodeResolutionFeatures.Exports)
? getConditions(options, useImportCondition)
: [];
const diagnostics: Diagnostic[] = [];
const moduleResolutionState: ModuleResolutionState = {
compilerOptions: options,
@@ -724,17 +725,33 @@ function getNodeResolutionFeatures(options: CompilerOptions) {
return features;
}
/** @internal */
/**
* @param overrideResolutionModeAttribute
* @internal
*/
export function getConditions(options: CompilerOptions, esmMode?: boolean) {
const moduleResolution = getEmitModuleResolutionKind(options);
if (esmMode === undefined) {
if (moduleResolution === ModuleResolutionKind.Bundler) {
// bundler always uses `import` unless explicitly overridden
esmMode ??= moduleResolution === ModuleResolutionKind.Bundler;
}
else if (moduleResolution === ModuleResolutionKind.Node10) {
// node10 does not support package.json imports/exports without
// an explicit resolution-mode override on a type-only import
// (indicated by `esmMode` being set)
return [];
}
}
// conditions are only used by the node16/nodenext/bundler resolvers - there's no priority order in the list,
// it's essentially a set (priority is determined by object insertion order in the object we look at).
const conditions = esmMode || getEmitModuleResolutionKind(options) === ModuleResolutionKind.Bundler
const conditions = esmMode
? ["import"]
: ["require"];
if (!options.noDtsResolution) {
conditions.push("types");
}
if (getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Bundler) {
if (moduleResolution !== ModuleResolutionKind.Bundler) {
conditions.push("node");
}
return concatenate(conditions, options.customConditions);
@@ -1091,22 +1108,6 @@ export function createModeAwareCache<T>(): ModeAwareCache<T> {
}
}
/** @internal */
export function zipToModeAwareCache<K, V>(
file: SourceFile,
keys: readonly K[],
values: readonly V[],
nameAndModeGetter: ResolutionNameAndModeGetter<K, SourceFile>,
): ModeAwareCache<V> {
Debug.assert(keys.length === values.length);
const map = createModeAwareCache<V>();
for (let i = 0; i < keys.length; ++i) {
const entry = keys[i];
map.set(nameAndModeGetter.getName(entry), nameAndModeGetter.getMode(entry, file), values[i]);
}
return map;
}
function getOriginalOrResolvedModuleFileName(result: ResolvedModuleWithFailedLookupLocations) {
return result.resolvedModule && (result.resolvedModule.originalPath || result.resolvedModule.resolvedFileName);
}
@@ -1411,13 +1412,13 @@ export function resolveModuleName(moduleName: string, containingFile: string, co
result = nodeNextModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference, resolutionMode);
break;
case ModuleResolutionKind.Node10:
result = nodeModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference);
result = nodeModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference, resolutionMode ? getConditions(compilerOptions, resolutionMode === ModuleKind.ESNext) : undefined);
break;
case ModuleResolutionKind.Classic:
result = classicNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference);
break;
case ModuleResolutionKind.Bundler:
result = bundlerModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference);
result = bundlerModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference, resolutionMode ? getConditions(compilerOptions, resolutionMode === ModuleKind.ESNext) : undefined);
break;
default:
return Debug.fail(`Unexpected moduleResolution: ${moduleResolution}`);
@@ -1699,7 +1700,7 @@ function nodeNextModuleNameResolver(moduleName: string, containingFile: string,
);
}
function nodeNextModuleNameResolverWorker(features: NodeResolutionFeatures, moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, resolutionMode?: ResolutionMode): ResolvedModuleWithFailedLookupLocations {
function nodeNextModuleNameResolverWorker(features: NodeResolutionFeatures, moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, resolutionMode?: ResolutionMode, conditions?: string[]): ResolvedModuleWithFailedLookupLocations {
const containingDirectory = getDirectoryPath(containingFile);
// es module file or cjs-like input file, use a variant of the legacy cjs resolver that supports the selected modern features
@@ -1708,7 +1709,7 @@ function nodeNextModuleNameResolverWorker(features: NodeResolutionFeatures, modu
if (getResolveJsonModule(compilerOptions)) {
extensions |= Extensions.Json;
}
return nodeModuleNameResolverWorker(features | esmMode, moduleName, containingDirectory, compilerOptions, host, cache, extensions, /*isConfigLookup*/ false, redirectedReference);
return nodeModuleNameResolverWorker(features | esmMode, moduleName, containingDirectory, compilerOptions, host, cache, extensions, /*isConfigLookup*/ false, redirectedReference, conditions);
}
function tryResolveJSModuleWorker(moduleName: string, initialDir: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
@@ -1722,21 +1723,24 @@ function tryResolveJSModuleWorker(moduleName: string, initialDir: string, host:
Extensions.JavaScript,
/*isConfigLookup*/ false,
/*redirectedReference*/ undefined,
/*conditions*/ undefined,
);
}
export function bundlerModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations {
export function bundlerModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations;
/** @internal */
export function bundlerModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, conditions?: string[]): ResolvedModuleWithFailedLookupLocations;
export function bundlerModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, conditions?: string[]): ResolvedModuleWithFailedLookupLocations {
const containingDirectory = getDirectoryPath(containingFile);
let extensions = compilerOptions.noDtsResolution ? Extensions.ImplementationFiles : Extensions.TypeScript | Extensions.JavaScript | Extensions.Declaration;
if (getResolveJsonModule(compilerOptions)) {
extensions |= Extensions.Json;
}
return nodeModuleNameResolverWorker(getNodeResolutionFeatures(compilerOptions), moduleName, containingDirectory, compilerOptions, host, cache, extensions, /*isConfigLookup*/ false, redirectedReference);
return nodeModuleNameResolverWorker(getNodeResolutionFeatures(compilerOptions), moduleName, containingDirectory, compilerOptions, host, cache, extensions, /*isConfigLookup*/ false, redirectedReference, conditions);
}
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations;
/** @internal */ export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, lookupConfig?: boolean): ResolvedModuleWithFailedLookupLocations; // eslint-disable-line @typescript-eslint/unified-signatures
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, isConfigLookup?: boolean): ResolvedModuleWithFailedLookupLocations {
/** @internal */ export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, conditions?: string[], lookupConfig?: boolean): ResolvedModuleWithFailedLookupLocations; // eslint-disable-line @typescript-eslint/unified-signatures
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, conditions?: string[], isConfigLookup?: boolean): ResolvedModuleWithFailedLookupLocations {
let extensions;
if (isConfigLookup) {
extensions = Extensions.Json;
@@ -1750,20 +1754,38 @@ export function nodeModuleNameResolver(moduleName: string, containingFile: strin
? Extensions.TypeScript | Extensions.JavaScript | Extensions.Declaration | Extensions.Json
: Extensions.TypeScript | Extensions.JavaScript | Extensions.Declaration;
}
return nodeModuleNameResolverWorker(NodeResolutionFeatures.None, moduleName, getDirectoryPath(containingFile), compilerOptions, host, cache, extensions, !!isConfigLookup, redirectedReference);
return nodeModuleNameResolverWorker(conditions ? NodeResolutionFeatures.AllFeatures : NodeResolutionFeatures.None, moduleName, getDirectoryPath(containingFile), compilerOptions, host, cache, extensions, !!isConfigLookup, redirectedReference, conditions);
}
/** @internal */
export function nodeNextJsonConfigResolver(moduleName: string, containingFile: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
return nodeModuleNameResolverWorker(NodeResolutionFeatures.NodeNextDefault, moduleName, getDirectoryPath(containingFile), { moduleResolution: ModuleResolutionKind.NodeNext }, host, /*cache*/ undefined, Extensions.Json, /*isConfigLookup*/ true, /*redirectedReference*/ undefined);
return nodeModuleNameResolverWorker(NodeResolutionFeatures.NodeNextDefault, moduleName, getDirectoryPath(containingFile), { moduleResolution: ModuleResolutionKind.NodeNext }, host, /*cache*/ undefined, Extensions.Json, /*isConfigLookup*/ true, /*redirectedReference*/ undefined, /*conditions*/ undefined);
}
function nodeModuleNameResolverWorker(features: NodeResolutionFeatures, moduleName: string, containingDirectory: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache: ModuleResolutionCache | undefined, extensions: Extensions, isConfigLookup: boolean, redirectedReference: ResolvedProjectReference | undefined): ResolvedModuleWithFailedLookupLocations {
function nodeModuleNameResolverWorker(
features: NodeResolutionFeatures,
moduleName: string,
containingDirectory: string,
compilerOptions: CompilerOptions,
host: ModuleResolutionHost,
cache: ModuleResolutionCache | undefined,
extensions: Extensions,
isConfigLookup: boolean,
redirectedReference: ResolvedProjectReference | undefined,
conditions: readonly string[] | undefined,
): ResolvedModuleWithFailedLookupLocations {
const traceEnabled = isTraceEnabled(compilerOptions, host);
const failedLookupLocations: string[] = [];
const affectingLocations: string[] = [];
const conditions = getConditions(compilerOptions, !!(features & NodeResolutionFeatures.EsmMode));
const moduleResolution = getEmitModuleResolutionKind(compilerOptions);
conditions ??= getConditions(
compilerOptions,
moduleResolution === ModuleResolutionKind.Bundler || moduleResolution === ModuleResolutionKind.Node10
? undefined
: !!(features & NodeResolutionFeatures.EsmMode),
);
const diagnostics: Diagnostic[] = [];
const state: ModuleResolutionState = {
@@ -1774,19 +1796,18 @@ function nodeModuleNameResolverWorker(features: NodeResolutionFeatures, moduleNa
affectingLocations,
packageJsonInfoCache: cache,
features,
conditions,
conditions: conditions ?? emptyArray,
requestContainingDirectory: containingDirectory,
reportDiagnostic: diag => void diagnostics.push(diag),
isConfigLookup,
candidateIsFromPackageJsonField: false,
};
if (traceEnabled && moduleResolutionSupportsPackageJsonExportsAndImports(getEmitModuleResolutionKind(compilerOptions))) {
trace(host, Diagnostics.Resolving_in_0_mode_with_conditions_1, features & NodeResolutionFeatures.EsmMode ? "ESM" : "CJS", conditions.map(c => `'${c}'`).join(", "));
if (traceEnabled && moduleResolutionSupportsPackageJsonExportsAndImports(moduleResolution)) {
trace(host, Diagnostics.Resolving_in_0_mode_with_conditions_1, features & NodeResolutionFeatures.EsmMode ? "ESM" : "CJS", state.conditions.map(c => `'${c}'`).join(", "));
}
let result;
if (getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node10) {
if (moduleResolution === ModuleResolutionKind.Node10) {
const priorityExtensions = extensions & (Extensions.TypeScript | Extensions.Declaration);
const secondaryExtensions = extensions & ~(Extensions.TypeScript | Extensions.Declaration);
result = priorityExtensions && tryResolve(priorityExtensions, state) ||
@@ -1807,7 +1828,7 @@ function nodeModuleNameResolverWorker(features: NodeResolutionFeatures, moduleNa
&& features & NodeResolutionFeatures.Exports
&& !isExternalModuleNameRelative(moduleName)
&& !extensionIsOk(Extensions.TypeScript | Extensions.Declaration, result.value.resolved.extension)
&& conditions.includes("import")
&& conditions?.includes("import")
) {
traceIfEnabled(state, Diagnostics.Resolution_of_non_relative_name_failed_trying_with_modern_Node_resolution_features_disabled_to_see_if_npm_library_needs_configuration_update);
const diagnosticState = {
@@ -1896,7 +1917,6 @@ function realPath(path: string, host: ModuleResolutionHost, traceEnabled: boolea
if (traceEnabled) {
trace(host, Diagnostics.Resolving_real_path_for_0_result_1, path, real);
}
Debug.assert(host.fileExists(real), `${path} linked to nonexistent file ${real}`);
return real;
}
@@ -2231,7 +2251,11 @@ function loadEntrypointsFromExportMap(
scope.packageDirectory,
extensionsToExtensionsArray(extensions),
/*excludes*/ undefined,
[changeAnyExtension(target.replace("*", "**/*"), getDeclarationEmitExtensionForPath(target))],
[
isDeclarationFileName(target)
? target.replace("*", "**/*")
: changeAnyExtension(target.replace("*", "**/*"), getDeclarationEmitExtensionForPath(target)),
],
).forEach(entry => {
entrypoints = appendIfUnique(entrypoints, {
path: entry,
@@ -2658,7 +2682,7 @@ function getLoadModuleFromTargetImportOrExport(extensions: Extensions, state: Mo
const combinedLookup = pattern ? target.replace(/\*/g, subpath) : target + subpath;
traceIfEnabled(state, Diagnostics.Using_0_subpath_1_with_target_2, "imports", key, combinedLookup);
traceIfEnabled(state, Diagnostics.Resolving_module_0_from_1, combinedLookup, scope.packageDirectory + "/");
const result = nodeModuleNameResolverWorker(state.features, combinedLookup, scope.packageDirectory + "/", state.compilerOptions, state.host, cache, extensions, /*isConfigLookup*/ false, redirectedReference);
const result = nodeModuleNameResolverWorker(state.features, combinedLookup, scope.packageDirectory + "/", state.compilerOptions, state.host, cache, extensions, /*isConfigLookup*/ false, redirectedReference, state.conditions);
return toSearchResult(
result.resolvedModule ? {
path: result.resolvedModule.resolvedFileName,
+86 -71
View File
@@ -9,8 +9,6 @@ import {
ArrayTypeNode,
ArrowFunction,
AsExpression,
AssertClause,
AssertEntry,
AssertionLevel,
AsteriskToken,
attachFileToDiagnostics,
@@ -117,6 +115,8 @@ import {
Identifier,
idText,
IfStatement,
ImportAttribute,
ImportAttributes,
ImportClause,
ImportDeclaration,
ImportEqualsDeclaration,
@@ -187,6 +187,7 @@ import {
JSDocOverloadTag,
JSDocOverrideTag,
JSDocParameterTag,
JSDocParsingMode,
JSDocPrivateTag,
JSDocPropertyLikeTag,
JSDocPropertyTag,
@@ -688,7 +689,7 @@ const forEachChildTable: ForEachChildTable = {
},
[SyntaxKind.ImportType]: function forEachChildInImportType<T>(node: ImportTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
return visitNode(cbNode, node.argument) ||
visitNode(cbNode, node.assertions) ||
visitNode(cbNode, node.attributes) ||
visitNode(cbNode, node.qualifier) ||
visitNodes(cbNode, cbNodes, node.typeArguments);
},
@@ -927,16 +928,16 @@ const forEachChildTable: ForEachChildTable = {
return visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, node.importClause) ||
visitNode(cbNode, node.moduleSpecifier) ||
visitNode(cbNode, node.assertClause);
visitNode(cbNode, node.attributes);
},
[SyntaxKind.ImportClause]: function forEachChildInImportClause<T>(node: ImportClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
return visitNode(cbNode, node.name) ||
visitNode(cbNode, node.namedBindings);
},
[SyntaxKind.AssertClause]: function forEachChildInAssertClause<T>(node: AssertClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
[SyntaxKind.ImportAttributes]: function forEachChildInImportAttributes<T>(node: ImportAttributes, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
return visitNodes(cbNode, cbNodes, node.elements);
},
[SyntaxKind.AssertEntry]: function forEachChildInAssertEntry<T>(node: AssertEntry, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
[SyntaxKind.ImportAttribute]: function forEachChildInImportAttribute<T>(node: ImportAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
return visitNode(cbNode, node.name) ||
visitNode(cbNode, node.value);
},
@@ -956,7 +957,7 @@ const forEachChildTable: ForEachChildTable = {
return visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, node.exportClause) ||
visitNode(cbNode, node.moduleSpecifier) ||
visitNode(cbNode, node.assertClause);
visitNode(cbNode, node.attributes);
},
[SyntaxKind.ImportSpecifier]: forEachChildInImportOrExportSpecifier,
[SyntaxKind.ExportSpecifier]: forEachChildInImportOrExportSpecifier,
@@ -1318,6 +1319,7 @@ export interface CreateSourceFileOptions {
setExternalModuleIndicator?: (file: SourceFile) => void;
/** @internal */ packageJsonLocations?: readonly string[];
/** @internal */ packageJsonScope?: PackageJsonInfo;
jsDocParsingMode?: JSDocParsingMode;
}
function setExternalModuleIndicator(sourceFile: SourceFile) {
@@ -1334,16 +1336,17 @@ export function createSourceFile(fileName: string, sourceText: string, languageV
languageVersion,
setExternalModuleIndicator: overrideSetExternalModuleIndicator,
impliedNodeFormat: format,
jsDocParsingMode,
} = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions : ({ languageVersion: languageVersionOrOptions } as CreateSourceFileOptions);
if (languageVersion === ScriptTarget.JSON) {
result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, ScriptKind.JSON, noop);
result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, ScriptKind.JSON, noop, jsDocParsingMode);
}
else {
const setIndicator = format === undefined ? overrideSetExternalModuleIndicator : (file: SourceFile) => {
file.impliedNodeFormat = format;
return (overrideSetExternalModuleIndicator || setExternalModuleIndicator)(file);
};
result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind, setIndicator);
result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind, setIndicator, jsDocParsingMode);
}
perfLogger?.logStopParseSourceFile();
@@ -1575,7 +1578,16 @@ namespace Parser {
var parseErrorBeforeNextFinishedNode = false;
/* eslint-enable no-var */
export function parseSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, syntaxCursor: IncrementalParser.SyntaxCursor | undefined, setParentNodes = false, scriptKind?: ScriptKind, setExternalModuleIndicatorOverride?: (file: SourceFile) => void): SourceFile {
export function parseSourceFile(
fileName: string,
sourceText: string,
languageVersion: ScriptTarget,
syntaxCursor: IncrementalParser.SyntaxCursor | undefined,
setParentNodes = false,
scriptKind?: ScriptKind,
setExternalModuleIndicatorOverride?: (file: SourceFile) => void,
jsDocParsingMode = JSDocParsingMode.ParseAll,
): SourceFile {
scriptKind = ensureScriptKind(fileName, scriptKind);
if (scriptKind === ScriptKind.JSON) {
const result = parseJsonText(fileName, sourceText, languageVersion, syntaxCursor, setParentNodes);
@@ -1589,9 +1601,9 @@ namespace Parser {
return result;
}
initializeState(fileName, sourceText, languageVersion, syntaxCursor, scriptKind);
initializeState(fileName, sourceText, languageVersion, syntaxCursor, scriptKind, jsDocParsingMode);
const result = parseSourceFileWorker(languageVersion, setParentNodes, scriptKind, setExternalModuleIndicatorOverride || setExternalModuleIndicator);
const result = parseSourceFileWorker(languageVersion, setParentNodes, scriptKind, setExternalModuleIndicatorOverride || setExternalModuleIndicator, jsDocParsingMode);
clearState();
@@ -1600,7 +1612,7 @@ namespace Parser {
export function parseIsolatedEntityName(content: string, languageVersion: ScriptTarget): EntityName | undefined {
// Choice of `isDeclarationFile` should be arbitrary
initializeState("", content, languageVersion, /*syntaxCursor*/ undefined, ScriptKind.JS);
initializeState("", content, languageVersion, /*syntaxCursor*/ undefined, ScriptKind.JS, JSDocParsingMode.ParseAll);
// Prime the scanner.
nextToken();
const entityName = parseEntityName(/*allowReservedWords*/ true);
@@ -1610,7 +1622,7 @@ namespace Parser {
}
export function parseJsonText(fileName: string, sourceText: string, languageVersion: ScriptTarget = ScriptTarget.ES2015, syntaxCursor?: IncrementalParser.SyntaxCursor, setParentNodes = false): JsonSourceFile {
initializeState(fileName, sourceText, languageVersion, syntaxCursor, ScriptKind.JSON);
initializeState(fileName, sourceText, languageVersion, syntaxCursor, ScriptKind.JSON, JSDocParsingMode.ParseAll);
sourceFlags = contextFlags;
// Prime the scanner.
@@ -1698,7 +1710,7 @@ namespace Parser {
return result;
}
function initializeState(_fileName: string, _sourceText: string, _languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, _scriptKind: ScriptKind) {
function initializeState(_fileName: string, _sourceText: string, _languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, _scriptKind: ScriptKind, _jsDocParsingMode: JSDocParsingMode) {
NodeConstructor = objectAllocator.getNodeConstructor();
TokenConstructor = objectAllocator.getTokenConstructor();
IdentifierConstructor = objectAllocator.getIdentifierConstructor();
@@ -1739,6 +1751,8 @@ namespace Parser {
scanner.setOnError(scanError);
scanner.setScriptTarget(languageVersion);
scanner.setLanguageVariant(languageVariant);
scanner.setScriptKind(scriptKind);
scanner.setJSDocParsingMode(_jsDocParsingMode);
}
function clearState() {
@@ -1746,6 +1760,8 @@ namespace Parser {
scanner.clearCommentDirectives();
scanner.setText("");
scanner.setOnError(undefined);
scanner.setScriptKind(ScriptKind.Unknown);
scanner.setJSDocParsingMode(JSDocParsingMode.ParseAll);
// Clear any data. We don't want to accidentally hold onto it for too long.
sourceText = undefined!;
@@ -1762,7 +1778,7 @@ namespace Parser {
topLevel = true;
}
function parseSourceFileWorker(languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind, setExternalModuleIndicator: (file: SourceFile) => void): SourceFile {
function parseSourceFileWorker(languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind, setExternalModuleIndicator: (file: SourceFile) => void, jsDocParsingMode: JSDocParsingMode): SourceFile {
const isDeclarationFile = isDeclarationFileName(fileName);
if (isDeclarationFile) {
contextFlags |= NodeFlags.Ambient;
@@ -1789,6 +1805,7 @@ namespace Parser {
sourceFile.identifierCount = identifierCount;
sourceFile.identifiers = identifiers;
sourceFile.parseDiagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile);
sourceFile.jsDocParsingMode = jsDocParsingMode;
if (jsDocDiagnostics) {
sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile);
}
@@ -2666,9 +2683,8 @@ namespace Parser {
token() === SyntaxKind.NumericLiteral;
}
function isAssertionKey(): boolean {
return tokenIsIdentifierOrKeyword(token()) ||
token() === SyntaxKind.StringLiteral;
function isImportAttributeName(): boolean {
return tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.StringLiteral;
}
function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName {
@@ -2830,8 +2846,8 @@ namespace Parser {
return isLiteralPropertyName();
case ParsingContext.ObjectBindingElements:
return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName();
case ParsingContext.AssertEntries:
return isAssertionKey();
case ParsingContext.ImportAttributes:
return isImportAttributeName();
case ParsingContext.HeritageClauseElement:
// If we see `{ ... }` then only consume it as an expression if it is followed by `,` or `{`
// That way we won't consume the body of a class in its heritage clause.
@@ -2962,7 +2978,7 @@ namespace Parser {
case ParsingContext.ObjectLiteralMembers:
case ParsingContext.ObjectBindingElements:
case ParsingContext.ImportOrExportSpecifiers:
case ParsingContext.AssertEntries:
case ParsingContext.ImportAttributes:
return token() === SyntaxKind.CloseBraceToken;
case ParsingContext.SwitchClauseStatements:
return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword;
@@ -3425,8 +3441,8 @@ namespace Parser {
return parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
case ParsingContext.JsxChildren:
return parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
case ParsingContext.AssertEntries:
return parseErrorAtCurrentToken(Diagnostics.Identifier_or_string_literal_expected); // AssertionKey.
case ParsingContext.ImportAttributes:
return parseErrorAtCurrentToken(Diagnostics.Identifier_or_string_literal_expected);
case ParsingContext.JSDocComment:
return parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
case ParsingContext.Count:
@@ -4495,26 +4511,6 @@ namespace Parser {
return token() === SyntaxKind.ImportKeyword;
}
function parseImportTypeAssertions(): ImportTypeAssertionContainer {
const pos = getNodePos();
const openBracePosition = scanner.getTokenStart();
parseExpected(SyntaxKind.OpenBraceToken);
const multiLine = scanner.hasPrecedingLineBreak();
parseExpected(SyntaxKind.AssertKeyword);
parseExpected(SyntaxKind.ColonToken);
const clause = parseAssertClause(/*skipAssertKeyword*/ true);
if (!parseExpected(SyntaxKind.CloseBraceToken)) {
const lastError = lastOrUndefined(parseDiagnostics);
if (lastError && lastError.code === Diagnostics._0_expected.code) {
addRelatedInfo(
lastError,
createDetachedDiagnostic(fileName, sourceText, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}"),
);
}
}
return finishNode(factory.createImportTypeAssertionContainer(clause, multiLine), pos);
}
function parseImportType(): ImportTypeNode {
sourceFlags |= NodeFlags.PossiblyContainsDynamicImport;
const pos = getNodePos();
@@ -4522,14 +4518,33 @@ namespace Parser {
parseExpected(SyntaxKind.ImportKeyword);
parseExpected(SyntaxKind.OpenParenToken);
const type = parseType();
let assertions: ImportTypeAssertionContainer | undefined;
let attributes: ImportAttributes | undefined;
if (parseOptional(SyntaxKind.CommaToken)) {
assertions = parseImportTypeAssertions();
const openBracePosition = scanner.getTokenStart();
parseExpected(SyntaxKind.OpenBraceToken);
const currentToken = token();
if (currentToken === SyntaxKind.WithKeyword || currentToken === SyntaxKind.AssertKeyword) {
nextToken();
}
else {
parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.WithKeyword));
}
parseExpected(SyntaxKind.ColonToken);
attributes = parseImportAttributes(currentToken as SyntaxKind.WithKeyword | SyntaxKind.AssertKeyword, /*skipKeyword*/ true);
if (!parseExpected(SyntaxKind.CloseBraceToken)) {
const lastError = lastOrUndefined(parseDiagnostics);
if (lastError && lastError.code === Diagnostics._0_expected.code) {
addRelatedInfo(
lastError,
createDetachedDiagnostic(fileName, sourceText, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}"),
);
}
}
}
parseExpected(SyntaxKind.CloseParenToken);
const qualifier = parseOptional(SyntaxKind.DotToken) ? parseEntityNameOfTypeReference() : undefined;
const typeArguments = parseTypeArgumentsOfTypeReference();
return finishNode(factory.createImportTypeNode(type, assertions, qualifier, typeArguments, isTypeOf), pos);
return finishNode(factory.createImportTypeNode(type, attributes, qualifier, typeArguments, isTypeOf), pos);
}
function nextTokenIsNumericOrBigIntLiteral() {
@@ -8341,34 +8356,33 @@ namespace Parser {
parseExpected(SyntaxKind.FromKeyword);
}
const moduleSpecifier = parseModuleSpecifier();
let assertClause: AssertClause | undefined;
if (token() === SyntaxKind.AssertKeyword && !scanner.hasPrecedingLineBreak()) {
assertClause = parseAssertClause();
const currentToken = token();
let attributes: ImportAttributes | undefined;
if ((currentToken === SyntaxKind.WithKeyword || currentToken === SyntaxKind.AssertKeyword) && !scanner.hasPrecedingLineBreak()) {
attributes = parseImportAttributes(currentToken);
}
parseSemicolon();
const node = factory.createImportDeclaration(modifiers, importClause, moduleSpecifier, assertClause);
const node = factory.createImportDeclaration(modifiers, importClause, moduleSpecifier, attributes);
return withJSDoc(finishNode(node, pos), hasJSDoc);
}
function parseAssertEntry() {
function parseImportAttribute() {
const pos = getNodePos();
const name = tokenIsIdentifierOrKeyword(token()) ? parseIdentifierName() : parseLiteralLikeNode(SyntaxKind.StringLiteral) as StringLiteral;
parseExpected(SyntaxKind.ColonToken);
const value = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);
return finishNode(factory.createAssertEntry(name, value), pos);
return finishNode(factory.createImportAttribute(name, value), pos);
}
function parseAssertClause(skipAssertKeyword?: true) {
function parseImportAttributes(token: SyntaxKind.AssertKeyword | SyntaxKind.WithKeyword, skipKeyword?: true) {
const pos = getNodePos();
if (!skipAssertKeyword) {
parseExpected(SyntaxKind.AssertKeyword);
if (!skipKeyword) {
parseExpected(token);
}
const openBracePosition = scanner.getTokenStart();
if (parseExpected(SyntaxKind.OpenBraceToken)) {
const multiLine = scanner.hasPrecedingLineBreak();
const elements = parseDelimitedList(ParsingContext.AssertEntries, parseAssertEntry, /*considerSemicolonAsDelimiter*/ true);
const elements = parseDelimitedList(ParsingContext.ImportAttributes, parseImportAttribute, /*considerSemicolonAsDelimiter*/ true);
if (!parseExpected(SyntaxKind.CloseBraceToken)) {
const lastError = lastOrUndefined(parseDiagnostics);
if (lastError && lastError.code === Diagnostics._0_expected.code) {
@@ -8378,11 +8392,11 @@ namespace Parser {
);
}
}
return finishNode(factory.createAssertClause(elements, multiLine), pos);
return finishNode(factory.createImportAttributes(elements, multiLine, token), pos);
}
else {
const elements = createNodeArray([], getNodePos(), /*end*/ undefined, /*hasTrailingComma*/ false);
return finishNode(factory.createAssertClause(elements, /*multiLine*/ false), pos);
return finishNode(factory.createImportAttributes(elements, /*multiLine*/ false, token), pos);
}
}
@@ -8585,7 +8599,7 @@ namespace Parser {
setAwaitContext(/*value*/ true);
let exportClause: NamedExportBindings | undefined;
let moduleSpecifier: Expression | undefined;
let assertClause: AssertClause | undefined;
let attributes: ImportAttributes | undefined;
const isTypeOnly = parseOptional(SyntaxKind.TypeKeyword);
const namespaceExportPos = getNodePos();
if (parseOptional(SyntaxKind.AsteriskToken)) {
@@ -8605,12 +8619,13 @@ namespace Parser {
moduleSpecifier = parseModuleSpecifier();
}
}
if (moduleSpecifier && token() === SyntaxKind.AssertKeyword && !scanner.hasPrecedingLineBreak()) {
assertClause = parseAssertClause();
const currentToken = token();
if (moduleSpecifier && (currentToken === SyntaxKind.WithKeyword || currentToken === SyntaxKind.AssertKeyword) && !scanner.hasPrecedingLineBreak()) {
attributes = parseImportAttributes(currentToken);
}
parseSemicolon();
setAwaitContext(savedAwaitContext);
const node = factory.createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause);
const node = factory.createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, attributes);
return withJSDoc(finishNode(node, pos), hasJSDoc);
}
@@ -8657,9 +8672,9 @@ namespace Parser {
TupleElementTypes, // Element types in tuple element type list
HeritageClauses, // Heritage clauses for a class or interface declaration.
ImportOrExportSpecifiers, // Named import clause's import specifier list,
AssertEntries, // Import entries list.
ImportAttributes, // Import attributes
JSDocComment, // Parsing via JSDocParser
Count, // Number of parsing contexts
Count, // Number of parsing contexts
}
const enum Tristate {
@@ -8670,7 +8685,7 @@ namespace Parser {
export namespace JSDocParser {
export function parseJSDocTypeExpressionForTests(content: string, start: number | undefined, length: number | undefined): { jsDocTypeExpression: JSDocTypeExpression; diagnostics: Diagnostic[]; } | undefined {
initializeState("file.js", content, ScriptTarget.Latest, /*syntaxCursor*/ undefined, ScriptKind.JS);
initializeState("file.js", content, ScriptTarget.Latest, /*syntaxCursor*/ undefined, ScriptKind.JS, JSDocParsingMode.ParseAll);
scanner.setText(content, start, length);
currentToken = scanner.scan();
const jsDocTypeExpression = parseJSDocTypeExpression();
@@ -8720,7 +8735,7 @@ namespace Parser {
}
export function parseIsolatedJSDocComment(content: string, start: number | undefined, length: number | undefined): { jsDoc: JSDoc; diagnostics: Diagnostic[]; } | undefined {
initializeState("", content, ScriptTarget.Latest, /*syntaxCursor*/ undefined, ScriptKind.JS);
initializeState("", content, ScriptTarget.Latest, /*syntaxCursor*/ undefined, ScriptKind.JS, JSDocParsingMode.ParseAll);
const jsDoc = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length));
const sourceFile = { languageVariant: LanguageVariant.Standard, text: content } as SourceFile;
@@ -9788,7 +9803,7 @@ namespace IncrementalParser {
if (sourceFile.statements.length === 0) {
// If we don't have any statements in the current source file, then there's no real
// way to incrementally parse. So just do a full parse instead.
return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator);
return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator, sourceFile.jsDocParsingMode);
}
// Make sure we're not trying to incrementally update a source file more than once. Once
@@ -9851,7 +9866,7 @@ namespace IncrementalParser {
// inconsistent tree. Setting the parents on the new tree should be very fast. We
// will immediately bail out of walking any subtrees when we can see that their parents
// are already correct.
const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator);
const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator, sourceFile.jsDocParsingMode);
result.commentDirectives = getNewCommentDirectives(
sourceFile.commentDirectives,
result.commentDirectives,
+138 -126
View File
@@ -139,7 +139,6 @@ import {
getPathFromPathComponents,
getPositionOfLineAndCharacter,
getPropertyArrayElementValue,
getResolvedModule,
getResolveJsonModule,
getRootLength,
getSetExternalModuleIndicator,
@@ -168,6 +167,7 @@ import {
HeritageClause,
Identifier,
identity,
ImportAttributes,
ImportClause,
ImportDeclaration,
ImportOrExportSpecifier,
@@ -272,6 +272,7 @@ import {
removeSuffix,
resolutionExtensionIsTSOrJson,
ResolutionMode,
ResolutionWithFailedLookupLocations,
resolveConfigFileProjectName,
ResolvedConfigFileName,
ResolvedModuleFull,
@@ -288,8 +289,6 @@ import {
ScriptTarget,
setParent,
setParentRecursive,
setResolvedModule,
setResolvedTypeReferenceDirective,
shouldResolveJsRequire,
skipTrivia,
skipTypeChecking,
@@ -330,7 +329,6 @@ import {
WriteFileCallback,
WriteFileCallbackData,
writeFileEnsuringDirectories,
zipToModeAwareCache,
} from "./_namespaces/ts";
import * as performance from "./_namespaces/ts.performance";
@@ -455,7 +453,11 @@ export function createWriteFileMeasuringIO(
}
/** @internal */
export function createCompilerHostWorker(options: CompilerOptions, setParentNodes?: boolean, system: System = sys): CompilerHost {
export function createCompilerHostWorker(
options: CompilerOptions,
setParentNodes?: boolean,
system: System = sys,
): CompilerHost {
const existingDirectories = new Map<string, boolean>();
const getCanonicalFileName = createGetCanonicalFileName(system.useCaseSensitiveFileNames);
function directoryExists(directoryPath: string): boolean {
@@ -863,7 +865,6 @@ export function getModeForResolutionAtIndex(file: SourceFile, index: number): Re
// eslint-disable-next-line @typescript-eslint/unified-signatures
export function getModeForResolutionAtIndex(file: SourceFileImportsList, index: number): ResolutionMode;
export function getModeForResolutionAtIndex(file: SourceFileImportsList, index: number): ResolutionMode {
if (file.impliedNodeFormat === undefined) return undefined;
// we ensure all elements of file.imports and file.moduleAugmentations have the relevant parent pointers set during program setup,
// so it's safe to use them even pre-bind
return getModeForUsageLocation(file, getModuleNameStringLiteralAt(file, index));
@@ -890,22 +891,22 @@ export function isExclusivelyTypeOnlyImportOrExport(decl: ImportDeclaration | Ex
* @returns The final resolution mode of the import
*/
export function getModeForUsageLocation(file: { impliedNodeFormat?: ResolutionMode; }, usage: StringLiteralLike) {
if (file.impliedNodeFormat === undefined) return undefined;
if ((isImportDeclaration(usage.parent) || isExportDeclaration(usage.parent))) {
const isTypeOnly = isExclusivelyTypeOnlyImportOrExport(usage.parent);
if (isTypeOnly) {
const override = getResolutionModeOverrideForClause(usage.parent.assertClause);
const override = getResolutionModeOverride(usage.parent.attributes);
if (override) {
return override;
}
}
}
if (usage.parent.parent && isImportTypeNode(usage.parent.parent)) {
const override = getResolutionModeOverrideForClause(usage.parent.parent.assertions?.assertClause);
const override = getResolutionModeOverride(usage.parent.parent.attributes);
if (override) {
return override;
}
}
if (file.impliedNodeFormat === undefined) return undefined;
if (file.impliedNodeFormat !== ModuleKind.ESNext) {
// in cjs files, import call expressions are esm format, otherwise everything is cjs
return isImportCall(walkUpParenthesizedExpressions(usage.parent)) ? ModuleKind.ESNext : ModuleKind.CommonJS;
@@ -917,16 +918,26 @@ export function getModeForUsageLocation(file: { impliedNodeFormat?: ResolutionMo
}
/** @internal */
export function getResolutionModeOverrideForClause(clause: AssertClause | undefined, grammarErrorOnNode?: (node: Node, diagnostic: DiagnosticMessage) => void) {
if (!clause) return undefined;
if (length(clause.elements) !== 1) {
grammarErrorOnNode?.(clause, Diagnostics.Type_import_assertions_should_have_exactly_one_key_resolution_mode_with_value_import_or_require);
export function getResolutionModeOverride(node: AssertClause | ImportAttributes | undefined, grammarErrorOnNode?: (node: Node, diagnostic: DiagnosticMessage) => void) {
if (!node) return undefined;
if (length(node.elements) !== 1) {
grammarErrorOnNode?.(
node,
node.token === SyntaxKind.WithKeyword
? Diagnostics.Type_import_attributes_should_have_exactly_one_key_resolution_mode_with_value_import_or_require
: Diagnostics.Type_import_assertions_should_have_exactly_one_key_resolution_mode_with_value_import_or_require,
);
return undefined;
}
const elem = clause.elements[0];
const elem = node.elements[0];
if (!isStringLiteralLike(elem.name)) return undefined;
if (elem.name.text !== "resolution-mode") {
grammarErrorOnNode?.(elem.name, Diagnostics.resolution_mode_is_the_only_valid_key_for_type_import_assertions);
grammarErrorOnNode?.(
elem.name,
node.token === SyntaxKind.WithKeyword
? Diagnostics.resolution_mode_is_the_only_valid_key_for_type_import_attributes
: Diagnostics.resolution_mode_is_the_only_valid_key_for_type_import_assertions,
);
return undefined;
}
if (!isStringLiteralLike(elem.value)) return undefined;
@@ -1108,7 +1119,8 @@ export function getInferredLibraryNameResolveFrom(options: CompilerOptions, curr
return combinePaths(containingDirectory, `__lib_node_modules_lookup_${libFileName}__.ts`);
}
function getLibraryNameFromLibFileName(libFileName: string) {
/** @internal */
export function getLibraryNameFromLibFileName(libFileName: string) {
// Support resolving to lib.dom.d.ts -> @typescript/lib-dom, and
// lib.dom.iterable.d.ts -> @typescript/lib-dom/iterable
// lib.es2015.symbol.wellknown.d.ts -> @typescript/lib-es2015/symbol-wellknown
@@ -1167,14 +1179,14 @@ export function isReferenceFileLocation(location: ReferenceFileLocation | Synthe
}
/** @internal */
export function getReferencedFileLocation(getSourceFileByPath: (path: Path) => SourceFile | undefined, ref: ReferencedFile): ReferenceFileLocation | SyntheticReferenceFileLocation {
const file = Debug.checkDefined(getSourceFileByPath(ref.file));
export function getReferencedFileLocation(program: Program, ref: ReferencedFile): ReferenceFileLocation | SyntheticReferenceFileLocation {
const file = Debug.checkDefined(program.getSourceFileByPath(ref.file));
const { kind, index } = ref;
let pos: number | undefined, end: number | undefined, packageId: PackageId | undefined, resolutionMode: FileReference["resolutionMode"] | undefined;
switch (kind) {
case FileIncludeKind.Import:
const importLiteral = getModuleNameStringLiteralAt(file, index);
packageId = file.resolvedModules?.get(importLiteral.text, getModeForResolutionAtIndex(file, index))?.resolvedModule?.packageId;
packageId = program.getResolvedModule(file, importLiteral.text, getModeForResolutionAtIndex(file, index))?.resolvedModule?.packageId;
if (importLiteral.pos === -1) return { file, packageId, text: importLiteral.text };
pos = skipTrivia(file.text, importLiteral.pos);
end = importLiteral.end;
@@ -1184,7 +1196,7 @@ export function getReferencedFileLocation(getSourceFileByPath: (path: Path) => S
break;
case FileIncludeKind.TypeReferenceDirective:
({ pos, end, resolutionMode } = file.typeReferenceDirectives[index]);
packageId = file.resolvedTypeReferenceDirectiveNames?.get(toFileNameLowerCase(file.typeReferenceDirectives[index].fileName), resolutionMode || file.impliedNodeFormat)?.resolvedTypeReferenceDirective?.packageId;
packageId = program.getResolvedTypeReferenceDirective(file, toFileNameLowerCase(file.typeReferenceDirectives[index].fileName), resolutionMode || file.impliedNodeFormat)?.resolvedTypeReferenceDirective?.packageId;
break;
case FileIncludeKind.LibReferenceDirective:
({ pos, end } = file.libReferenceDirectives[index]);
@@ -1391,7 +1403,7 @@ export const plainJSErrors = new Set<number>([
Diagnostics.Classes_may_not_have_a_field_named_constructor.code,
Diagnostics.Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern.code,
Diagnostics.Duplicate_label_0.code,
Diagnostics.Dynamic_imports_can_only_accept_a_module_specifier_and_an_optional_assertion_as_arguments.code,
Diagnostics.Dynamic_imports_can_only_accept_a_module_specifier_and_an_optional_set_of_attributes_as_arguments.code,
Diagnostics.for_await_loops_cannot_be_used_inside_a_class_static_block.code,
Diagnostics.JSX_attributes_must_only_be_assigned_a_non_empty_expression.code,
Diagnostics.JSX_elements_cannot_have_multiple_attributes_with_the_same_name.code,
@@ -1509,6 +1521,11 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
let resolvedLibReferences: Map<string, LibResolution> | undefined;
let resolvedLibProcessing: Map<string, LibResolution> | undefined;
let resolvedModules: Map<Path, ModeAwareCache<ResolvedModuleWithFailedLookupLocations>> | undefined;
let resolvedModulesProcessing: Map<Path, readonly ResolvedModuleWithFailedLookupLocations[]> | undefined;
let resolvedTypeReferenceDirectiveNames: Map<Path, ModeAwareCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>> | undefined;
let resolvedTypeReferenceDirectiveNamesProcessing: Map<Path, readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[]> | undefined;
let packageMap: Map<string, boolean> | undefined;
// The below settings are to track if a .js file should be add to the program if loaded via searching under node_modules.
@@ -1834,6 +1851,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
// unconditionally set oldProgram to undefined to prevent it from being captured in closure
oldProgram = undefined;
resolvedLibProcessing = undefined;
resolvedModulesProcessing = undefined;
resolvedTypeReferenceDirectiveNamesProcessing = undefined;
const program: Program = {
getRootFileNames: () => rootNames,
@@ -1875,7 +1894,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
sourceFileToPackageName,
redirectTargetsMap,
usesUriStyleNodeCoreModules,
resolvedModules,
resolvedTypeReferenceDirectiveNames,
resolvedLibReferences,
getResolvedModule,
getResolvedTypeReferenceDirective,
forEachResolvedModule,
forEachResolvedTypeReferenceDirective,
getCurrentPackagesMap: () => packageMap,
typesPackageExists,
packageBundlesTypes,
@@ -1909,7 +1934,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
case FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic:
return programDiagnostics.add(createDiagnosticExplainingFile(diagnostic.file && getSourceFileByPath(diagnostic.file), diagnostic.fileProcessingReason, diagnostic.diagnostic, diagnostic.args || emptyArray));
case FilePreprocessingDiagnosticsKind.FilePreprocessingReferencedDiagnostic:
const { file, pos, end } = getReferencedFileLocation(getSourceFileByPath, diagnostic.reason) as ReferenceFileLocation;
const { file, pos, end } = getReferencedFileLocation(program, diagnostic.reason) as ReferenceFileLocation;
return programDiagnostics.add(createFileDiagnostic(file, Debug.checkDefined(pos), Debug.checkDefined(end) - pos, diagnostic.diagnostic, ...diagnostic.args || emptyArray));
case FilePreprocessingDiagnosticsKind.ResolutionDiagnostics:
return diagnostic.diagnostics.forEach(d => programDiagnostics.add(d));
@@ -1925,6 +1950,37 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
return program;
function getResolvedModule(file: SourceFile, moduleName: string, mode: ResolutionMode) {
return resolvedModules?.get(file.path)?.get(moduleName, mode);
}
function getResolvedTypeReferenceDirective(file: SourceFile, typeDirectiveName: string, mode: ResolutionMode) {
return resolvedTypeReferenceDirectiveNames?.get(file.path)?.get(typeDirectiveName, mode);
}
function forEachResolvedModule(
callback: (resolution: ResolvedModuleWithFailedLookupLocations, moduleName: string, mode: ResolutionMode, filePath: Path) => void,
file?: SourceFile,
) {
forEachResolution(resolvedModules, callback, file);
}
function forEachResolvedTypeReferenceDirective(
callback: (resolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations, moduleName: string, mode: ResolutionMode, filePath: Path) => void,
file?: SourceFile,
): void {
forEachResolution(resolvedTypeReferenceDirectiveNames, callback, file);
}
function forEachResolution<T>(
resolutionCache: Map<Path, ModeAwareCache<T>> | undefined,
callback: (resolution: T, moduleName: string, mode: ResolutionMode, filePath: Path) => void,
file: SourceFile | undefined,
) {
if (file) resolutionCache?.get(file.path)?.forEach((resolution, name, mode) => callback(resolution, name, mode, file.path));
else resolutionCache?.forEach((resolutions, filePath) => resolutions.forEach((resolution, name, mode) => callback(resolution, name, mode, filePath)));
}
function getPackagesMap() {
if (packageMap) return packageMap;
packageMap = new Map();
@@ -1932,12 +1988,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
// This is useful as an approximation of whether a package bundles its own types.
// Note: we only look at files already found by module resolution,
// so there may be files we did not consider.
files.forEach(sf => {
if (!sf.resolvedModules) return;
sf.resolvedModules.forEach(({ resolvedModule }) => {
if (resolvedModule?.packageId) packageMap!.set(resolvedModule.packageId.name, resolvedModule.extension === Extension.Dts || !!packageMap!.get(resolvedModule.packageId.name));
});
forEachResolvedModule(({ resolvedModule }) => {
if (resolvedModule?.packageId) packageMap!.set(resolvedModule.packageId.name, resolvedModule.extension === Extension.Dts || !!packageMap!.get(resolvedModule.packageId.name));
});
return packageMap;
}
@@ -2084,23 +2136,6 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
return resolveModuleNamesWorker(moduleNames, file, /*reusedNames*/ undefined);
}
const oldSourceFile = oldProgram && oldProgram.getSourceFile(file.fileName);
if (oldSourceFile !== file && file.resolvedModules) {
// `file` was created for the new program.
//
// We only set `file.resolvedModules` via work from the current function,
// so it is defined iff we already called the current function on `file`.
// That call happened no later than the creation of the `file` object,
// which per above occurred during the current program creation.
// Since we assume the filesystem does not change during program creation,
// it is safe to reuse resolutions from the earlier call.
const result: ResolvedModuleWithFailedLookupLocations[] = [];
for (const moduleName of moduleNames) {
const resolvedModule = file.resolvedModules.get(moduleName.text, getModeForUsageLocation(file, moduleName))!;
result.push(resolvedModule);
}
return result;
}
// At this point, we know at least one of the following hold:
// - file has local declarations for ambient modules
// - old program state is available
@@ -2121,13 +2156,14 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
let reusedNames: StringLiteralLike[] | undefined;
/** A transient placeholder used to mark predicted resolution in the result list. */
const predictedToResolveToAmbientModuleMarker: ResolvedModuleWithFailedLookupLocations = emptyResolution;
const oldSourceFile = oldProgram && oldProgram.getSourceFile(file.fileName);
for (let i = 0; i < moduleNames.length; i++) {
const moduleName = moduleNames[i];
// If the source file is unchanged and doesnt have invalidated resolution, reuse the module resolutions
if (file === oldSourceFile && !hasInvalidatedResolutions(oldSourceFile.path)) {
if (file === oldSourceFile && !hasInvalidatedResolutions(file.path)) {
const mode = getModeForUsageLocation(file, moduleName);
const oldResolution = oldSourceFile.resolvedModules?.get(moduleName.text, mode);
const oldResolution = oldProgram?.getResolvedModule(file, moduleName.text, mode);
if (oldResolution?.resolvedModule) {
if (isTraceEnabled(options, host)) {
trace(
@@ -2195,7 +2231,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
// If we change our policy of rechecking failed lookups on each program create,
// we should adjust the value returned here.
function moduleNameResolvesToAmbientModuleInNonModifiedFile(moduleName: StringLiteralLike): boolean {
const resolutionToFile = getResolvedModule(oldSourceFile, moduleName.text, getModeForUsageLocation(file, moduleName));
const resolutionToFile = oldProgram?.getResolvedModule(file, moduleName.text, getModeForUsageLocation(file, moduleName))?.resolvedModule;
const resolvedFile = resolutionToFile && oldProgram!.getSourceFile(resolutionToFile.resolvedFileName);
if (resolutionToFile && resolvedFile) {
// In the old program, we resolved to an ambient module that was in the same
@@ -2228,41 +2264,23 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
return resolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames, containingFile, /*reusedNames*/ undefined);
}
const oldSourceFile = !isString(containingFile) ? oldProgram && oldProgram.getSourceFile(containingFile.fileName) : undefined;
if (!isString(containingFile)) {
if (oldSourceFile !== containingFile && containingFile.resolvedTypeReferenceDirectiveNames) {
// `file` was created for the new program.
//
// We only set `file.resolvedTypeReferenceDirectiveNames` via work from the current function,
// so it is defined iff we already called the current function on `file`.
// That call happened no later than the creation of the `file` object,
// which per above occurred during the current program creation.
// Since we assume the filesystem does not change during program creation,
// it is safe to reuse resolutions from the earlier call.
const result: ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] = [];
for (const typeDirectiveName of typeDirectiveNames as readonly FileReference[]) {
// We lower-case all type references because npm automatically lowercases all packages. See GH#9824.
const resolvedTypeReferenceDirective = containingFile.resolvedTypeReferenceDirectiveNames.get(getTypeReferenceResolutionName(typeDirectiveName), getModeForFileReference(typeDirectiveName, containingFile.impliedNodeFormat))!;
result.push(resolvedTypeReferenceDirective);
}
return result;
}
}
/** An ordered list of module names for which we cannot recover the resolution. */
let unknownTypeReferenceDirectiveNames: T[] | undefined;
let result: ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] | undefined;
let reusedNames: T[] | undefined;
const containingSourceFile = !isString(containingFile) ? containingFile : undefined;
const oldSourceFile = !isString(containingFile) ? oldProgram && oldProgram.getSourceFile(containingFile.fileName) : undefined;
const canReuseResolutions = !isString(containingFile) ?
containingFile === oldSourceFile && !hasInvalidatedResolutions(oldSourceFile.path) :
containingFile === oldSourceFile && !hasInvalidatedResolutions(containingFile.path) :
!hasInvalidatedResolutions(toPath(containingFile));
for (let i = 0; i < typeDirectiveNames.length; i++) {
const entry = typeDirectiveNames[i];
if (canReuseResolutions) {
const typeDirectiveName = getTypeReferenceResolutionName(entry);
const mode = getModeForFileReference(entry, containingSourceFile?.impliedNodeFormat);
const oldResolution = (!isString(containingFile) ? oldSourceFile?.resolvedTypeReferenceDirectiveNames : oldProgram?.getAutomaticTypeDirectiveResolutions())?.get(typeDirectiveName, mode);
const oldResolution = !isString(containingFile) ?
oldProgram?.getResolvedTypeReferenceDirective(containingFile, typeDirectiveName, mode) :
oldProgram?.getAutomaticTypeDirectiveResolutions()?.get(typeDirectiveName, mode);
if (oldResolution?.resolvedTypeReferenceDirective) {
if (isTraceEnabled(options, host)) {
trace(
@@ -2364,7 +2382,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
// check if program source files has changed in the way that can affect structure of the program
const newSourceFiles: SourceFile[] = [];
const modifiedSourceFiles: { oldFile: SourceFile; newFile: SourceFile; }[] = [];
const modifiedSourceFiles: SourceFile[] = [];
structureIsReused = StructureIsReused.Completely;
// If the missing file paths are now present, it can change the progam structure,
@@ -2476,14 +2494,19 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
}
// tentatively approve the file
modifiedSourceFiles.push({ oldFile: oldSourceFile, newFile: newSourceFile });
modifiedSourceFiles.push(newSourceFile);
}
else if (hasInvalidatedResolutions(oldSourceFile.path)) {
// 'module/types' references could have changed
structureIsReused = StructureIsReused.SafeModules;
// add file to the modified list so that we will resolve it later
modifiedSourceFiles.push({ oldFile: oldSourceFile, newFile: newSourceFile });
modifiedSourceFiles.push(newSourceFile);
}
else {
for (const moduleName of oldSourceFile.ambientModuleNames) {
ambientModuleNameToUnmodifiedFileName.set(moduleName, oldSourceFile.fileName);
}
}
// if file has passed all checks it should be safe to reuse it
@@ -2494,38 +2517,34 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
return structureIsReused;
}
const modifiedFiles = modifiedSourceFiles.map(f => f.oldFile);
for (const oldFile of oldSourceFiles) {
if (!contains(modifiedFiles, oldFile)) {
for (const moduleName of oldFile.ambientModuleNames) {
ambientModuleNameToUnmodifiedFileName.set(moduleName, oldFile.fileName);
}
}
}
// try to verify results of module resolution
for (const { oldFile: oldSourceFile, newFile: newSourceFile } of modifiedSourceFiles) {
for (const newSourceFile of modifiedSourceFiles) {
const moduleNames = getModuleNames(newSourceFile);
const resolutions = resolveModuleNamesReusingOldState(moduleNames, newSourceFile);
(resolvedModulesProcessing ??= new Map()).set(newSourceFile.path, resolutions);
// ensure that module resolution results are still correct
const resolutionsChanged = hasChangesInResolutions(moduleNames, newSourceFile, resolutions, oldSourceFile.resolvedModules, moduleResolutionIsEqualTo, moduleResolutionNameAndModeGetter);
if (resolutionsChanged) {
structureIsReused = StructureIsReused.SafeModules;
newSourceFile.resolvedModules = zipToModeAwareCache(newSourceFile, moduleNames, resolutions, moduleResolutionNameAndModeGetter);
}
else {
newSourceFile.resolvedModules = oldSourceFile.resolvedModules;
}
const resolutionsChanged = hasChangesInResolutions(
moduleNames,
newSourceFile,
resolutions,
(name, mode) => oldProgram!.getResolvedModule(newSourceFile, name, mode),
moduleResolutionIsEqualTo,
moduleResolutionNameAndModeGetter,
);
if (resolutionsChanged) structureIsReused = StructureIsReused.SafeModules;
const typesReferenceDirectives = newSourceFile.typeReferenceDirectives;
const typeReferenceResolutions = resolveTypeReferenceDirectiveNamesReusingOldState(typesReferenceDirectives, newSourceFile);
(resolvedTypeReferenceDirectiveNamesProcessing ??= new Map()).set(newSourceFile.path, typeReferenceResolutions);
// ensure that types resolutions are still correct
const typeReferenceResolutionsChanged = hasChangesInResolutions(typesReferenceDirectives, newSourceFile, typeReferenceResolutions, oldSourceFile.resolvedTypeReferenceDirectiveNames, typeDirectiveIsEqualTo, typeReferenceResolutionNameAndModeGetter);
if (typeReferenceResolutionsChanged) {
structureIsReused = StructureIsReused.SafeModules;
newSourceFile.resolvedTypeReferenceDirectiveNames = zipToModeAwareCache(newSourceFile, typesReferenceDirectives, typeReferenceResolutions, typeReferenceResolutionNameAndModeGetter);
}
else {
newSourceFile.resolvedTypeReferenceDirectiveNames = oldSourceFile.resolvedTypeReferenceDirectiveNames;
}
const typeReferenceResolutionsChanged = hasChangesInResolutions(
typesReferenceDirectives,
newSourceFile,
typeReferenceResolutions,
(name, mode) => oldProgram?.getResolvedTypeReferenceDirective(newSourceFile, name, mode),
typeDirectiveIsEqualTo,
typeReferenceResolutionNameAndModeGetter,
);
if (typeReferenceResolutionsChanged) structureIsReused = StructureIsReused.SafeModules;
}
if (structureIsReused !== StructureIsReused.Completely) {
@@ -2583,6 +2602,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
sourceFileToPackageName = oldProgram.sourceFileToPackageName;
redirectTargetsMap = oldProgram.redirectTargetsMap;
usesUriStyleNodeCoreModules = oldProgram.usesUriStyleNodeCoreModules;
resolvedModules = oldProgram.resolvedModules;
resolvedTypeReferenceDirectiveNames = oldProgram.resolvedTypeReferenceDirectiveNames;
resolvedLibReferences = oldProgram.resolvedLibReferences;
packageMap = oldProgram.getCurrentPackagesMap();
@@ -3283,7 +3304,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
function createSyntheticImport(text: string, file: SourceFile) {
const externalHelpersModuleReference = factory.createStringLiteral(text);
const importDecl = factory.createImportDeclaration(/*modifiers*/ undefined, /*importClause*/ undefined, externalHelpersModuleReference, /*assertClause*/ undefined);
const importDecl = factory.createImportDeclaration(/*modifiers*/ undefined, /*importClause*/ undefined, externalHelpersModuleReference, /*attributes*/ undefined);
addInternalEmitFlags(importDecl, InternalEmitFlags.NeverApplyImportHelper);
setParent(externalHelpersModuleReference, importDecl);
setParent(importDecl, file);
@@ -3545,8 +3566,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
const languageVersion = getEmitScriptTarget(options);
const setExternalModuleIndicator = getSetExternalModuleIndicator(options);
return typeof result === "object" ?
{ ...result, languageVersion, setExternalModuleIndicator } :
{ languageVersion, impliedNodeFormat: result, setExternalModuleIndicator };
{ ...result, languageVersion, setExternalModuleIndicator, jsDocParsingMode: host.jsDocParsingMode } :
{ languageVersion, impliedNodeFormat: result, setExternalModuleIndicator, jsDocParsingMode: host.jsDocParsingMode };
}
function findSourceFileWorker(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined {
@@ -3828,27 +3849,19 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
function processTypeReferenceDirectives(file: SourceFile) {
const typeDirectives = file.typeReferenceDirectives;
if (!typeDirectives.length) {
file.resolvedTypeReferenceDirectiveNames = undefined;
return;
}
if (!typeDirectives.length) return;
const resolutions = resolveTypeReferenceDirectiveNamesReusingOldState(typeDirectives, file);
const resolutions = resolvedTypeReferenceDirectiveNamesProcessing?.get(file.path) ||
resolveTypeReferenceDirectiveNamesReusingOldState(typeDirectives, file);
const resolutionsInFile = createModeAwareCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>();
(resolvedTypeReferenceDirectiveNames ??= new Map()).set(file.path, resolutionsInFile);
for (let index = 0; index < typeDirectives.length; index++) {
const ref = file.typeReferenceDirectives[index];
const resolvedTypeReferenceDirective = resolutions[index];
// store resolved type directive on the file
const fileName = toFileNameLowerCase(ref.fileName);
setResolvedTypeReferenceDirective(file, fileName, resolvedTypeReferenceDirective, getModeForFileReference(ref, file.impliedNodeFormat));
resolutionsInFile.set(fileName, getModeForFileReference(ref, file.impliedNodeFormat), resolvedTypeReferenceDirective);
const mode = ref.resolutionMode || file.impliedNodeFormat;
if (mode && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeNext) {
(fileProcessingDiagnostics ??= []).push({
kind: FilePreprocessingDiagnosticsKind.ResolutionDiagnostics,
diagnostics: [
createDiagnosticForRange(file, ref, Diagnostics.resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext),
],
});
}
processTypeReferenceDirective(fileName, mode, resolvedTypeReferenceDirective, { kind: FileIncludeKind.TypeReferenceDirective, file: file.path, index });
}
}
@@ -4007,14 +4020,17 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
if (file.imports.length || file.moduleAugmentations.length) {
// Because global augmentation doesn't have string literal name, we can check for global augmentation as such.
const moduleNames = getModuleNames(file);
const resolutions = resolveModuleNamesReusingOldState(moduleNames, file);
const resolutions = resolvedModulesProcessing?.get(file.path) ||
resolveModuleNamesReusingOldState(moduleNames, file);
Debug.assert(resolutions.length === moduleNames.length);
const optionsForFile = (useSourceOfProjectReferenceRedirect ? getRedirectReferenceForResolution(file)?.commandLine.options : undefined) || options;
const resolutionsInFile = createModeAwareCache<ResolutionWithFailedLookupLocations>();
(resolvedModules ??= new Map()).set(file.path, resolutionsInFile);
for (let index = 0; index < moduleNames.length; index++) {
const resolution = resolutions[index].resolvedModule;
const moduleName = moduleNames[index].text;
const mode = getModeForUsageLocation(file, moduleNames[index]);
setResolvedModule(file, moduleName, resolutions[index], mode);
resolutionsInFile.set(moduleName, mode, resolutions[index]);
addResolutionDiagnosticsFromResolutionOrCache(file, moduleName, resolutions[index], mode);
if (!resolution) {
@@ -4064,10 +4080,6 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
}
}
}
else {
// no imports - drop cached module resolutions
file.resolvedModules = undefined;
}
}
function checkSourceFilesBelongToPath(sourceFiles: readonly SourceFile[], rootDirectory: string): boolean {
@@ -4607,7 +4619,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
if (fileProcessingReason) processReason(fileProcessingReason);
// If we have location and there is only one reason file is in which is the location, dont add details for file include
if (locationReason && fileIncludeReasons?.length === 1) fileIncludeReasons = undefined;
const location = locationReason && getReferencedFileLocation(getSourceFileByPath, locationReason);
const location = locationReason && getReferencedFileLocation(program, locationReason);
const fileIncludeReasonDetails = fileIncludeReasons && chainDiagnosticMessages(fileIncludeReasons, Diagnostics.The_file_is_in_the_program_because_Colon);
const redirectInfo = file && explainIfFileIsRedirectAndImpliedFormat(file);
const chain = chainDiagnosticMessages(redirectInfo ? fileIncludeReasonDetails ? [fileIncludeReasonDetails, ...redirectInfo] : redirectInfo : fileIncludeReasonDetails, diagnostic, ...args || emptyArray);
@@ -4645,7 +4657,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
function fileIncludeReasonToRelatedInformation(reason: FileIncludeReason): DiagnosticWithLocation | undefined {
if (isReferencedFile(reason)) {
const referenceLocation = getReferencedFileLocation(getSourceFileByPath, reason);
const referenceLocation = getReferencedFileLocation(program, reason);
let message: DiagnosticMessage;
switch (reason.kind) {
case FileIncludeKind.Import:
@@ -4963,8 +4975,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
if (!symlinks) {
symlinks = createSymlinkCache(currentDirectory, getCanonicalFileName);
}
if (files && automaticTypeDirectiveResolutions && !symlinks.hasProcessedResolutions()) {
symlinks.setSymlinksFromResolutions(files, automaticTypeDirectiveResolutions);
if (files && !symlinks.hasProcessedResolutions()) {
symlinks.setSymlinksFromResolutions(forEachResolvedModule, forEachResolvedTypeReferenceDirective, automaticTypeDirectiveResolutions);
}
return symlinks;
}
+209 -128
View File
@@ -54,6 +54,7 @@ import {
normalizePath,
PackageId,
packageIdToString,
PackageJsonInfo,
parseNodeModuleFromPath,
Path,
PathPathComponents,
@@ -89,9 +90,26 @@ export interface HasInvalidatedFromResolutionCache {
* @internal
*/
export interface ResolutionCache {
rootDirForResolution: string;
resolvedModuleNames: Map<Path, ModeAwareCache<CachedResolvedModuleWithFailedLookupLocations>>;
resolvedTypeReferenceDirectives: Map<Path, ModeAwareCache<CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations>>;
resolvedLibraries: Map<string, CachedResolvedModuleWithFailedLookupLocations>;
resolvedFileToResolution: Map<Path, Set<ResolutionWithFailedLookupLocations>>;
resolutionsWithFailedLookups: Set<ResolutionWithFailedLookupLocations>;
resolutionsWithOnlyAffectingLocations: Set<ResolutionWithFailedLookupLocations>;
directoryWatchesOfFailedLookups: Map<string, DirectoryWatchesOfFailedLookup>;
fileWatchesOfAffectingLocations: Map<string, FileWatcherOfAffectingLocation>;
startRecordingFilesWithChangedResolutions(): void;
finishRecordingFilesWithChangedResolutions(): Path[] | undefined;
watchFailedLookupLocationsOfExternalModuleResolutions<T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName>(
name: string,
resolution: T,
filePath: Path,
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>,
deferWatchingNonRelativeResolution: boolean,
): void;
resolveModuleNameLiterals(
moduleLiterals: readonly StringLiteralLike[],
containingFile: string,
@@ -121,7 +139,7 @@ export interface ResolutionCache {
invalidateResolutionsOfFailedLookupLocations(): boolean;
invalidateResolutionOfFile(filePath: Path): void;
removeResolutionsOfFile(filePath: Path): void;
removeResolutionsOfFile(filePath: Path, syncDirWatcherRemove?: boolean): void;
removeResolutionsFromProjectReferenceRedirects(filePath: Path): void;
setFilesWithInvalidatedNonRelativeUnresolvedImports(filesWithUnresolvedImports: Map<Path, readonly string[]>): void;
createHasInvalidatedResolutions(
@@ -154,7 +172,8 @@ export interface ResolutionWithFailedLookupLocations {
node10Result?: string;
}
interface ResolutionWithResolvedFileName {
/** @internal */
export interface ResolutionWithResolvedFileName {
resolvedFileName: string | undefined;
packageId?: PackageId;
}
@@ -163,7 +182,8 @@ interface ResolutionWithResolvedFileName {
export interface CachedResolvedModuleWithFailedLookupLocations extends ResolvedModuleWithFailedLookupLocations, ResolutionWithFailedLookupLocations {
}
interface CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations extends ResolvedTypeReferenceDirectiveWithFailedLookupLocations, ResolutionWithFailedLookupLocations {
/** @internal */
export interface CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations extends ResolvedTypeReferenceDirectiveWithFailedLookupLocations, ResolutionWithFailedLookupLocations {
}
/** @internal */
@@ -187,15 +207,17 @@ export interface ResolutionCacheHost extends MinimalResolutionCacheHost {
onDiscoveredSymlink?(): void;
}
interface FileWatcherOfAffectingLocation {
/** @internal */
export interface FileWatcherOfAffectingLocation {
/** watcher for the lookup */
watcher: FileWatcher;
resolutions: number;
files: number;
paths: Set<string>;
symlinks: Set<string> | undefined;
}
interface DirectoryWatchesOfFailedLookup {
/** @internal */
export interface DirectoryWatchesOfFailedLookup {
/** watcher for the lookup */
watcher: FileWatcher;
/** ref count keeping this watch alive */
@@ -226,7 +248,7 @@ export function removeIgnoredPath(path: Path): Path | undefined {
function perceivedOsRootLengthForWatching(pathComponents: Readonly<PathPathComponents>, length: number) {
// Ignore "/", "c:/"
if (length <= 1) return 1;
let userCheckIndex = 1;
let indexAfterOsRoot = 1;
let isDosStyle = pathComponents[0].search(/[a-zA-Z]:/) === 0;
if (
pathComponents[0] !== directorySeparator &&
@@ -235,20 +257,25 @@ function perceivedOsRootLengthForWatching(pathComponents: Readonly<PathPathCompo
) {
// ignore "//vda1cs4850/c$/folderAtRoot"
if (length === 2) return 2;
userCheckIndex = 2;
indexAfterOsRoot = 2;
isDosStyle = true;
}
if (
isDosStyle &&
!pathComponents[userCheckIndex].match(/^users$/i)
!pathComponents[indexAfterOsRoot].match(/^users$/i)
) {
// Paths like c:/notUsers
return userCheckIndex;
return indexAfterOsRoot;
}
if (pathComponents[indexAfterOsRoot].match(/^workspaces$/i)) {
// Paths like: /workspaces as codespaces hoist the repos in /workspaces so we have to exempt these from "2" level from root rule
return indexAfterOsRoot + 1;
}
// Paths like: c:/users/username or /home/username
return userCheckIndex + 2;
return indexAfterOsRoot + 2;
}
/**
@@ -412,7 +439,74 @@ export function getRootPathSplitLength(rootPath: Path) {
return rootPath.split(directorySeparator).length - (hasTrailingDirectorySeparator(rootPath) ? 1 : 0);
}
type GetResolutionWithResolvedFileName<T extends ResolutionWithFailedLookupLocations = ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName = ResolutionWithResolvedFileName> = (resolution: T) => R | undefined;
/** @internal */
export function createModuleResolutionLoaderUsingGlobalCache(
containingFile: string,
redirectedReference: ResolvedProjectReference | undefined,
options: CompilerOptions,
resolutionHost: ResolutionCacheHost,
moduleResolutionCache: ModuleResolutionCache,
): ResolutionLoader<StringLiteralLike, ResolvedModuleWithFailedLookupLocations, SourceFile> {
return {
nameAndMode: moduleResolutionNameAndModeGetter,
resolve: (moduleName, resoluionMode) =>
resolveModuleNameUsingGlobalCache(
resolutionHost,
moduleResolutionCache,
moduleName,
containingFile,
options,
redirectedReference,
resoluionMode,
),
};
}
function resolveModuleNameUsingGlobalCache(
resolutionHost: ResolutionCacheHost,
moduleResolutionCache: ModuleResolutionCache,
moduleName: string,
containingFile: string,
compilerOptions: CompilerOptions,
redirectedReference?: ResolvedProjectReference,
mode?: ResolutionMode,
): ResolvedModuleWithFailedLookupLocations {
const host = resolutionHost.getCompilerHost?.() || resolutionHost;
const primaryResult = ts_resolveModuleName(moduleName, containingFile, compilerOptions, host, moduleResolutionCache, redirectedReference, mode);
// return result immediately only if global cache support is not enabled or if it is .ts, .tsx or .d.ts
if (!resolutionHost.getGlobalCache) {
return primaryResult;
}
// otherwise try to load typings from @types
const globalCache = resolutionHost.getGlobalCache();
if (globalCache !== undefined && !isExternalModuleNameRelative(moduleName) && !(primaryResult.resolvedModule && extensionIsTS(primaryResult.resolvedModule.extension))) {
// create different collection of failed lookup locations for second pass
// if it will fail and we've already found something during the first pass - we don't want to pollute its results
const { resolvedModule, failedLookupLocations, affectingLocations, resolutionDiagnostics } = loadModuleFromGlobalCache(
Debug.checkDefined(resolutionHost.globalCacheResolutionModuleName)(moduleName),
resolutionHost.projectName,
compilerOptions,
host,
globalCache,
moduleResolutionCache,
);
if (resolvedModule) {
// Modify existing resolution so its saved in the directory cache as well
(primaryResult.resolvedModule as any) = resolvedModule;
primaryResult.failedLookupLocations = updateResolutionField(primaryResult.failedLookupLocations, failedLookupLocations);
primaryResult.affectingLocations = updateResolutionField(primaryResult.affectingLocations, affectingLocations);
primaryResult.resolutionDiagnostics = updateResolutionField(primaryResult.resolutionDiagnostics, resolutionDiagnostics);
return primaryResult;
}
}
// Default return the result from the first pass
return primaryResult;
}
/** @internal */
export type GetResolutionWithResolvedFileName<T extends ResolutionWithFailedLookupLocations = ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName = ResolutionWithResolvedFileName> = (resolution: T) => R | undefined;
/** @internal */
export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootDirForResolution: string, logChangesWhenResolvingModule: boolean): ResolutionCache {
@@ -423,7 +517,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
const resolutionsWithFailedLookups = new Set<ResolutionWithFailedLookupLocations>();
const resolutionsWithOnlyAffectingLocations = new Set<ResolutionWithFailedLookupLocations>();
const resolvedFileToResolution = new Map<string, Set<ResolutionWithFailedLookupLocations>>();
const resolvedFileToResolution = new Map<Path, Set<ResolutionWithFailedLookupLocations>>();
const impliedFormatPackageJsons = new Map<Path, readonly string[]>();
let hasChangedAutomaticTypeDirectiveNames = false;
@@ -464,7 +558,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
moduleResolutionCache.getPackageJsonInfoCache(),
);
const directoryWatchesOfFailedLookups = new Map<string, DirectoryWatchesOfFailedLookup>();
const directoryWatchesOfFailedLookups = new Map<Path, DirectoryWatchesOfFailedLookup>();
const fileWatchesOfAffectingLocations = new Map<string, FileWatcherOfAffectingLocation>();
const rootDir = getRootDirectoryOfResolutionCache(rootDirForResolution, getCurrentDirectory);
const rootPath = resolutionHost.toPath(rootDir);
@@ -474,6 +568,16 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
const typeRootsWatches = new Map<string, FileWatcher>();
return {
rootDirForResolution,
resolvedModuleNames,
resolvedTypeReferenceDirectives,
resolvedLibraries,
resolvedFileToResolution,
resolutionsWithFailedLookups,
resolutionsWithOnlyAffectingLocations,
directoryWatchesOfFailedLookups,
fileWatchesOfAffectingLocations,
watchFailedLookupLocationsOfExternalModuleResolutions,
getModuleResolutionCache: () => moduleResolutionCache,
startRecordingFilesWithChangedResolutions,
finishRecordingFilesWithChangedResolutions,
@@ -596,7 +700,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
if (!newProgram?.resolvedLibReferences?.has(libFileName)) {
stopWatchFailedLookupLocationOfResolution(
resolution,
resolutionHost.toPath(getInferredLibraryNameResolveFrom(newProgram!.getCompilerOptions(), getCurrentDirectory(), libFileName)),
resolutionHost.toPath(getInferredLibraryNameResolveFrom(resolutionHost.getCompilationSettings(), getCurrentDirectory(), libFileName)),
getResolvedModule,
);
resolvedLibraries.delete(libFileName);
@@ -633,73 +737,23 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
}
});
}
directoryWatchesOfFailedLookups.forEach((watcher, path) => {
if (watcher.refCount === 0) {
directoryWatchesOfFailedLookups.delete(path);
watcher.watcher.close();
}
});
fileWatchesOfAffectingLocations.forEach((watcher, path) => {
if (watcher.files === 0 && watcher.resolutions === 0) {
fileWatchesOfAffectingLocations.delete(path);
watcher.watcher.close();
}
});
directoryWatchesOfFailedLookups.forEach(closeDirectoryWatchesOfFailedLookup);
fileWatchesOfAffectingLocations.forEach(closeFileWatcherOfAffectingLocation);
hasChangedAutomaticTypeDirectiveNames = false;
}
function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, redirectedReference?: ResolvedProjectReference, mode?: ResolutionMode): CachedResolvedModuleWithFailedLookupLocations {
const host = resolutionHost.getCompilerHost?.() || resolutionHost;
const primaryResult = ts_resolveModuleName(moduleName, containingFile, compilerOptions, host, moduleResolutionCache, redirectedReference, mode);
// return result immediately only if global cache support is not enabled or if it is .ts, .tsx or .d.ts
if (!resolutionHost.getGlobalCache) {
return primaryResult;
function closeDirectoryWatchesOfFailedLookup(watcher: DirectoryWatchesOfFailedLookup, path: Path) {
if (watcher.refCount === 0) {
directoryWatchesOfFailedLookups.delete(path);
watcher.watcher.close();
}
// otherwise try to load typings from @types
const globalCache = resolutionHost.getGlobalCache();
if (globalCache !== undefined && !isExternalModuleNameRelative(moduleName) && !(primaryResult.resolvedModule && extensionIsTS(primaryResult.resolvedModule.extension))) {
// create different collection of failed lookup locations for second pass
// if it will fail and we've already found something during the first pass - we don't want to pollute its results
const { resolvedModule, failedLookupLocations, affectingLocations, resolutionDiagnostics } = loadModuleFromGlobalCache(
Debug.checkDefined(resolutionHost.globalCacheResolutionModuleName)(moduleName),
resolutionHost.projectName,
compilerOptions,
host,
globalCache,
moduleResolutionCache,
);
if (resolvedModule) {
// Modify existing resolution so its saved in the directory cache as well
(primaryResult.resolvedModule as any) = resolvedModule;
primaryResult.failedLookupLocations = updateResolutionField(primaryResult.failedLookupLocations, failedLookupLocations);
primaryResult.affectingLocations = updateResolutionField(primaryResult.affectingLocations, affectingLocations);
primaryResult.resolutionDiagnostics = updateResolutionField(primaryResult.resolutionDiagnostics, resolutionDiagnostics);
return primaryResult;
}
}
// Default return the result from the first pass
return primaryResult;
}
function createModuleResolutionLoader(
containingFile: string,
redirectedReference: ResolvedProjectReference | undefined,
options: CompilerOptions,
): ResolutionLoader<StringLiteralLike, ResolvedModuleWithFailedLookupLocations, SourceFile> {
return {
nameAndMode: moduleResolutionNameAndModeGetter,
resolve: (moduleName, resoluionMode) =>
resolveModuleName(
moduleName,
containingFile,
options,
redirectedReference,
resoluionMode,
),
};
function closeFileWatcherOfAffectingLocation(watcher: FileWatcherOfAffectingLocation, path: string) {
if (watcher.files === 0 && watcher.resolutions === 0 && !watcher.symlinks?.size) {
fileWatchesOfAffectingLocations.delete(path);
watcher.watcher.close();
}
}
interface ResolveNamesWithLocalCacheInput<Entry, SourceFile, T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName> {
@@ -760,9 +814,11 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
resolutionHost.onDiscoveredSymlink();
}
resolutionsInFile.set(name, mode, resolution);
watchFailedLookupLocationsOfExternalModuleResolutions(name, resolution, path, getResolutionWithResolvedFileName, deferWatchingNonRelativeResolution);
if (existingResolution) {
stopWatchFailedLookupLocationOfResolution(existingResolution, path, getResolutionWithResolvedFileName);
if (resolution !== existingResolution) {
watchFailedLookupLocationsOfExternalModuleResolutions(name, resolution, path, getResolutionWithResolvedFileName, deferWatchingNonRelativeResolution);
if (existingResolution) {
stopWatchFailedLookupLocationOfResolution(existingResolution, path, getResolutionWithResolvedFileName);
}
}
if (logChanges && filesWithChangedSetOfUnresolvedImports && !resolutionIsEqualTo(existingResolution, resolution)) {
@@ -881,10 +937,12 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
options,
reusedNames,
perFileCache: resolvedModuleNames,
loader: createModuleResolutionLoader(
loader: createModuleResolutionLoaderUsingGlobalCache(
containingFile,
redirectedReference,
options,
resolutionHost,
moduleResolutionCache,
),
getResolutionWithResolvedFileName: getResolvedModule,
shouldRetryResolution: resolution => !resolution.resolvedModule || !resolutionExtensionIsTSOrJson(resolution.resolvedModule.extension),
@@ -936,7 +994,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
const resolutionsInFile = resolvedModuleNames.get(path);
const resolution = resolutionsInFile?.get(moduleName, /*mode*/ undefined);
if (resolution && !resolution.isInvalidated) return resolution;
return resolveModuleName(moduleName, containingFile, resolutionHost.getCompilationSettings());
return resolveModuleNameUsingGlobalCache(resolutionHost, moduleResolutionCache, moduleName, containingFile, resolutionHost.getCompilationSettings());
}
function isNodeModulesAtTypesDirectory(dirPath: Path) {
@@ -1037,49 +1095,61 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
return;
}
let locationToWatch = affectingLocation;
let isSymlink = false;
let symlinkWatcher: FileWatcherOfAffectingLocation | undefined;
if (resolutionHost.realpath) {
locationToWatch = resolutionHost.realpath(affectingLocation);
if (affectingLocation !== locationToWatch) {
const fileWatcher = fileWatchesOfAffectingLocations.get(locationToWatch);
if (fileWatcher) {
if (forResolution) fileWatcher.resolutions++;
else fileWatcher.files++;
fileWatcher.paths.add(affectingLocation);
fileWatchesOfAffectingLocations.set(affectingLocation, fileWatcher);
return;
}
isSymlink = true;
symlinkWatcher = fileWatchesOfAffectingLocations.get(locationToWatch);
}
}
const paths = new Set<string>();
paths.add(locationToWatch);
let actualWatcher = canWatchAffectingLocation(resolutionHost.toPath(locationToWatch)) ?
resolutionHost.watchAffectingFileLocation(locationToWatch, (fileName, eventKind) => {
cachedDirectoryStructureHost?.addOrDeleteFile(fileName, resolutionHost.toPath(locationToWatch), eventKind);
const packageJsonMap = moduleResolutionCache.getPackageJsonInfoCache().getInternalMap();
paths.forEach(path => {
if (watcher.resolutions) (affectingPathChecks ??= new Set()).add(path);
if (watcher.files) (affectingPathChecksForFile ??= new Set()).add(path);
packageJsonMap?.delete(resolutionHost.toPath(path));
});
resolutionHost.scheduleInvalidateResolutionsOfFailedLookupLocations();
}) : noopFileWatcher;
const watcher: FileWatcherOfAffectingLocation = {
watcher: actualWatcher !== noopFileWatcher ? {
close: () => {
actualWatcher.close();
// Ensure when watching symlinked package.json, we can close the actual file watcher only once
actualWatcher = noopFileWatcher;
},
} : actualWatcher,
resolutions: forResolution ? 1 : 0,
files: forResolution ? 0 : 1,
paths,
};
fileWatchesOfAffectingLocations.set(locationToWatch, watcher);
if (affectingLocation !== locationToWatch) {
fileWatchesOfAffectingLocations.set(affectingLocation, watcher);
paths.add(affectingLocation);
const resolutions = forResolution ? 1 : 0;
const files = forResolution ? 0 : 1;
if (!isSymlink || !symlinkWatcher) {
const watcher: FileWatcherOfAffectingLocation = {
watcher: canWatchAffectingLocation(resolutionHost.toPath(locationToWatch)) ?
resolutionHost.watchAffectingFileLocation(locationToWatch, (fileName, eventKind) => {
cachedDirectoryStructureHost?.addOrDeleteFile(fileName, resolutionHost.toPath(locationToWatch), eventKind);
invalidateAffectingFileWatcher(locationToWatch, moduleResolutionCache.getPackageJsonInfoCache().getInternalMap());
resolutionHost.scheduleInvalidateResolutionsOfFailedLookupLocations();
}) : noopFileWatcher,
resolutions: isSymlink ? 0 : resolutions,
files: isSymlink ? 0 : files,
symlinks: undefined,
};
fileWatchesOfAffectingLocations.set(locationToWatch, watcher);
if (isSymlink) symlinkWatcher = watcher;
}
if (isSymlink) {
Debug.assert(!!symlinkWatcher);
const watcher: FileWatcherOfAffectingLocation = {
watcher: {
close: () => {
const symlinkWatcher = fileWatchesOfAffectingLocations.get(locationToWatch);
// Close symlink watcher if no ref
if (symlinkWatcher?.symlinks?.delete(affectingLocation) && !symlinkWatcher.symlinks.size && !symlinkWatcher.resolutions && !symlinkWatcher.files) {
fileWatchesOfAffectingLocations.delete(locationToWatch);
symlinkWatcher.watcher.close();
}
},
},
resolutions,
files,
symlinks: undefined,
};
fileWatchesOfAffectingLocations.set(affectingLocation, watcher);
(symlinkWatcher.symlinks ??= new Set()).add(affectingLocation);
}
}
function invalidateAffectingFileWatcher(path: string, packageJsonMap: Map<Path, PackageJsonInfo | boolean> | undefined) {
const watcher = fileWatchesOfAffectingLocations.get(path);
if (watcher?.resolutions) (affectingPathChecks ??= new Set()).add(path);
if (watcher?.files) (affectingPathChecksForFile ??= new Set()).add(path);
watcher?.symlinks?.forEach(path => invalidateAffectingFileWatcher(path, packageJsonMap));
packageJsonMap?.delete(resolutionHost.toPath(path));
}
function watchFailedLookupLocationOfNonRelativeModuleResolutions(resolutions: ResolutionWithFailedLookupLocations[], name: string) {
@@ -1103,7 +1173,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
}
}
function stopWatchFailedLookupLocation(failedLookupLocation: string, removeAtRoot: boolean) {
function stopWatchFailedLookupLocation(failedLookupLocation: string, removeAtRoot: boolean, syncDirWatcherRemove: boolean | undefined) {
const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation);
const toWatch = getDirectoryToWatchFailedLookupLocation(
failedLookupLocation,
@@ -1119,7 +1189,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
removeAtRoot = true;
}
else {
removeDirectoryWatcher(dirPath);
removeDirectoryWatcher(dirPath, syncDirWatcherRemove);
}
}
return removeAtRoot;
@@ -1129,6 +1199,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
resolution: T,
filePath: Path,
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>,
syncDirWatcherRemove?: boolean,
) {
Debug.checkDefined(resolution.files).delete(filePath);
resolution.refCount!--;
@@ -1147,11 +1218,11 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
let removeAtRoot = false;
if (failedLookupLocations) {
for (const failedLookupLocation of failedLookupLocations) {
removeAtRoot = stopWatchFailedLookupLocation(failedLookupLocation, removeAtRoot);
removeAtRoot = stopWatchFailedLookupLocation(failedLookupLocation, removeAtRoot, syncDirWatcherRemove);
}
}
if (node10Result) removeAtRoot = stopWatchFailedLookupLocation(node10Result, removeAtRoot);
if (removeAtRoot) removeDirectoryWatcher(rootPath);
if (node10Result) removeAtRoot = stopWatchFailedLookupLocation(node10Result, removeAtRoot, syncDirWatcherRemove);
if (removeAtRoot) removeDirectoryWatcher(rootPath, syncDirWatcherRemove);
}
else if (affectingLocations?.length) {
resolutionsWithOnlyAffectingLocations.delete(resolution);
@@ -1161,14 +1232,16 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
for (const affectingLocation of affectingLocations) {
const watcher = fileWatchesOfAffectingLocations.get(affectingLocation)!;
watcher.resolutions--;
if (syncDirWatcherRemove) closeFileWatcherOfAffectingLocation(watcher, affectingLocation);
}
}
}
function removeDirectoryWatcher(dirPath: string) {
function removeDirectoryWatcher(dirPath: Path, syncDirWatcherRemove: boolean | undefined) {
const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath)!;
// Do not close the watcher yet since it might be needed by other failed lookup locations.
dirWatcher.refCount--;
if (syncDirWatcherRemove) closeDirectoryWatchesOfFailedLookup(dirWatcher, dirPath);
}
function createDirectoryWatcher(directory: string, dirPath: Path, nonRecursive: boolean | undefined) {
@@ -1187,11 +1260,19 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
cache: Map<string, ModeAwareCache<T>>,
filePath: Path,
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>,
syncDirWatcherRemove: boolean | undefined,
) {
// Deleted file, stop watching failed lookups for all the resolutions in the file
const resolutions = cache.get(filePath);
if (resolutions) {
resolutions.forEach(resolution => stopWatchFailedLookupLocationOfResolution(resolution, filePath, getResolutionWithResolvedFileName));
resolutions.forEach(resolution =>
stopWatchFailedLookupLocationOfResolution(
resolution,
filePath,
getResolutionWithResolvedFileName,
syncDirWatcherRemove,
)
);
cache.delete(filePath);
}
}
@@ -1210,9 +1291,9 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
resolvedProjectReference.commandLine.fileNames.forEach(f => removeResolutionsOfFile(resolutionHost.toPath(f)));
}
function removeResolutionsOfFile(filePath: Path) {
removeResolutionsOfFileFromCache(resolvedModuleNames, filePath, getResolvedModule);
removeResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath, getResolvedTypeReferenceDirective);
function removeResolutionsOfFile(filePath: Path, syncDirWatcherRemove?: boolean) {
removeResolutionsOfFileFromCache(resolvedModuleNames, filePath, getResolvedModule, syncDirWatcherRemove);
removeResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath, getResolvedTypeReferenceDirective, syncDirWatcherRemove);
}
function invalidateResolutions(resolutions: Set<ResolutionWithFailedLookupLocations> | Map<string, ResolutionWithFailedLookupLocations> | undefined, canInvalidate: (resolution: ResolutionWithFailedLookupLocations) => boolean | undefined) {
+48 -4
View File
@@ -12,6 +12,7 @@ import {
DiagnosticMessage,
Diagnostics,
identity,
JSDocParsingMode,
JSDocSyntaxKind,
JsxTokenSyntaxKind,
KeywordSyntaxKind,
@@ -21,6 +22,7 @@ import {
parsePseudoBigInt,
positionIsSynthesized,
PunctuationOrKeywordSyntaxKind,
ScriptKind,
ScriptTarget,
SourceFileLike,
SyntaxKind,
@@ -95,6 +97,8 @@ export interface Scanner {
setOnError(onError: ErrorCallback | undefined): void;
setScriptTarget(scriptTarget: ScriptTarget): void;
setLanguageVariant(variant: LanguageVariant): void;
setScriptKind(scriptKind: ScriptKind): void;
setJSDocParsingMode(kind: JSDocParsingMode): void;
/** @deprecated use {@link resetTokenState} */
setTextPos(textPos: number): void;
resetTokenState(pos: number): void;
@@ -343,6 +347,8 @@ const commentDirectiveRegExSingleLine = /^\/\/\/?\s*@(ts-expect-error|ts-ignore)
*/
const commentDirectiveRegExMultiLine = /^(?:\/|\*)*\s*@(ts-expect-error|ts-ignore)/;
const jsDocSeeOrLink = /@(?:see|link)/i;
function lookupInUnicodeMap(code: number, map: readonly number[]): boolean {
// Bail out quickly if it couldn't possibly be in the map.
if (code < map[0]) {
@@ -1001,6 +1007,9 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
var commentDirectives: CommentDirective[] | undefined;
var inJSDocType = 0;
var scriptKind = ScriptKind.Unknown;
var jsDocParsingMode = JSDocParsingMode.ParseAll;
setText(text, start, length);
var scanner: Scanner = {
@@ -1045,6 +1054,8 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
setText,
setScriptTarget,
setLanguageVariant,
setScriptKind,
setJSDocParsingMode,
setOnError,
resetTokenState,
setTextPos: resetTokenState,
@@ -1352,7 +1363,8 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
start = pos;
continue;
}
if (isLineBreak(ch) && !jsxAttributeString) {
if ((ch === CharacterCodes.lineFeed || ch === CharacterCodes.carriageReturn) && !jsxAttributeString) {
result += text.substring(start, pos);
tokenFlags |= TokenFlags.Unterminated;
error(Diagnostics.Unterminated_string_literal);
@@ -1971,9 +1983,7 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
// Multi-line comment
if (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) {
pos += 2;
if (text.charCodeAt(pos) === CharacterCodes.asterisk && text.charCodeAt(pos + 1) !== CharacterCodes.slash) {
tokenFlags |= TokenFlags.PrecedingJSDocComment;
}
const isJSDoc = text.charCodeAt(pos) === CharacterCodes.asterisk && text.charCodeAt(pos + 1) !== CharacterCodes.slash;
let commentClosed = false;
let lastLineStart = tokenStart;
@@ -1994,6 +2004,10 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
}
}
if (isJSDoc && shouldParseJSDoc()) {
tokenFlags |= TokenFlags.PrecedingJSDocComment;
}
commentDirectives = appendIfCommentDirective(commentDirectives, text.slice(lastLineStart, pos), commentDirectiveRegExMultiLine, lastLineStart);
if (!commentClosed) {
@@ -2275,6 +2289,28 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
}
}
function shouldParseJSDoc() {
switch (jsDocParsingMode) {
case JSDocParsingMode.ParseAll:
return true;
case JSDocParsingMode.ParseNone:
return false;
}
if (scriptKind !== ScriptKind.TS && scriptKind !== ScriptKind.TSX) {
// If outside of TS, we need JSDoc to get any type info.
return true;
}
if (jsDocParsingMode === JSDocParsingMode.ParseForTypeInfo) {
// If we're in TS, but we don't need to produce reliable errors,
// we don't need to parse to find @see or @link.
return false;
}
return jsDocSeeOrLink.test(text.slice(fullStartPos, pos));
}
function reScanInvalidIdentifier(): SyntaxKind {
Debug.assert(token === SyntaxKind.Unknown, "'reScanInvalidIdentifier' should only be called when the current token is 'SyntaxKind.Unknown'.");
pos = tokenStart = fullStartPos;
@@ -2775,6 +2811,14 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
languageVariant = variant;
}
function setScriptKind(kind: ScriptKind) {
scriptKind = kind;
}
function setJSDocParsingMode(kind: JSDocParsingMode) {
jsDocParsingMode = kind;
}
function resetTokenState(position: number) {
Debug.assert(position >= 0);
pos = position;
+14 -30
View File
@@ -6,7 +6,6 @@ import {
append,
ArrayBindingElement,
arrayFrom,
AssertClause,
BindingElement,
BindingName,
BindingPattern,
@@ -70,7 +69,7 @@ import {
getOutputPathsFor,
getParseTreeNode,
getRelativePathToDirectoryOrUrl,
getResolutionModeOverrideForClause,
getResolutionModeOverride,
getResolvedExternalModuleName,
getSetAccessorValueParameter,
getSourceFileOfNode,
@@ -86,6 +85,7 @@ import {
hasSyntacticModifier,
HeritageClause,
Identifier,
ImportAttributes,
ImportDeclaration,
ImportEqualsDeclaration,
ImportTypeNode,
@@ -95,16 +95,15 @@ import {
isAnyImportSyntax,
isArray,
isArrayBindingElement,
isBinaryExpression,
isBindingElement,
isBindingPattern,
isClassDeclaration,
isClassElement,
isComputedPropertyName,
isDeclaration,
isElementAccessExpression,
isEntityName,
isEntityNameExpression,
isExpandoPropertyDeclaration,
isExportAssignment,
isExportDeclaration,
isExpressionWithTypeArguments,
@@ -131,10 +130,8 @@ import {
isMethodSignature,
isModifier,
isModuleDeclaration,
isNightly,
isOmittedExpression,
isPrivateIdentifier,
isPropertyAccessExpression,
isPropertySignature,
isSemicolonClassElement,
isSetAccessorDeclaration,
@@ -314,7 +311,6 @@ export function transformDeclarations(context: TransformationContext) {
trackExternalModuleSymbolOfImportTypeNode,
reportNonlocalAugmentation,
reportNonSerializableProperty,
reportImportTypeNodeResolutionModeOverride,
};
let errorNameNode: DeclarationName | undefined;
let errorFallbackNode: Declaration | undefined;
@@ -458,12 +454,6 @@ export function transformDeclarations(context: TransformationContext) {
}
}
function reportImportTypeNodeResolutionModeOverride() {
if (!isNightly() && (errorNameNode || errorFallbackNode)) {
context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_type_of_this_expression_cannot_be_named_without_a_resolution_mode_assertion_which_is_an_unstable_feature_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next));
}
}
function transformDeclarationsForJS(sourceFile: SourceFile, bundled?: boolean) {
const oldDiag = getSymbolAccessibilityDiagnostic;
getSymbolAccessibilityDiagnostic = s => (s.errorNode && canProduceDiagnostics(s.errorNode) ? createGetSymbolAccessibilityDiagnosticForNode(s.errorNode)(s) : ({
@@ -987,7 +977,7 @@ export function transformDeclarations(context: TransformationContext) {
decl.modifiers,
decl.importClause,
rewriteModuleSpecifier(decl, decl.moduleSpecifier),
getResolutionModeOverrideForClauseInNightly(decl.assertClause),
tryGetResolutionModeOverride(decl.attributes),
);
}
// The `importClause` visibility corresponds to the default's visibility.
@@ -1004,7 +994,7 @@ export function transformDeclarations(context: TransformationContext) {
/*namedBindings*/ undefined,
),
rewriteModuleSpecifier(decl, decl.moduleSpecifier),
getResolutionModeOverrideForClauseInNightly(decl.assertClause),
tryGetResolutionModeOverride(decl.attributes),
);
}
if (decl.importClause.namedBindings.kind === SyntaxKind.NamespaceImport) {
@@ -1020,7 +1010,7 @@ export function transformDeclarations(context: TransformationContext) {
namedBindings,
),
rewriteModuleSpecifier(decl, decl.moduleSpecifier),
getResolutionModeOverrideForClauseInNightly(decl.assertClause),
tryGetResolutionModeOverride(decl.attributes),
) : undefined;
}
// Named imports (optionally with visible default)
@@ -1036,7 +1026,7 @@ export function transformDeclarations(context: TransformationContext) {
bindingList && bindingList.length ? factory.updateNamedImports(decl.importClause.namedBindings, bindingList) : undefined,
),
rewriteModuleSpecifier(decl, decl.moduleSpecifier),
getResolutionModeOverrideForClauseInNightly(decl.assertClause),
tryGetResolutionModeOverride(decl.attributes),
);
}
// Augmentation of export depends on import
@@ -1046,21 +1036,15 @@ export function transformDeclarations(context: TransformationContext) {
decl.modifiers,
/*importClause*/ undefined,
rewriteModuleSpecifier(decl, decl.moduleSpecifier),
getResolutionModeOverrideForClauseInNightly(decl.assertClause),
tryGetResolutionModeOverride(decl.attributes),
);
}
// Nothing visible
}
function getResolutionModeOverrideForClauseInNightly(assertClause: AssertClause | undefined) {
const mode = getResolutionModeOverrideForClause(assertClause);
if (mode !== undefined) {
if (!isNightly()) {
context.addDiagnostic(createDiagnosticForNode(assertClause!, Diagnostics.resolution_mode_assertions_are_unstable_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next));
}
return assertClause;
}
return undefined;
function tryGetResolutionModeOverride(node: ImportAttributes | undefined) {
const mode = getResolutionModeOverride(node);
return node && mode !== undefined ? node : undefined;
}
function transformAndReplaceLatePaintedStatements(statements: NodeArray<Statement>): NodeArray<Statement> {
@@ -1331,7 +1315,7 @@ export function transformDeclarations(context: TransformationContext) {
return cleanup(factory.updateImportTypeNode(
input,
factory.updateLiteralTypeNode(input.argument, rewriteModuleSpecifier(input, input.argument.literal)),
input.assertions,
input.attributes,
input.qualifier,
visitNodes(input.typeArguments, visitDeclarationSubtree, isTypeNode),
input.isTypeOf,
@@ -1393,7 +1377,7 @@ export function transformDeclarations(context: TransformationContext) {
input.isTypeOnly,
input.exportClause,
rewriteModuleSpecifier(input, input.moduleSpecifier),
getResolutionModeOverrideForClause(input.assertClause) ? input.assertClause : undefined,
tryGetResolutionModeOverride(input.attributes),
);
}
case SyntaxKind.ExportAssignment: {
@@ -1540,7 +1524,7 @@ export function transformDeclarations(context: TransformationContext) {
fakespace.symbol = props[0].parent!;
const exportMappings: [Identifier, string][] = [];
let declarations: (VariableStatement | ExportDeclaration)[] = mapDefined(props, p => {
if (!p.valueDeclaration || !(isPropertyAccessExpression(p.valueDeclaration) || isElementAccessExpression(p.valueDeclaration) || isBinaryExpression(p.valueDeclaration))) {
if (!isExpandoPropertyDeclaration(p.valueDeclaration)) {
return undefined;
}
const nameStr = unescapeLeadingUnderscores(p.escapedName);
+1 -1
View File
@@ -170,7 +170,7 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B
for (const [importSource, importSpecifiersMap] of arrayFrom(currentFileState.utilizedImplicitRuntimeImports.entries())) {
if (isExternalModule(node)) {
// Add `import` statement
const importStatement = factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, factory.createNamedImports(arrayFrom(importSpecifiersMap.values()))), factory.createStringLiteral(importSource), /*assertClause*/ undefined);
const importStatement = factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, factory.createNamedImports(arrayFrom(importSpecifiersMap.values()))), factory.createStringLiteral(importSource), /*attributes*/ undefined);
setParentRecursive(importStatement, /*incremental*/ false);
statements = insertStatementAfterCustomPrologue(statements.slice(), importStatement);
}
@@ -159,6 +159,7 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S
]),
),
factory.createStringLiteral("module"),
/*attributes*/ undefined,
);
const requireHelperName = factory.createUniqueName("__require", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel);
const requireStatement = factory.createVariableStatement(
@@ -265,7 +266,7 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S
),
),
node.moduleSpecifier,
node.assertClause,
node.attributes,
);
setOriginalNode(importDecl, node.exportClause);
+3 -3
View File
@@ -2227,7 +2227,7 @@ export function transformTypeScript(context: TransformationContext) {
/*modifiers*/ undefined,
importClause,
node.moduleSpecifier,
node.assertClause,
node.attributes,
)
: undefined;
}
@@ -2323,7 +2323,7 @@ export function transformTypeScript(context: TransformationContext) {
node.isTypeOnly,
exportClause,
node.moduleSpecifier,
node.assertClause,
node.attributes,
)
: undefined;
}
@@ -2393,7 +2393,7 @@ export function transformTypeScript(context: TransformationContext) {
/*modifiers*/ undefined,
/*importClause*/ undefined,
node.moduleReference.expression,
/*assertClause*/ undefined,
/*attributes*/ undefined,
),
node,
),
+1 -2
View File
@@ -4,8 +4,7 @@
"types": ["node"]
},
"references": [
],
"references": [],
"include": ["**/*"]
}
+116 -37
View File
@@ -1,6 +1,5 @@
import {
BaseNodeFactory,
CheckMode,
CreateSourceFileOptions,
EmitHelperFactory,
GetCanonicalFileName,
@@ -376,9 +375,12 @@ export const enum SyntaxKind {
DefaultClause,
HeritageClause,
CatchClause,
AssertClause,
AssertEntry,
ImportTypeAssertionContainer,
ImportAttributes,
ImportAttribute,
/** @deprecated */ AssertClause = ImportAttributes,
/** @deprecated */ AssertEntry = ImportAttribute,
/** @deprecated */ ImportTypeAssertionContainer,
// Property assignments
PropertyAssignment,
@@ -1129,6 +1131,8 @@ export type HasChildren =
| ImportDeclaration
| AssertClause
| AssertEntry
| ImportAttributes
| ImportAttribute
| ImportClause
| NamespaceImport
| NamespaceExport
@@ -2141,10 +2145,11 @@ export interface KeywordTypeNode<TKind extends KeywordTypeSyntaxKind = KeywordTy
readonly kind: TKind;
}
/** @deprecated */
export interface ImportTypeAssertionContainer extends Node {
readonly kind: SyntaxKind.ImportTypeAssertionContainer;
readonly parent: ImportTypeNode;
readonly assertClause: AssertClause;
/** @deprecated */ readonly assertClause: AssertClause;
readonly multiLine?: boolean;
}
@@ -2152,7 +2157,8 @@ export interface ImportTypeNode extends NodeWithTypeArguments {
readonly kind: SyntaxKind.ImportType;
readonly isTypeOf: boolean;
readonly argument: TypeNode;
readonly assertions?: ImportTypeAssertionContainer;
/** @deprecated */ readonly assertions?: ImportTypeAssertionContainer;
readonly attributes?: ImportAttributes;
readonly qualifier?: EntityName;
}
@@ -3602,7 +3608,8 @@ export interface ImportDeclaration extends Statement {
readonly importClause?: ImportClause;
/** If this is not a StringLiteral it will be a grammar error. */
readonly moduleSpecifier: Expression;
readonly assertClause?: AssertClause;
/** @deprecated */ readonly assertClause?: AssertClause;
readonly attributes?: ImportAttributes;
}
export type NamedImportBindings =
@@ -3627,19 +3634,29 @@ export interface ImportClause extends NamedDeclaration {
readonly namedBindings?: NamedImportBindings;
}
export type AssertionKey = Identifier | StringLiteral;
/** @deprecated */
export type AssertionKey = ImportAttributeName;
export interface AssertEntry extends Node {
readonly kind: SyntaxKind.AssertEntry;
readonly parent: AssertClause;
readonly name: AssertionKey;
/** @deprecated */
export type AssertEntry = ImportAttribute;
/** @deprecated */
export type AssertClause = ImportAttributes;
export type ImportAttributeName = Identifier | StringLiteral;
export interface ImportAttribute extends Node {
readonly kind: SyntaxKind.ImportAttribute;
readonly parent: ImportAttributes;
readonly name: ImportAttributeName;
readonly value: Expression;
}
export interface AssertClause extends Node {
readonly kind: SyntaxKind.AssertClause;
export interface ImportAttributes extends Node {
readonly token: SyntaxKind.WithKeyword | SyntaxKind.AssertKeyword;
readonly kind: SyntaxKind.ImportAttributes;
readonly parent: ImportDeclaration | ExportDeclaration;
readonly elements: NodeArray<AssertEntry>;
readonly elements: NodeArray<ImportAttribute>;
readonly multiLine?: boolean;
}
@@ -3672,7 +3689,8 @@ export interface ExportDeclaration extends DeclarationStatement, JSDocContainer
readonly exportClause?: NamedExportBindings;
/** If this is not a StringLiteral it will be a grammar error. */
readonly moduleSpecifier?: Expression;
readonly assertClause?: AssertClause;
/** @deprecated */ readonly assertClause?: AssertClause;
readonly attributes?: ImportAttributes;
}
export interface NamedImports extends Node {
@@ -4277,11 +4295,6 @@ export interface SourceFile extends Declaration, LocalsContainer {
/** @internal */ classifiableNames?: ReadonlySet<__String>;
// Comments containing @ts-* directives, in order.
/** @internal */ commentDirectives?: CommentDirective[];
// Stores a mapping 'external module reference text' -> 'resolved file name' | undefined
// It is used to resolve module names in the checker.
// Content of this field should never be used directly - use getResolvedModuleFileName/setResolvedModuleFileName functions instead
/** @internal */ resolvedModules?: ModeAwareCache<ResolvedModuleWithFailedLookupLocations>;
/** @internal */ resolvedTypeReferenceDirectiveNames?: ModeAwareCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>;
/** @internal */ imports: readonly StringLiteralLike[];
// Identifier only if `declare global`
/** @internal */ moduleAugmentations: readonly (StringLiteral | Identifier)[];
@@ -4297,6 +4310,8 @@ export interface SourceFile extends Declaration, LocalsContainer {
/** @internal */ exportedModulesFromDeclarationEmit?: ExportedModulesFromDeclarationEmit;
/** @internal */ endFlowNode?: FlowNode;
/** @internal */ jsDocParsingMode?: JSDocParsingMode;
}
/** @internal */
@@ -4650,6 +4665,25 @@ export interface Program extends ScriptReferenceHost {
/** @internal */
getFilesByNameMap(): Map<string, SourceFile | false | undefined>;
/** @internal */
resolvedModules: Map<Path, ModeAwareCache<ResolvedModuleWithFailedLookupLocations>> | undefined;
/** @internal */
resolvedTypeReferenceDirectiveNames: Map<Path, ModeAwareCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>> | undefined;
/** @internal */
getResolvedModule(f: SourceFile, moduleName: string, mode: ResolutionMode): ResolvedModuleWithFailedLookupLocations | undefined;
/** @internal */
getResolvedTypeReferenceDirective(f: SourceFile, typeDirectiveName: string, mode: ResolutionMode): ResolvedTypeReferenceDirectiveWithFailedLookupLocations | undefined;
/** @internal */
forEachResolvedModule(
callback: (resolution: ResolvedModuleWithFailedLookupLocations, moduleName: string, mode: ResolutionMode, filePath: Path) => void,
file?: SourceFile,
): void;
/** @internal */
forEachResolvedTypeReferenceDirective(
callback: (resolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations, moduleName: string, mode: ResolutionMode, filePath: Path) => void,
file?: SourceFile,
): void;
/**
* Emits the JavaScript and declaration files. If targetSourceFile is not specified, then
* the JavaScript and declaration files will be produced for all the files in this program.
@@ -4866,6 +4900,8 @@ export interface TypeCheckerHost extends ModuleSpecifierResolutionHost {
getProjectReferenceRedirect(fileName: string): string | undefined;
isSourceOfProjectReferenceRedirect(fileName: string): boolean;
getResolvedModule(f: SourceFile, moduleName: string, mode: ResolutionMode): ResolvedModuleWithFailedLookupLocations | undefined;
readonly redirectTargetsMap: RedirectTargetsMap;
typesPackageExists(packageName: string): boolean;
@@ -4992,7 +5028,7 @@ export interface TypeChecker {
*/
getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[], argumentCount?: number): Signature | undefined;
/** @internal */ getResolvedSignatureForSignatureHelp(node: CallLikeExpression, candidatesOutArray?: Signature[], argumentCount?: number): Signature | undefined;
/** @internal */ getResolvedSignatureForStringLiteralCompletions(call: CallLikeExpression, editingArgument: Node, candidatesOutArray: Signature[], checkMode?: CheckMode): Signature | undefined;
/** @internal */ getCandidateSignaturesForStringLiteralCompletions(call: CallLikeExpression, editingArgument: Node): Signature[];
/** @internal */ getExpandedParameters(sig: Signature): readonly (readonly Symbol[])[];
/** @internal */ hasEffectiveRestParameter(sig: Signature): boolean;
/** @internal */ containsArgumentsReference(declaration: SignatureDeclaration): boolean;
@@ -6119,6 +6155,7 @@ export interface Type {
// Intrinsic types (TypeFlags.Intrinsic)
export interface IntrinsicType extends Type {
intrinsicName: string; // Name of intrinsic type
debugIntrinsicName: string | undefined;
objectFlags: ObjectFlags;
}
@@ -6204,6 +6241,8 @@ export const enum ObjectFlags {
RequiresWidening = ContainsWideningType | ContainsObjectOrArrayLiteral,
/** @internal */
PropagatingFlags = ContainsWideningType | ContainsObjectOrArrayLiteral | NonInferrableType,
/** @internal */
InstantiatedMapped = Mapped | Instantiated,
// Object flags that uniquely identify the kind of ObjectType
/** @internal */
ObjectTypeKindMask = ClassOrInterface | Reference | Tuple | Anonymous | Mapped | ReverseMapped | EvolvingArray,
@@ -6673,7 +6712,6 @@ export interface Signature {
declaration?: SignatureDeclaration | JSDocSignature; // Originating declaration
typeParameters?: readonly TypeParameter[]; // Type parameters (undefined if non-generic)
parameters: readonly Symbol[]; // Parameters
/** @internal */
thisParameter?: Symbol; // symbol of this-type parameter
/** @internal */
// See comment in `instantiateSignature` for why these are set lazily.
@@ -7344,6 +7382,7 @@ export interface CommandLineOptionBase {
showInSimplifiedHelpView?: boolean;
category?: DiagnosticMessage;
strictFlag?: true; // true if the option is one of the flag under strict
allowJsFlag?: true;
affectsSourceFile?: true; // true if we should recreate SourceFiles after this option changes
affectsModuleResolution?: true; // currently same effect as `affectsSourceFile`
affectsBindDiagnostics?: true; // true if this affects binding (currently same effect as `affectsSourceFile`)
@@ -7778,6 +7817,8 @@ export interface CompilerHost extends ModuleResolutionHost {
// For testing:
/** @internal */ storeFilesChangingSignatureDuringEmit?: boolean;
/** @internal */ getBuildInfo?(fileName: string, configFilePath: string | undefined): BuildInfo | undefined;
jsDocParsingMode?: JSDocParsingMode;
}
/** true if --out otherwise source file name *
@@ -8085,6 +8126,9 @@ export interface SourceFileMayBeEmittedHost {
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
getResolvedProjectReferenceToRedirect(fileName: string): ResolvedProjectReference | undefined;
isSourceOfProjectReferenceRedirect(fileName: string): boolean;
getCurrentDirectory(): string;
getCanonicalFileName: GetCanonicalFileName;
useCaseSensitiveFileNames(): boolean;
}
/** @internal */
@@ -8393,8 +8437,8 @@ export interface NodeFactory {
updateConditionalTypeNode(node: ConditionalTypeNode, checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode;
createInferTypeNode(typeParameter: TypeParameterDeclaration): InferTypeNode;
updateInferTypeNode(node: InferTypeNode, typeParameter: TypeParameterDeclaration): InferTypeNode;
createImportTypeNode(argument: TypeNode, assertions?: ImportTypeAssertionContainer, qualifier?: EntityName, typeArguments?: readonly TypeNode[], isTypeOf?: boolean): ImportTypeNode;
updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, assertions: ImportTypeAssertionContainer | undefined, qualifier: EntityName | undefined, typeArguments: readonly TypeNode[] | undefined, isTypeOf?: boolean): ImportTypeNode;
createImportTypeNode(argument: TypeNode, attributes?: ImportAttributes, qualifier?: EntityName, typeArguments?: readonly TypeNode[], isTypeOf?: boolean): ImportTypeNode;
updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, attributes: ImportAttributes | undefined, qualifier: EntityName | undefined, typeArguments: readonly TypeNode[] | undefined, isTypeOf?: boolean): ImportTypeNode;
createParenthesizedType(type: TypeNode): ParenthesizedTypeNode;
updateParenthesizedType(node: ParenthesizedTypeNode, type: TypeNode): ParenthesizedTypeNode;
createThisTypeNode(): ThisTypeNode;
@@ -8574,16 +8618,21 @@ export interface NodeFactory {
updateNamespaceExportDeclaration(node: NamespaceExportDeclaration, name: Identifier): NamespaceExportDeclaration;
createImportEqualsDeclaration(modifiers: readonly ModifierLike[] | undefined, isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
updateImportEqualsDeclaration(node: ImportEqualsDeclaration, modifiers: readonly ModifierLike[] | undefined, isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
createImportDeclaration(modifiers: readonly ModifierLike[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, assertClause?: AssertClause): ImportDeclaration;
updateImportDeclaration(node: ImportDeclaration, modifiers: readonly ModifierLike[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, assertClause: AssertClause | undefined): ImportDeclaration;
createImportDeclaration(modifiers: readonly ModifierLike[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, attributes?: ImportAttributes): ImportDeclaration;
updateImportDeclaration(node: ImportDeclaration, modifiers: readonly ModifierLike[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, attributes: ImportAttributes | undefined): ImportDeclaration;
createImportClause(isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause;
updateImportClause(node: ImportClause, isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause;
createAssertClause(elements: NodeArray<AssertEntry>, multiLine?: boolean): AssertClause;
updateAssertClause(node: AssertClause, elements: NodeArray<AssertEntry>, multiLine?: boolean): AssertClause;
createAssertEntry(name: AssertionKey, value: Expression): AssertEntry;
updateAssertEntry(node: AssertEntry, name: AssertionKey, value: Expression): AssertEntry;
createImportTypeAssertionContainer(clause: AssertClause, multiLine?: boolean): ImportTypeAssertionContainer;
updateImportTypeAssertionContainer(node: ImportTypeAssertionContainer, clause: AssertClause, multiLine?: boolean): ImportTypeAssertionContainer;
/** @deprecated */ createAssertClause(elements: NodeArray<AssertEntry>, multiLine?: boolean): AssertClause;
/** @deprecated */ updateAssertClause(node: AssertClause, elements: NodeArray<AssertEntry>, multiLine?: boolean): AssertClause;
/** @deprecated */ createAssertEntry(name: AssertionKey, value: Expression): AssertEntry;
/** @deprecated */ updateAssertEntry(node: AssertEntry, name: AssertionKey, value: Expression): AssertEntry;
/** @deprecated */ createImportTypeAssertionContainer(clause: AssertClause, multiLine?: boolean): ImportTypeAssertionContainer;
/** @deprecated */ updateImportTypeAssertionContainer(node: ImportTypeAssertionContainer, clause: AssertClause, multiLine?: boolean): ImportTypeAssertionContainer;
createImportAttributes(elements: NodeArray<ImportAttribute>, multiLine?: boolean): ImportAttributes;
/** @internal */ createImportAttributes(elements: NodeArray<ImportAttribute>, multiLine?: boolean, token?: ImportAttributes["token"]): ImportAttributes;
updateImportAttributes(node: ImportAttributes, elements: NodeArray<ImportAttribute>, multiLine?: boolean): ImportAttributes;
createImportAttribute(name: ImportAttributeName, value: Expression): ImportAttribute;
updateImportAttribute(node: ImportAttribute, name: ImportAttributeName, value: Expression): ImportAttribute;
createNamespaceImport(name: Identifier): NamespaceImport;
updateNamespaceImport(node: NamespaceImport, name: Identifier): NamespaceImport;
createNamespaceExport(name: Identifier): NamespaceExport;
@@ -8594,8 +8643,8 @@ export interface NodeFactory {
updateImportSpecifier(node: ImportSpecifier, isTypeOnly: boolean, propertyName: Identifier | undefined, name: Identifier): ImportSpecifier;
createExportAssignment(modifiers: readonly ModifierLike[] | undefined, isExportEquals: boolean | undefined, expression: Expression): ExportAssignment;
updateExportAssignment(node: ExportAssignment, modifiers: readonly ModifierLike[] | undefined, expression: Expression): ExportAssignment;
createExportDeclaration(modifiers: readonly ModifierLike[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression, assertClause?: AssertClause): ExportDeclaration;
updateExportDeclaration(node: ExportDeclaration, modifiers: readonly ModifierLike[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier: Expression | undefined, assertClause: AssertClause | undefined): ExportDeclaration;
createExportDeclaration(modifiers: readonly ModifierLike[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression, attributes?: ImportAttributes): ExportDeclaration;
updateExportDeclaration(node: ExportDeclaration, modifiers: readonly ModifierLike[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier: Expression | undefined, attributes: ImportAttributes | undefined): ExportDeclaration;
createNamedExports(elements: readonly ExportSpecifier[]): NamedExports;
updateNamedExports(node: NamedExports, elements: readonly ExportSpecifier[]): NamedExports;
createExportSpecifier(isTypeOnly: boolean, propertyName: string | Identifier | undefined, name: string | Identifier): ExportSpecifier;
@@ -9450,6 +9499,7 @@ export interface PrinterOptions {
/** @internal */ sourceMap?: boolean;
/** @internal */ inlineSourceMap?: boolean;
/** @internal */ inlineSources?: boolean;
/** @internal*/ omitBraceSourceMapPositions?: boolean;
/** @internal */ extendedDiagnostics?: boolean;
/** @internal */ onlyPrintJsDocStyle?: boolean;
/** @internal */ neverAsciiEscape?: boolean;
@@ -9631,7 +9681,6 @@ export interface SymbolTracker {
trackExternalModuleSymbolOfImportTypeNode?(symbol: Symbol): void;
reportNonlocalAugmentation?(containingFile: SourceFile, parentSymbol: Symbol, augmentingSymbol: Symbol): void;
reportNonSerializableProperty?(propertyName: string): void;
reportImportTypeNodeResolutionModeOverride?(): void;
}
export interface TextSpan {
@@ -9724,7 +9773,8 @@ export const enum ListFormat {
ObjectBindingPatternElements = SingleLine | AllowTrailingComma | SpaceBetweenBraces | CommaDelimited | SpaceBetweenSiblings | NoSpaceIfEmpty,
ArrayBindingPatternElements = SingleLine | AllowTrailingComma | CommaDelimited | SpaceBetweenSiblings | NoSpaceIfEmpty,
ObjectLiteralExpressionProperties = PreserveLines | CommaDelimited | SpaceBetweenSiblings | SpaceBetweenBraces | Indented | Braces | NoSpaceIfEmpty,
ImportClauseEntries = PreserveLines | CommaDelimited | SpaceBetweenSiblings | SpaceBetweenBraces | Indented | Braces | NoSpaceIfEmpty,
ImportAttributes = PreserveLines | CommaDelimited | SpaceBetweenSiblings | SpaceBetweenBraces | Indented | Braces | NoSpaceIfEmpty,
/** @deprecated */ ImportClauseEntries = ImportAttributes,
ArrayLiteralExpressionElements = PreserveLines | CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | Indented | SquareBrackets,
CommaListElements = CommaDelimited | SpaceBetweenSiblings | SingleLine,
CallExpressionArguments = CommaDelimited | SpaceBetweenSiblings | SingleLine | Parenthesis,
@@ -9842,6 +9892,34 @@ export const commentPragmas = {
},
} as const;
export const enum JSDocParsingMode {
/**
* Always parse JSDoc comments and include them in the AST.
*
* This is the default if no mode is provided.
*/
ParseAll,
/**
* Never parse JSDoc comments, mo matter the file type.
*/
ParseNone,
/**
* Parse only JSDoc comments which are needed to provide correct type errors.
*
* This will always parse JSDoc in non-TS files, but only parse JSDoc comments
* containing `@see` and `@link` in TS files.
*/
ParseForTypeErrors,
/**
* Parse only JSDoc comments which are needed to provide correct type info.
*
* This will always parse JSDoc in non-TS files, but never in TS files.
*
* Note: Do not use this mode if you require accurate type errors; use {@link ParseForTypeErrors} instead.
*/
ParseForTypeInfo,
}
/** @internal */
export type PragmaArgTypeMaybeCapture<TDesc> = TDesc extends { captureSpan: true; } ? { value: string; pos: number; end: number; } : string;
@@ -9936,6 +10014,7 @@ export interface UserPreferences {
readonly organizeImportsNumericCollation?: boolean;
readonly organizeImportsAccentCollation?: boolean;
readonly organizeImportsCaseFirst?: "upper" | "lower" | false;
readonly excludeLibrarySymbolsInNavTo?: boolean;
}
/** Represents a bigint literal value without requiring bigint support */
+78 -61
View File
@@ -62,6 +62,7 @@ import {
CommentDirectivesMap,
CommentDirectiveType,
CommentRange,
comparePaths,
compareStringsCaseSensitive,
compareValues,
Comparison,
@@ -78,7 +79,6 @@ import {
contains,
containsPath,
createGetCanonicalFileName,
createModeAwareCache,
createMultiMap,
createScanner,
createTextSpan,
@@ -162,6 +162,7 @@ import {
GetCanonicalFileName,
getCombinedModifierFlags,
getCombinedNodeFlags,
getCommonSourceDirectory,
getContainerFlags,
getDirectoryPath,
getJSDocAugmentsTag,
@@ -193,6 +194,7 @@ import {
getPathComponents,
getPathFromPathComponents,
getRelativePathToDirectoryOrUrl,
getResolutionModeOverride,
getRootLength,
getSnippetElement,
getStringComparer,
@@ -552,7 +554,6 @@ import {
VariableDeclarationList,
VariableLikeDeclaration,
VariableStatement,
version,
WhileStatement,
WithStatement,
WrappedExpression,
@@ -742,34 +743,6 @@ export function getFullWidth(node: Node) {
return node.end - node.pos;
}
/** @internal */
export function getResolvedModule(sourceFile: SourceFile | undefined, moduleNameText: string, mode: ResolutionMode): ResolvedModuleFull | undefined {
return sourceFile?.resolvedModules?.get(moduleNameText, mode)?.resolvedModule;
}
/** @internal */
export function setResolvedModule(sourceFile: SourceFile, moduleNameText: string, resolvedModule: ResolvedModuleWithFailedLookupLocations, mode: ResolutionMode): void {
if (!sourceFile.resolvedModules) {
sourceFile.resolvedModules = createModeAwareCache();
}
sourceFile.resolvedModules.set(moduleNameText, mode, resolvedModule);
}
/** @internal */
export function setResolvedTypeReferenceDirective(sourceFile: SourceFile, typeReferenceDirectiveName: string, resolvedTypeReferenceDirective: ResolvedTypeReferenceDirectiveWithFailedLookupLocations, mode: ResolutionMode): void {
if (!sourceFile.resolvedTypeReferenceDirectiveNames) {
sourceFile.resolvedTypeReferenceDirectiveNames = createModeAwareCache();
}
sourceFile.resolvedTypeReferenceDirectiveNames.set(typeReferenceDirectiveName, mode, resolvedTypeReferenceDirective);
}
/** @internal */
export function getResolvedTypeReferenceDirective(sourceFile: SourceFile | undefined, typeReferenceDirectiveName: string, mode: ResolutionMode): ResolvedTypeReferenceDirective | undefined {
return sourceFile?.resolvedTypeReferenceDirectiveNames?.get(typeReferenceDirectiveName, mode)?.resolvedTypeReferenceDirective;
}
/** @internal */
export function projectReferenceIsEqualTo(oldRef: ProjectReference, newRef: ProjectReference) {
return oldRef.path === newRef.path &&
@@ -793,7 +766,7 @@ export function moduleResolutionIsEqualTo(oldResolution: ResolvedModuleWithFaile
/** @internal */
export function createModuleNotFoundChain(sourceFile: SourceFile, host: TypeCheckerHost, moduleReference: string, mode: ResolutionMode, packageName: string) {
const node10Result = sourceFile.resolvedModules?.get(moduleReference, mode)?.node10Result;
const node10Result = host.getResolvedModule(sourceFile, moduleReference, mode)?.node10Result;
const result = node10Result
? chainDiagnosticMessages(
/*details*/ undefined,
@@ -855,7 +828,7 @@ export function hasChangesInResolutions<K, V>(
names: readonly K[],
newSourceFile: SourceFile,
newResolutions: readonly V[],
oldResolutions: ModeAwareCache<V> | undefined,
getOldResolution: (name: string, mode: ResolutionMode) => V | undefined,
comparer: (oldResolution: V, newResolution: V) => boolean,
nameAndModeGetter: ResolutionNameAndModeGetter<K, SourceFile>,
): boolean {
@@ -866,7 +839,7 @@ export function hasChangesInResolutions<K, V>(
const entry = names[i];
const name = nameAndModeGetter.getName(entry);
const mode = nameAndModeGetter.getMode(entry, newSourceFile);
const oldResolution = oldResolutions && oldResolutions.get(name, mode);
const oldResolution = getOldResolution(name, mode);
const changed = oldResolution
? !newResolution || !comparer(oldResolution, newResolution)
: newResolution;
@@ -6002,11 +5975,6 @@ export function getIndentSize() {
return indentStrings[1].length;
}
/** @internal */
export function isNightly() {
return version.includes("-dev") || version.includes("-insiders");
}
/** @internal */
export function createTextWriter(newLine: string): EmitTextWriter {
// Why var? It avoids TDZ checks in the runtime which can be costly.
@@ -6368,13 +6336,31 @@ export function getSourceFilesToEmit(host: EmitHost, targetSourceFile?: SourceFi
*/
export function sourceFileMayBeEmitted(sourceFile: SourceFile, host: SourceFileMayBeEmittedHost, forceDtsEmit?: boolean) {
const options = host.getCompilerOptions();
return !(options.noEmitForJsFiles && isSourceFileJS(sourceFile)) &&
!sourceFile.isDeclarationFile &&
!host.isSourceFileFromExternalLibrary(sourceFile) &&
(forceDtsEmit || (
!(isJsonSourceFile(sourceFile) && host.getResolvedProjectReferenceToRedirect(sourceFile.fileName)) &&
!host.isSourceOfProjectReferenceRedirect(sourceFile.fileName)
));
// Js files are emitted only if option is enabled
if (options.noEmitForJsFiles && isSourceFileJS(sourceFile)) return false;
// Declaration files are not emitted
if (sourceFile.isDeclarationFile) return false;
// Source file from node_modules are not emitted
if (host.isSourceFileFromExternalLibrary(sourceFile)) return false;
// forcing dts emit => file needs to be emitted
if (forceDtsEmit) return true;
// Check other conditions for file emit
// Source files from referenced projects are not emitted
if (host.isSourceOfProjectReferenceRedirect(sourceFile.fileName)) return false;
// Any non json file should be emitted
if (!isJsonSourceFile(sourceFile)) return true;
if (host.getResolvedProjectReferenceToRedirect(sourceFile.fileName)) return false;
// Emit json file if outFile is specified
if (outFile(options)) return true;
// Json file is not emitted if outDir is not specified
if (!options.outDir) return false;
// Otherwise if rootDir or composite config file, we know common sourceDir and can check if file would be emitted in same location
if (options.rootDir || (options.composite && options.configFilePath)) {
const commonDir = getNormalizedAbsolutePath(getCommonSourceDirectory(options, () => [], host.getCurrentDirectory(), host.getCanonicalFileName), host.getCurrentDirectory());
const outputPath = getSourceFilePathInNewDirWorker(sourceFile.fileName, options.outDir, host.getCurrentDirectory(), commonDir, host.getCanonicalFileName);
if (comparePaths(sourceFile.fileName, outputPath, host.getCurrentDirectory(), !host.useCaseSensitiveFileNames()) === Comparison.EqualTo) return false;
}
return true;
}
/** @internal */
@@ -7239,8 +7225,8 @@ export function isRightSideOfQualifiedNameOrPropertyAccess(node: Node) {
/** @internal */
export function isRightSideOfAccessExpression(node: Node) {
return isPropertyAccessExpression(node.parent) && node.parent.name === node
|| isElementAccessExpression(node.parent) && node.parent.argumentExpression === node;
return !!node.parent && (isPropertyAccessExpression(node.parent) && node.parent.name === node
|| isElementAccessExpression(node.parent) && node.parent.argumentExpression === node);
}
/** @internal */
@@ -8764,7 +8750,9 @@ export function compilerOptionsAffectDeclarationPath(newOptions: CompilerOptions
/** @internal */
export function getCompilerOptionValue(options: CompilerOptions, option: CommandLineOption): unknown {
return option.strictFlag ? getStrictOptionValue(options, option.name as StrictOptionName) : options[option.name];
return option.strictFlag ? getStrictOptionValue(options, option.name as StrictOptionName) :
option.allowJsFlag ? getAllowJSCompilerOption(options) :
options[option.name];
}
/** @internal */
@@ -8809,9 +8797,15 @@ export function hasZeroOrOneAsteriskCharacter(str: string): boolean {
/** @internal */
export interface SymlinkedDirectory {
/** Matches the casing returned by `realpath`. Used to compute the `realpath` of children. */
/**
* Matches the casing returned by `realpath`. Used to compute the `realpath` of children.
* Always has trailing directory separator
*/
real: string;
/** toPath(real). Stored to avoid repeated recomputation. */
/**
* toPath(real). Stored to avoid repeated recomputation.
* Always has trailing directory separator
*/
realPath: Path;
}
@@ -8831,7 +8825,15 @@ export interface SymlinkCache {
* don't include automatic type reference directives. Must be called only when
* `hasProcessedResolutions` returns false (once per cache instance).
*/
setSymlinksFromResolutions(files: readonly SourceFile[], typeReferenceDirectives: ModeAwareCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>): void;
setSymlinksFromResolutions(
forEachResolvedModule: (
callback: (resolution: ResolvedModuleWithFailedLookupLocations, moduleName: string, mode: ResolutionMode, filePath: Path) => void,
) => void,
forEachResolvedTypeReferenceDirective: (
callback: (resolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations, moduleName: string, mode: ResolutionMode, filePath: Path) => void,
) => void,
typeReferenceDirectives: ModeAwareCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>,
): void;
/**
* @internal
* Whether `setSymlinksFromResolutions` has already been called.
@@ -8858,18 +8860,16 @@ export function createSymlinkCache(cwd: string, getCanonicalFileName: GetCanonic
if (!containsIgnoredPath(symlinkPath)) {
symlinkPath = ensureTrailingDirectorySeparator(symlinkPath);
if (real !== false && !symlinkedDirectories?.has(symlinkPath)) {
(symlinkedDirectoriesByRealpath ||= createMultiMap()).add(ensureTrailingDirectorySeparator(real.realPath), symlink);
(symlinkedDirectoriesByRealpath ||= createMultiMap()).add(real.realPath, symlink);
}
(symlinkedDirectories || (symlinkedDirectories = new Map())).set(symlinkPath, real);
}
},
setSymlinksFromResolutions(files, typeReferenceDirectives) {
setSymlinksFromResolutions(forEachResolvedModule, forEachResolvedTypeReferenceDirective, typeReferenceDirectives) {
Debug.assert(!hasProcessedResolutions);
hasProcessedResolutions = true;
for (const file of files) {
file.resolvedModules?.forEach(resolution => processResolution(this, resolution.resolvedModule));
file.resolvedTypeReferenceDirectiveNames?.forEach(resolution => processResolution(this, resolution.resolvedTypeReferenceDirective));
}
forEachResolvedModule(resolution => processResolution(this, resolution.resolvedModule));
forEachResolvedTypeReferenceDirective(resolution => processResolution(this, resolution.resolvedTypeReferenceDirective));
typeReferenceDirectives.forEach(resolution => processResolution(this, resolution.resolvedTypeReferenceDirective));
},
hasProcessedResolutions: () => hasProcessedResolutions,
@@ -8883,7 +8883,10 @@ export function createSymlinkCache(cwd: string, getCanonicalFileName: GetCanonic
if (commonResolved && commonOriginal) {
cache.setSymlinkedDirectory(
commonOriginal,
{ real: commonResolved, realPath: toPath(commonResolved, cwd, getCanonicalFileName) },
{
real: ensureTrailingDirectorySeparator(commonResolved),
realPath: ensureTrailingDirectorySeparator(toPath(commonResolved, cwd, getCanonicalFileName)),
},
);
}
}
@@ -10196,9 +10199,10 @@ export function isNumericLiteralName(name: string | __String) {
}
/** @internal */
export function createPropertyNameNodeForIdentifierOrLiteral(name: string, target: ScriptTarget, singleQuote?: boolean, stringNamed?: boolean) {
return isIdentifierText(name, target) ? factory.createIdentifier(name) :
!stringNamed && isNumericLiteralName(name) && +name >= 0 ? factory.createNumericLiteral(+name) :
export function createPropertyNameNodeForIdentifierOrLiteral(name: string, target: ScriptTarget, singleQuote: boolean, stringNamed: boolean, isMethod: boolean) {
const isMethodNamedNew = isMethod && name === "new";
return !isMethodNamedNew && isIdentifierText(name, target) ? factory.createIdentifier(name) :
!stringNamed && !isMethodNamedNew && isNumericLiteralName(name) && +name >= 0 ? factory.createNumericLiteral(+name) :
factory.createStringLiteral(name, !!singleQuote);
}
@@ -10432,3 +10436,16 @@ export function getPropertyNameFromType(type: StringLiteralType | NumberLiteralT
}
return Debug.fail();
}
/** @internal */
export function isExpandoPropertyDeclaration(declaration: Declaration | undefined): declaration is PropertyAccessExpression | ElementAccessExpression | BinaryExpression {
return !!declaration && (isPropertyAccessExpression(declaration) || isElementAccessExpression(declaration) || isBinaryExpression(declaration));
}
/** @internal */
export function hasResolutionModeOverride(node: ImportTypeNode | ImportDeclaration | ExportDeclaration | undefined) {
if (node === undefined) {
return false;
}
return !!getResolutionModeOverride(node.attributes);
}
+16 -6
View File
@@ -6,7 +6,6 @@ import {
ArrayBindingOrAssignmentElement,
ArrayBindingOrAssignmentPattern,
AssertionExpression,
AssertionKey,
AssignmentDeclarationKind,
AssignmentPattern,
AutoAccessorPropertyDeclaration,
@@ -92,6 +91,7 @@ import {
hasSyntacticModifier,
HasType,
Identifier,
ImportAttributeName,
ImportClause,
ImportEqualsDeclaration,
ImportSpecifier,
@@ -403,7 +403,7 @@ export function createTextChangeRange(span: TextSpan, newLength: number): TextCh
return { span, newLength };
}
export let unchangedTextChangeRange = createTextChangeRange(createTextSpan(0, 0), 0); // eslint-disable-line prefer-const
export const unchangedTextChangeRange = createTextChangeRange(createTextSpan(0, 0), 0);
/**
* Called to merge all the changes that occurred across several versions of a script snapshot
@@ -1518,14 +1518,14 @@ export function isTypeOnlyImportOrExportDeclaration(node: Node): node is TypeOnl
return isTypeOnlyImportDeclaration(node) || isTypeOnlyExportDeclaration(node);
}
export function isAssertionKey(node: Node): node is AssertionKey {
return isStringLiteral(node) || isIdentifier(node);
}
export function isStringTextContainingNode(node: Node): node is StringLiteral | TemplateLiteralToken {
return node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind);
}
export function isImportAttributeName(node: Node): node is ImportAttributeName {
return isStringLiteral(node) || isIdentifier(node);
}
// Identifiers
/** @internal */
@@ -1704,6 +1704,11 @@ export function isAutoAccessorPropertyDeclaration(node: Node): node is AutoAcces
return isPropertyDeclaration(node) && hasAccessorModifier(node);
}
/** @internal */
export function isClassFieldAndNotAutoAccessor(node: Node): boolean {
return node.parent && isClassLike(node.parent) && isPropertyDeclaration(node) && !hasAccessorModifier(node);
}
/** @internal */
export function isMethodOrAccessor(node: Node): node is MethodDeclaration | AccessorDeclaration {
switch (node.kind) {
@@ -1915,6 +1920,11 @@ export function isPropertyAccessOrQualifiedName(node: Node): node is PropertyAcc
|| kind === SyntaxKind.QualifiedName;
}
/** @internal */
export function isCallLikeOrFunctionLikeExpression(node: Node): node is CallLikeExpression | SignatureDeclaration {
return isCallLikeExpression(node) || isFunctionLike(node);
}
export function isCallLikeExpression(node: Node): node is CallLikeExpression {
switch (node.kind) {
case SyntaxKind.JsxOpeningElement:
+12 -12
View File
@@ -12,8 +12,6 @@ import {
isArray,
isArrayBindingElement,
isAssertClause,
isAssertEntry,
isAssertionKey,
isAssertsKeyword,
isAsteriskToken,
isAwaitKeyword,
@@ -42,9 +40,11 @@ import {
isHeritageClause,
isIdentifier,
isIdentifierOrThisTypeNode,
isImportAttribute,
isImportAttributeName,
isImportAttributes,
isImportClause,
isImportSpecifier,
isImportTypeAssertionContainer,
isJsxAttributeLike,
isJsxAttributeName,
isJsxAttributes,
@@ -894,7 +894,7 @@ const visitEachChildTable: VisitEachChildTable = {
return context.factory.updateImportTypeNode(
node,
Debug.checkDefined(nodeVisitor(node.argument, visitor, isTypeNode)),
nodeVisitor(node.assertions, visitor, isImportTypeAssertionContainer),
nodeVisitor(node.attributes, visitor, isImportAttributes),
nodeVisitor(node.qualifier, visitor, isEntityName),
nodesVisitor(node.typeArguments, visitor, isTypeNode),
node.isTypeOf,
@@ -1524,22 +1524,22 @@ const visitEachChildTable: VisitEachChildTable = {
nodesVisitor(node.modifiers, visitor, isModifierLike),
nodeVisitor(node.importClause, visitor, isImportClause),
Debug.checkDefined(nodeVisitor(node.moduleSpecifier, visitor, isExpression)),
nodeVisitor(node.assertClause, visitor, isAssertClause),
nodeVisitor(node.attributes, visitor, isImportAttributes),
);
},
[SyntaxKind.AssertClause]: function visitEachChildOfAssertClause(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) {
return context.factory.updateAssertClause(
[SyntaxKind.ImportAttributes]: function visitEachChildOfImportAttributes(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) {
return context.factory.updateImportAttributes(
node,
nodesVisitor(node.elements, visitor, isAssertEntry),
nodesVisitor(node.elements, visitor, isImportAttribute),
node.multiLine,
);
},
[SyntaxKind.AssertEntry]: function visitEachChildOfAssertEntry(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) {
return context.factory.updateAssertEntry(
[SyntaxKind.ImportAttribute]: function visitEachChildOfImportAttribute(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) {
return context.factory.updateImportAttribute(
node,
Debug.checkDefined(nodeVisitor(node.name, visitor, isAssertionKey)),
Debug.checkDefined(nodeVisitor(node.name, visitor, isImportAttributeName)),
Debug.checkDefined(nodeVisitor(node.value, visitor, isExpression)),
);
},
@@ -1598,7 +1598,7 @@ const visitEachChildTable: VisitEachChildTable = {
node.isTypeOnly,
nodeVisitor(node.exportClause, visitor, isNamedExportBindings),
nodeVisitor(node.moduleSpecifier, visitor, isExpression),
nodeVisitor(node.assertClause, visitor, isAssertClause),
nodeVisitor(node.attributes, visitor, isImportAttributes),
);
},
+2 -1
View File
@@ -442,7 +442,7 @@ export function getMatchedIncludeSpec(program: Program, fileName: string) {
export function fileIncludeReasonToDiagnostics(program: Program, reason: FileIncludeReason, fileNameConvertor?: (fileName: string) => string): DiagnosticMessageChain {
const options = program.getCompilerOptions();
if (isReferencedFile(reason)) {
const referenceLocation = getReferencedFileLocation(path => program.getSourceFileByPath(path), reason);
const referenceLocation = getReferencedFileLocation(program, reason);
const referenceText = isReferenceFileLocation(referenceLocation) ? referenceLocation.file.text.substring(referenceLocation.pos, referenceLocation.end) : `"${referenceLocation.text}"`;
let message: DiagnosticMessage;
Debug.assert(isReferenceFileLocation(referenceLocation) || reason.kind === FileIncludeKind.Import, "Only synthetic references are imports");
@@ -768,6 +768,7 @@ export function createCompilerHostFromProgramHost(host: ProgramHost<any>, getCom
createHash: maybeBind(host, host.createHash),
readDirectory: maybeBind(host, host.readDirectory),
storeFilesChangingSignatureDuringEmit: host.storeFilesChangingSignatureDuringEmit,
jsDocParsingMode: host.jsDocParsingMode,
};
return compilerHost;
}
+12 -2
View File
@@ -53,6 +53,7 @@ import {
isArray,
isIgnoredFileFromWildCardWatching,
isProgramUptoDate,
JSDocParsingMode,
MapLike,
maybeBind,
ModuleResolutionCache,
@@ -64,6 +65,7 @@ import {
perfLogger,
PollingInterval,
ProjectReference,
ResolutionCache,
ResolutionCacheHost,
ResolutionMode,
ResolvedModule,
@@ -254,6 +256,8 @@ export interface ProgramHost<T extends BuilderProgram> {
* Returns the module resolution cache used by a provided `resolveModuleNames` implementation so that any non-name module resolution operations (eg, package.json lookup) can reuse it
*/
getModuleResolutionCache?(): ModuleResolutionCache | undefined;
jsDocParsingMode?: JSDocParsingMode;
}
/**
* Internal interface used to wire emit through same host
@@ -338,6 +342,8 @@ export interface Watch<T> {
getCurrentProgram(): T;
/** Closes the watch */
close(): void;
/** @internal */
getResolutionCache(): ResolutionCache;
}
/**
@@ -549,8 +555,8 @@ export function createWatchProgram<T extends BuilderProgram>(host: WatchCompiler
if (configFileName) updateExtendedConfigFilesWatches(toPath(configFileName), compilerOptions, watchOptions, WatchType.ExtendedConfigFile);
return configFileName ?
{ getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, close } :
{ getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, updateRootFileNames, close };
{ getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, close, getResolutionCache } :
{ getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, updateRootFileNames, close, getResolutionCache };
function close() {
clearInvalidateResolutionsOfFailedLookupLocations();
@@ -590,6 +596,10 @@ export function createWatchProgram<T extends BuilderProgram>(host: WatchCompiler
}
}
function getResolutionCache() {
return resolutionCache;
}
function getCurrentBuilderProgram() {
return builderProgram;
}
+30 -2
View File
@@ -20,9 +20,11 @@ import {
FileWatcherCallback,
FileWatcherEventKind,
find,
getAllowJSCompilerOption,
getBaseFileName,
getDirectoryPath,
getNormalizedAbsolutePath,
getResolveJsonModule,
hasExtension,
identity,
insertSorted,
@@ -44,6 +46,7 @@ import {
removeIgnoredPath,
returnNoopFileWatcher,
returnTrue,
ScriptKind,
setSysLog,
SortedArray,
SortedReadonlyArray,
@@ -563,6 +566,7 @@ export interface IsIgnoredFileFromWildCardWatchingInput {
useCaseSensitiveFileNames: boolean;
writeLog: (s: string) => void;
toPath: (fileName: string) => Path;
getScriptKind?: (fileName: string) => ScriptKind;
}
/** @internal */
export function isIgnoredFileFromWildCardWatching({
@@ -577,6 +581,7 @@ export function isIgnoredFileFromWildCardWatching({
useCaseSensitiveFileNames,
writeLog,
toPath,
getScriptKind,
}: IsIgnoredFileFromWildCardWatchingInput): boolean {
const newPath = removeIgnoredPath(fileOrDirectoryPath);
if (!newPath) {
@@ -588,8 +593,12 @@ export function isIgnoredFileFromWildCardWatching({
if (fileOrDirectoryPath === watchedDirPath) return false;
// 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 (hasExtension(fileOrDirectoryPath) && !isSupportedSourceFileName(fileOrDirectory, options, extraFileExtensions)) {
if (
hasExtension(fileOrDirectoryPath) && !(
isSupportedSourceFileName(fileOrDirectory, options, extraFileExtensions) ||
isSupportedScriptKind()
)
) {
writeLog(`Project: ${configFileName} Detected file add/remove of non supported extension: ${fileOrDirectory}`);
return true;
}
@@ -634,6 +643,25 @@ export function isIgnoredFileFromWildCardWatching({
builderProgram.getState().fileInfos.has(file) :
!!find(program as readonly string[], rootFile => toPath(rootFile) === file);
}
function isSupportedScriptKind() {
if (!getScriptKind) return false;
const scriptKind = getScriptKind(fileOrDirectory);
switch (scriptKind) {
case ScriptKind.TS:
case ScriptKind.TSX:
case ScriptKind.Deferred:
case ScriptKind.External:
return true;
case ScriptKind.JS:
case ScriptKind.JSX:
return getAllowJSCompilerOption(options);
case ScriptKind.JSON:
return getResolveJsonModule(options);
case ScriptKind.Unknown:
return false;
}
}
}
function isBuilderProgram<T extends BuilderProgram>(program: Program | T): program is T {
@@ -57,6 +57,7 @@ import {
getNormalizedAbsolutePath,
isIncrementalCompilation,
isWatchSet,
JSDocParsingMode,
normalizePath,
optionDeclarations,
optionsForBuild,
@@ -789,6 +790,9 @@ function reportWatchModeWithoutSysSupport(sys: System, reportDiagnostic: Diagnos
return false;
}
// This could be inlined everywhere, but this is convenient for debugging and patching.
const defaultJSDocParsingMode = JSDocParsingMode.ParseForTypeErrors;
function performBuild(
sys: System,
cb: ExecuteCommandLineCallbacks,
@@ -839,6 +843,7 @@ function performBuild(
createBuilderStatusReporter(sys, shouldBePretty(sys, buildOptions)),
createWatchStatusReporter(sys, buildOptions),
);
buildHost.jsDocParsingMode = defaultJSDocParsingMode;
const solutionPerformance = enableSolutionPerformance(sys, buildOptions);
updateSolutionBuilderHost(sys, cb, buildHost, solutionPerformance);
const onWatchStatusChange = buildHost.onWatchStatusChange;
@@ -868,6 +873,7 @@ function performBuild(
createBuilderStatusReporter(sys, shouldBePretty(sys, buildOptions)),
createReportErrorSummary(sys, buildOptions),
);
buildHost.jsDocParsingMode = defaultJSDocParsingMode;
const solutionPerformance = enableSolutionPerformance(sys, buildOptions);
updateSolutionBuilderHost(sys, cb, buildHost, solutionPerformance);
const builder = createSolutionBuilder(buildHost, projects, buildOptions);
@@ -891,6 +897,7 @@ function performCompilation(
) {
const { fileNames, options, projectReferences } = config;
const host = createCompilerHostWorker(options, /*setParentNodes*/ undefined, sys);
host.jsDocParsingMode = defaultJSDocParsingMode;
const currentDirectory = host.getCurrentDirectory();
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames());
changeCompilerHostLikeToUseCache(host, fileName => toPath(fileName, currentDirectory, getCanonicalFileName));
@@ -924,6 +931,7 @@ function performIncrementalCompilation(
const { options, fileNames, projectReferences } = config;
enableStatisticsAndTracing(sys, options, /*isBuildMode*/ false);
const host = createIncrementalCompilerHost(options, sys);
host.jsDocParsingMode = defaultJSDocParsingMode;
const exitStatus = ts_performIncrementalCompilation({
host,
system: sys,
@@ -975,6 +983,7 @@ function updateWatchCompilationHost(
cb: ExecuteCommandLineCallbacks,
watchCompilerHost: WatchCompilerHost<EmitAndSemanticDiagnosticsBuilderProgram>,
) {
watchCompilerHost.jsDocParsingMode = defaultJSDocParsingMode;
updateCreateProgram(sys, watchCompilerHost, /*isBuildMode*/ false);
const emitFilesUsingBuilder = watchCompilerHost.afterProgramCreate!; // TODO: GH#18217
watchCompilerHost.afterProgramCreate = builderProgram => {
+18 -7
View File
@@ -314,15 +314,25 @@ export class SessionClient implements LanguageService {
return notImplemented();
}
getNavigateToItems(searchValue: string): NavigateToItem[] {
getNavigateToItems(searchValue: string, maxResultCount: number, file: string | undefined, _excludeDtsFiles: boolean | undefined, excludeLibFiles: boolean | undefined): NavigateToItem[] {
const args: protocol.NavtoRequestArgs = {
searchValue,
file: this.host.getScriptFileNames()[0],
file,
currentFileOnly: !!file,
maxResultCount,
};
const oldPreferences = this.preferences;
if (excludeLibFiles) {
this.configure({ excludeLibrarySymbolsInNavTo: true });
}
const request = this.processRequest<protocol.NavtoRequest>(protocol.CommandTypes.Navto, args);
const response = this.processResponse<protocol.NavtoResponse>(request);
if (excludeLibFiles) {
this.configure(oldPreferences || {});
}
return response.body!.map(entry => ({ // TODO: GH#18217
name: entry.name,
containerName: entry.containerName || "",
@@ -579,14 +589,13 @@ export class SessionClient implements LanguageService {
const providePrefixAndSuffixTextForRename = typeof preferences === "boolean" ? preferences : preferences?.providePrefixAndSuffixTextForRename;
const quotePreference = typeof preferences === "boolean" ? undefined : preferences?.quotePreference;
if (providePrefixAndSuffixTextForRename !== undefined || quotePreference !== undefined) {
const oldPreferences = this.preferences;
// User preferences have to be set through the `Configure` command
this.configure({ providePrefixAndSuffixTextForRename, quotePreference });
// Options argument is not used, so don't pass in options
this.getRenameInfo(fileName, position, /*preferences*/ {}, findInStrings, findInComments);
// Restore previous user preferences
if (this.preferences) {
this.configure(this.preferences);
}
this.configure(oldPreferences || {});
}
else {
this.getRenameInfo(fileName, position, /*preferences*/ {}, findInStrings, findInComments);
@@ -812,6 +821,7 @@ export class SessionClient implements LanguageService {
kind?: string,
includeInteractiveActions?: boolean,
): ApplicableRefactorInfo[] {
const oldPreferences = this.preferences;
if (preferences) { // Temporarily set preferences
this.configure(preferences);
}
@@ -822,7 +832,7 @@ export class SessionClient implements LanguageService {
const request = this.processRequest<protocol.GetApplicableRefactorsRequest>(protocol.CommandTypes.GetApplicableRefactors, args);
const response = this.processResponse<protocol.GetApplicableRefactorsResponse>(request);
if (preferences) { // Restore preferences
this.configure(this.preferences || {});
this.configure(oldPreferences || {});
}
return response.body!; // TODO: GH#18217
}
@@ -844,6 +854,7 @@ export class SessionClient implements LanguageService {
preferences: UserPreferences | undefined,
interactiveRefactorArguments?: InteractiveRefactorArguments,
): RefactorEditInfo {
const oldPreferences = this.preferences;
if (preferences) { // Temporarily set preferences
this.configure(preferences);
}
@@ -868,7 +879,7 @@ export class SessionClient implements LanguageService {
}
if (preferences) { // Restore preferences
this.configure(this.preferences || {});
this.configure(oldPreferences || {});
}
return {
+19 -9
View File
@@ -153,7 +153,10 @@ export class System implements ts.System {
}
public setModifiedTime(path: string, time: Date) {
this.vfs.utimesSync(path, time, time);
try {
this.vfs.utimesSync(path, time, time);
}
catch { /* ignored */ }
}
public createHash(data: string): string {
@@ -245,13 +248,14 @@ export class CompilerHost implements ts.CompilerHost {
private readonly _outputsMap: collections.SortedMap<string, number>;
public readonly traces: string[] = [];
public readonly shouldAssertInvariants = !Harness.lightMode;
public readonly jsDocParsingMode: ts.JSDocParsingMode | undefined;
private _setParentNodes: boolean;
private _sourceFiles: collections.SortedMap<string, ts.SourceFile>;
private _parseConfigHost: ParseConfigHost | undefined;
private _newLine: string;
constructor(sys: System | vfs.FileSystem, options = ts.getDefaultCompilerOptions(), setParentNodes = false) {
constructor(sys: System | vfs.FileSystem, options = ts.getDefaultCompilerOptions(), setParentNodes = false, jsDocParsingMode?: ts.JSDocParsingMode) {
if (sys instanceof vfs.FileSystem) sys = new System(sys);
this.sys = sys;
this.defaultLibLocation = sys.vfs.meta.get("defaultLibLocation") || "";
@@ -259,6 +263,7 @@ export class CompilerHost implements ts.CompilerHost {
this._sourceFiles = new collections.SortedMap<string, ts.SourceFile>({ comparer: sys.vfs.stringComparer, sort: "insertion" });
this._setParentNodes = setParentNodes;
this._outputsMap = new collections.SortedMap(this.vfs.stringComparer);
this.jsDocParsingMode = jsDocParsingMode;
}
public get vfs() {
@@ -347,7 +352,7 @@ export class CompilerHost implements ts.CompilerHost {
return vpath.resolve(this.getDefaultLibLocation(), ts.getDefaultLibFileName(options));
}
public getSourceFile(fileName: string, languageVersion: number): ts.SourceFile | undefined {
public getSourceFile(fileName: string, languageVersionOrOptions: ts.ScriptTarget | ts.CreateSourceFileOptions): ts.SourceFile | undefined {
const canonicalFileName = this.getCanonicalFileName(vpath.resolve(this.getCurrentDirectory(), fileName));
const existing = this._sourceFiles.get(canonicalFileName);
if (existing) return existing;
@@ -361,7 +366,12 @@ export class CompilerHost implements ts.CompilerHost {
// reused across multiple tests. In that case, we cache the SourceFile we parse
// so that it can be reused across multiple tests to avoid the cost of
// repeatedly parsing the same file over and over (such as lib.d.ts).
const cacheKey = this.vfs.shadowRoot && `SourceFile[languageVersion=${languageVersion},setParentNodes=${this._setParentNodes}]`;
// TODO(jakebailey): the below is totally wrong; languageVersionOrOptions can be an object,
// and so any options bag will be keyed as "[object Object]", and we'll incorrectly share
// SourceFiles parsed with different options. But fixing this doesn't expose any bugs and
// doubles the memory usage of a test run, so I'm leaving it for now.
const cacheKey = this.vfs.shadowRoot && `SourceFile[languageVersionOrOptions=${languageVersionOrOptions},setParentNodes=${this._setParentNodes}]`;
if (cacheKey) {
const meta = this.vfs.filemeta(canonicalFileName);
const sourceFileFromMetadata = meta.get(cacheKey) as ts.SourceFile | undefined;
@@ -371,7 +381,7 @@ export class CompilerHost implements ts.CompilerHost {
}
}
const parsed = ts.createSourceFile(fileName, content, languageVersion, this._setParentNodes || this.shouldAssertInvariants);
const parsed = ts.createSourceFile(fileName, content, languageVersionOrOptions, this._setParentNodes || this.shouldAssertInvariants);
if (this.shouldAssertInvariants) {
Utils.assertInvariants(parsed, /*parent*/ undefined);
}
@@ -558,13 +568,13 @@ export function patchHostForBuildInfoWrite<T extends ts.System>(sys: T, version:
export class SolutionBuilderHost extends CompilerHost implements ts.SolutionBuilderHost<ts.BuilderProgram> {
createProgram: ts.CreateProgram<ts.BuilderProgram>;
private constructor(sys: System | vfs.FileSystem, options?: ts.CompilerOptions, setParentNodes?: boolean, createProgram?: ts.CreateProgram<ts.BuilderProgram>) {
super(sys, options, setParentNodes);
private constructor(sys: System | vfs.FileSystem, options?: ts.CompilerOptions, setParentNodes?: boolean, createProgram?: ts.CreateProgram<ts.BuilderProgram>, jsDocParsingMode?: ts.JSDocParsingMode) {
super(sys, options, setParentNodes, jsDocParsingMode);
this.createProgram = createProgram || ts.createEmitAndSemanticDiagnosticsBuilderProgram as unknown as ts.CreateProgram<ts.BuilderProgram>;
}
static create(sys: System | vfs.FileSystem, options?: ts.CompilerOptions, setParentNodes?: boolean, createProgram?: ts.CreateProgram<ts.BuilderProgram>) {
const host = new SolutionBuilderHost(sys, options, setParentNodes, createProgram);
static create(sys: System | vfs.FileSystem, options?: ts.CompilerOptions, setParentNodes?: boolean, createProgram?: ts.CreateProgram<ts.BuilderProgram>, jsDocParsingMode?: ts.JSDocParsingMode) {
const host = new SolutionBuilderHost(sys, options, setParentNodes, createProgram, jsDocParsingMode);
patchHostForBuildInfoReadWrite(host.sys);
return host;
}
+5 -3
View File
@@ -2427,7 +2427,7 @@ export class TestState {
baselineFile,
annotations + "\n\n" + stringify(result, (key, value) => {
return key === "exportMapKey"
? value.replace(/\|[0-9]+/g, "|*")
? value.replace(/ \d+ /g, " * ")
: value;
}),
);
@@ -2763,6 +2763,7 @@ export class TestState {
this.languageService.getProgram()?.getCompilerOptions() || {},
),
setExternalModuleIndicator: ts.getSetExternalModuleIndicator(this.languageService.getProgram()?.getCompilerOptions() || {}),
jsDocParsingMode: this.languageServiceAdapterHost.jsDocParsingMode,
};
const referenceSourceFile = ts.createLanguageServiceSourceFile(
this.activeFile.fileName,
@@ -3765,8 +3766,9 @@ export class TestState {
}
public verifyNavigateTo(options: readonly FourSlashInterface.VerifyNavigateToOptions[]): void {
for (const { pattern, expected, fileName } of options) {
const items = this.languageService.getNavigateToItems(pattern, /*maxResultCount*/ undefined, fileName);
for (const { pattern, expected, fileName, excludeLibFiles } of options) {
const file = fileName && this.findFile(fileName).fileName;
const items = this.languageService.getNavigateToItems(pattern, /*maxResultCount*/ undefined, file, /*excludeDtsFiles*/ undefined, excludeLibFiles);
this.assertObjectsEqual(
items,
expected.map((e): ts.NavigateToItem => ({
+2
View File
@@ -1133,6 +1133,7 @@ export namespace Completion {
interfaceEntry("ImportMeta"),
interfaceEntry("ImportCallOptions"),
interfaceEntry("ImportAssertions"),
interfaceEntry("ImportAttributes"),
varEntry("Math"),
varEntry("Date"),
interfaceEntry("DateConstructor"),
@@ -1809,6 +1810,7 @@ export interface VerifyNavigateToOptions {
readonly pattern: string;
readonly fileName?: string;
readonly expected: readonly ExpectedNavigateToItem[];
readonly excludeLibFiles?: boolean;
}
export interface ExpectedNavigateToItem {
+2 -2
View File
@@ -243,13 +243,13 @@ export namespace Compiler {
export function createSourceFileAndAssertInvariants(
fileName: string,
sourceText: string,
languageVersion: ts.ScriptTarget,
languageVersionOrOptions: ts.ScriptTarget | ts.CreateSourceFileOptions,
) {
// We'll only assert invariants outside of light mode.
const shouldAssertInvariants = !lightMode;
// Only set the parent nodes if we're asserting invariants. We don't need them otherwise.
const result = ts.createSourceFile(fileName, sourceText, languageVersion, /*setParentNodes:*/ shouldAssertInvariants);
const result = ts.createSourceFile(fileName, sourceText, languageVersionOrOptions, /*setParentNodes:*/ shouldAssertInvariants);
if (shouldAssertInvariants) {
Utils.assertInvariants(result, /*parent:*/ undefined);
+1
View File
@@ -146,6 +146,7 @@ export abstract class LanguageServiceAdapterHost {
public readonly sys = new fakes.System(new vfs.FileSystem(/*ignoreCase*/ true, { cwd: virtualFileSystemRoot }));
public typesRegistry: Map<string, void> | undefined;
private scriptInfos: collections.SortedMap<string, ScriptInfo>;
public jsDocParsingMode: ts.JSDocParsingMode | undefined;
constructor(protected cancellationToken = DefaultHostCancellationToken.instance, protected settings = ts.getDefaultCompilerOptions()) {
this.scriptInfos = new collections.SortedMap({ comparer: this.vfs.stringComparer, sort: "insertion" });
+425 -1
View File
@@ -102,7 +102,431 @@ function verifyDocumentRegistry(service: ts.server.ProjectService) {
service.forEachProject(collectStats);
verifyDocumentRegistryStats(service.documentRegistry, stats);
}
interface ResolutionInfo {
cacheType: string;
fileName: string;
name: string;
mode: ts.ResolutionMode;
}
function getResolutionCacheDetails<File, T extends ts.ResolutionWithFailedLookupLocations>(
baseline: string[],
cacheType: string,
file: File,
forEach:
| ((
callback: (resolvedModule: T, moduleName: string, mode: ts.ResolutionMode) => void,
file: File,
) => void)
| undefined,
getResolvedFileName: (resolution: T) => string | undefined,
indent: string,
) {
let addedCacheType = false;
forEach?.((resolved, key, mode) => {
if (!addedCacheType) {
addedCacheType = true;
baseline.push(`${indent}${cacheType}:`);
}
baseline.push(`${indent} ${key}: ${mode ? ts.getNameOfCompilerOptionValue(mode, ts.moduleOptionDeclaration.type) + ":" : ""}${getResolvedFileName(resolved)}`);
}, file);
}
function getResolvedModuleFileName(r: ts.ResolvedModuleWithFailedLookupLocations) {
return r.resolvedModule?.resolvedFileName;
}
function getResolvedTypeRefFileName(r: ts.ResolvedTypeReferenceDirectiveWithFailedLookupLocations) {
return r.resolvedTypeReferenceDirective?.resolvedFileName;
}
function getLibResolutionCacheDetails(
baseline: string[],
cache: Map<string, ts.LibResolution> | undefined,
indent: string,
) {
let addedCacheType = false;
cache?.forEach((resolved, libFileName) => {
if (!addedCacheType) {
addedCacheType = true;
baseline.push(`${indent}Libs:`);
}
baseline.push(`${indent} ${libFileName}: Actual: ${resolved.actual} Resolution: ${getResolvedModuleFileName(resolved.resolution)}`);
});
}
function getProgramStructure(program: ts.Program | undefined) {
const baseline: string[] = [];
program?.getSourceFiles().slice().sort((f1, f2) => ts.comparePathsCaseSensitive(f1.path, f2.path)).forEach(f => {
baseline.push(` File: ${f.fileName} Path: ${f.path} ResolvedPath: ${f.resolvedPath} impliedNodeFormat: ${f.impliedNodeFormat}`);
baseline.push(f.text.split(/\r?\n/g).map(l => l ? " " + l : "").join("\n"));
getResolutionCacheDetails(
baseline,
"Modules",
f,
program.forEachResolvedModule,
getResolvedModuleFileName,
" ",
);
getResolutionCacheDetails(
baseline,
"TypeRefs",
f,
program.forEachResolvedTypeReferenceDirective,
getResolvedTypeRefFileName,
" ",
);
});
getResolutionCacheDetails(
baseline,
"AutoTypeRefs",
/*file*/ undefined,
program?.getAutomaticTypeDirectiveResolutions().forEach,
getResolvedTypeRefFileName,
" ",
);
getLibResolutionCacheDetails(
baseline,
program?.resolvedLibReferences,
" ",
);
return baseline.join("\n");
}
export function verifyProgramStructure(expectedProgram: ts.Program, actualProgram: ts.Program, projectName: string) {
const actual = getProgramStructure(actualProgram);
const expected = getProgramStructure(expectedProgram);
ts.Debug.assert(actual === expected, `Program verification:: ${projectName}`);
}
export function verifyResolutionCache(
actual: ts.ResolutionCache,
actualProgram: ts.Program,
resolutionHostCacheHost: ts.ResolutionCacheHost,
projectName: string,
) {
const currentDirectory = resolutionHostCacheHost.getCurrentDirectory!();
const expected = ts.createResolutionCache(resolutionHostCacheHost, actual.rootDirForResolution, /*logChangesWhenResolvingModule*/ false);
expected.startCachingPerDirectoryResolution();
type ExpectedResolution = ts.CachedResolvedModuleWithFailedLookupLocations & ts.CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations;
const expectedToResolution = new Map<ExpectedResolution, ts.ResolutionWithFailedLookupLocations>();
const resolutionToExpected = new Map<ts.ResolutionWithFailedLookupLocations, ExpectedResolution>();
const resolutionToRefs = new Map<ts.ResolutionWithFailedLookupLocations, ResolutionInfo[]>();
actual.resolvedModuleNames.forEach((resolutions, path) =>
collectResolutionToRefFromCache(
"Modules",
path,
resolutions,
getResolvedModuleFileName,
/*deferWatchingNonRelativeResolution*/ true,
expected.resolvedModuleNames,
)
);
actual.resolvedTypeReferenceDirectives.forEach((resolutions, path) =>
collectResolutionToRefFromCache(
"TypeRefs",
path,
resolutions,
getResolvedTypeRefFileName,
/*deferWatchingNonRelativeResolution*/ false,
expected.resolvedTypeReferenceDirectives,
)
);
actual.resolvedLibraries.forEach((resolved, libFileName) => {
const expectedResolution = collectResolution(
"Libs",
resolutionHostCacheHost.toPath(
ts.getInferredLibraryNameResolveFrom(actualProgram.getCompilerOptions(), currentDirectory, libFileName),
),
resolved,
getResolvedModuleFileName(resolved),
ts.getLibraryNameFromLibFileName(libFileName),
/*mode*/ undefined,
/*deferWatchingNonRelativeResolution*/ false,
);
expected.resolvedLibraries.set(libFileName, expectedResolution);
});
expected.finishCachingPerDirectoryResolution(actualProgram, /*oldProgram*/ undefined);
// Verify ref count
resolutionToRefs.forEach((info, resolution) => {
ts.Debug.assert(
resolution.refCount === info.length,
`${projectName}:: Expected Resolution ref count ${info.length} but got ${resolution.refCount}`,
() =>
`Expected from:: ${JSON.stringify(info, undefined, " ")}` +
`Actual from: ${resolution.refCount}`,
);
ts.Debug.assert(
resolutionToExpected.get(resolution)!.refCount === resolution.refCount,
`${projectName}:: Expected Resolution ref count ${resolutionToExpected.get(resolution)!.refCount} but got ${resolution.refCount}`,
);
verifySet(resolutionToExpected.get(resolution)!.files, resolution.files, `Resolution files`);
});
verifyMapOfResolutionSet(expected.resolvedFileToResolution, actual.resolvedFileToResolution, `resolvedFileToResolution`);
verifyResolutionSet(expected.resolutionsWithFailedLookups, actual.resolutionsWithFailedLookups, `resolutionsWithFailedLookups`);
verifyResolutionSet(expected.resolutionsWithOnlyAffectingLocations, actual.resolutionsWithOnlyAffectingLocations, `resolutionsWithOnlyAffectingLocations`);
verifyDirectoryWatchesOfFailedLookups(expected.directoryWatchesOfFailedLookups, actual.directoryWatchesOfFailedLookups);
verifyFileWatchesOfAffectingLocations(expected.fileWatchesOfAffectingLocations, actual.fileWatchesOfAffectingLocations);
// Stop watching resolutions to verify everything gets closed.
actual.resolvedModuleNames.forEach((_resolutions, path) => expected.removeResolutionsOfFile(path));
actual.resolvedTypeReferenceDirectives.forEach((_resolutions, path) => expected.removeResolutionsOfFile(path));
expected.finishCachingPerDirectoryResolution(/*newProgram*/ undefined, actualProgram);
resolutionToExpected.forEach(expected => {
ts.Debug.assert(!expected.refCount, `${projectName}:: All the resolution should be released`);
ts.Debug.assert(!expected.files?.size, `${projectName}:: Shouldnt ref to any files`);
});
ts.Debug.assert(expected.resolvedFileToResolution.size === 0, `${projectName}:: resolvedFileToResolution should be released`);
ts.Debug.assert(expected.resolutionsWithFailedLookups.size === 0, `${projectName}:: resolutionsWithFailedLookups should be released`);
ts.Debug.assert(expected.resolutionsWithOnlyAffectingLocations.size === 0, `${projectName}:: resolutionsWithOnlyAffectingLocations should be released`);
ts.Debug.assert(expected.directoryWatchesOfFailedLookups.size === 0, `${projectName}:: directoryWatchesOfFailedLookups should be released`);
ts.Debug.assert(expected.fileWatchesOfAffectingLocations.size === 0, `${projectName}:: fileWatchesOfAffectingLocations should be released`);
function collectResolutionToRefFromCache<T extends ts.ResolutionWithFailedLookupLocations>(
cacheType: string,
fileName: ts.Path,
cache: ts.ModeAwareCache<T> | undefined,
getResolvedFileName: (resolution: T) => string | undefined,
deferWatchingNonRelativeResolution: boolean,
storeExpcted: Map<ts.Path, ts.ModeAwareCache<ts.ResolutionWithFailedLookupLocations>>,
) {
ts.Debug.assert(
actualProgram.getSourceFileByPath(fileName) || ts.endsWith(fileName, ts.inferredTypesContainingFile),
`${projectName}:: ${cacheType} ${fileName} Expect cache for file in program or auto type ref`,
);
let expectedCache: ts.ModeAwareCache<ts.ResolutionWithFailedLookupLocations> | undefined;
cache?.forEach((resolved, name, mode) => {
const resolvedFileName = getResolvedFileName(resolved);
const expected = collectResolution(cacheType, fileName, resolved, resolvedFileName, name, mode, deferWatchingNonRelativeResolution);
if (!expectedCache) storeExpcted.set(fileName, expectedCache = ts.createModeAwareCache());
expectedCache.set(name, mode, expected);
});
}
function collectResolution<T extends ts.ResolutionWithFailedLookupLocations>(
cacheType: string,
fileName: ts.Path,
resolved: T,
resolvedFileName: string | undefined,
name: string,
mode: ts.ResolutionMode,
deferWatchingNonRelativeResolution: boolean,
): ExpectedResolution {
const existing = resolutionToRefs.get(resolved);
let expectedResolution: ExpectedResolution;
if (existing) {
existing.push({ cacheType, fileName, name, mode });
expectedResolution = resolutionToExpected.get(resolved)!;
}
else {
resolutionToRefs.set(resolved, [{ cacheType, fileName, name, mode }]);
expectedResolution = {
resolvedModule: (resolved as any).resolvedModule,
resolvedTypeReferenceDirective: (resolved as any).resolvedTypeReferenceDirective,
failedLookupLocations: resolved.failedLookupLocations,
affectingLocations: resolved.affectingLocations,
node10Result: resolved.node10Result,
};
expectedToResolution.set(expectedResolution, resolved);
resolutionToExpected.set(resolved, expectedResolution);
}
expected.watchFailedLookupLocationsOfExternalModuleResolutions(name, expectedResolution, fileName, () => ({ resolvedFileName }), deferWatchingNonRelativeResolution);
return expectedResolution;
}
function verifyMap<Expected, Actual>(
expected: Map<string, Expected> | undefined,
actual: Map<string, Actual> | undefined,
verifyValue: (expected: Expected | undefined, actual: Actual | undefined, key: string) => void,
caption: string,
) {
expected?.forEach((expected, path) => verifyValue(expected, actual?.get(path), `${caption}:: ${path}`));
actual?.forEach((actual, path) => verifyValue(expected?.get(path), actual, `${caption}:: ${path}`));
}
function verifySet(
expected: Set<string> | undefined,
actual: Set<string> | undefined,
caption: string,
) {
expected?.forEach(expected =>
ts.Debug.assert(
actual?.has(expected),
`${projectName}:: ${caption}:: Expected should be present in actual`,
)
);
actual?.forEach(actual =>
ts.Debug.assert(
expected?.has(actual),
`${projectName}:: ${caption}:: Actual should be present in expected`,
)
);
}
function verifyMapOfResolutionSet(
expected: Map<ts.Path, Set<ts.ResolutionWithFailedLookupLocations>> | undefined,
actual: Map<ts.Path, Set<ts.ResolutionWithFailedLookupLocations>> | undefined,
caption: string,
) {
verifyMap(expected, actual, verifyResolutionSet, caption);
}
function verifyResolutionSet(
expected: Set<ts.ResolutionWithFailedLookupLocations> | undefined,
actual: Set<ts.ResolutionWithFailedLookupLocations> | undefined,
caption: string,
) {
expected?.forEach(resolution =>
ts.Debug.assert(
actual?.has(expectedToResolution.get(resolution as ExpectedResolution)!),
`${projectName}:: ${caption}:: Expected resolution should be present in actual resolutions`,
)
);
actual?.forEach(resolution =>
ts.Debug.assert(
expected?.has(resolutionToExpected.get(resolution)!),
`${projectName}:: ${caption}:: Actual resolution should be present in expected resolutions`,
)
);
}
function verifyDirectoryWatchesOfFailedLookups(expected: Map<string, ts.DirectoryWatchesOfFailedLookup>, actual: Map<string, ts.DirectoryWatchesOfFailedLookup>) {
verifyMap(expected, actual, (expected, actual, caption) => {
ts.Debug.assert(expected?.refCount === actual?.refCount, `${projectName}:: ${caption}:: refCount`);
ts.Debug.assert(!!expected?.refCount, `${projectName}:: ${caption}:: expected refCount to be non zero`);
ts.Debug.assert(expected?.nonRecursive === actual?.nonRecursive, `${projectName}:: ${caption}:: nonRecursive`);
}, "directoryWatchesOfFailedLookups");
}
function verifyFileWatchesOfAffectingLocations(
expected: Map<string, ts.FileWatcherOfAffectingLocation>,
actual: Map<string, ts.FileWatcherOfAffectingLocation>,
) {
verifyMap(expected, actual, verifyFileWatcherOfAffectingLocation, "fileWatchesOfAffectingLocations");
}
function verifyFileWatcherOfAffectingLocation(
expected: ts.FileWatcherOfAffectingLocation | undefined,
actual: ts.FileWatcherOfAffectingLocation | undefined,
caption: string,
) {
ts.Debug.assert(expected?.resolutions === actual?.resolutions, `${projectName}:: ${caption}:: resolutions`);
ts.Debug.assert(expected?.files === actual?.files, `${projectName}:: ${caption}:: files`);
verifySet(expected?.symlinks, actual?.symlinks, `${projectName}:: ${caption}:: symlinks`);
}
}
function verifyProgram(service: ts.server.ProjectService, project: ts.server.Project) {
if (service.serverMode === ts.LanguageServiceMode.Syntactic) return;
const options = project.getCompilerOptions();
const compilerHost = ts.createCompilerHostWorker(options, /*setParentNodes*/ undefined, service.host);
compilerHost.useSourceOfProjectReferenceRedirect = project.useSourceOfProjectReferenceRedirect?.bind(project);
compilerHost.getCurrentDirectory = project.getCurrentDirectory.bind(project);
const getDefaultLibLocation = compilerHost.getDefaultLibLocation!;
compilerHost.getDefaultLibLocation = () => ts.getNormalizedAbsolutePath(getDefaultLibLocation(), service.host.getCurrentDirectory());
compilerHost.getDefaultLibFileName = options => ts.combinePaths(compilerHost.getDefaultLibLocation!(), ts.getDefaultLibFileName(options));
const readFile = compilerHost.readFile;
compilerHost.readFile = fileName => {
const path = project.toPath(fileName);
const info = project.projectService.filenameToScriptInfo.get(path);
if (info?.isDynamicOrHasMixedContent() || project.fileIsOpen(path)) {
return ts.getSnapshotText(info!.getSnapshot());
}
if (!ts.isAnySupportedFileExtension(path)) {
// Some external file
const snapshot = project.getScriptSnapshot(path);
return snapshot ? ts.getSnapshotText(snapshot) : undefined;
}
// Read only rooted disk paths from host similar to ProjectService
if (!ts.isRootedDiskPath(fileName) || !compilerHost.fileExists(fileName)) return undefined;
if (ts.hasTSFileExtension(fileName)) return readFile(fileName);
let text: string | undefined | false;
let fileSize: number;
if (service.host.getFileSize) fileSize = service.host.getFileSize(fileName);
else {
text = readFile(fileName);
fileSize = text?.length || 0;
text = text !== undefined ? text : false;
}
// Large js files like project service
if (fileSize > ts.server.maxFileSize) return "";
return text !== undefined ? text || undefined : readFile(fileName);
};
const resolutionHostCacheHost: ts.ResolutionCacheHost = {
...compilerHost,
getCompilerHost: () => compilerHost,
toPath: project.toPath.bind(project),
getCompilationSettings: project.getCompilationSettings.bind(project),
projectName: project.projectName,
getGlobalCache: project.getGlobalCache.bind(project),
globalCacheResolutionModuleName: project.globalCacheResolutionModuleName.bind(project),
fileIsOpen: project.fileIsOpen.bind(project),
getCurrentProgram: () => project.getCurrentProgram(),
watchDirectoryOfFailedLookupLocation: ts.returnNoopFileWatcher,
watchAffectingFileLocation: ts.returnNoopFileWatcher,
onInvalidatedResolution: ts.noop,
watchTypeRootsDirectory: ts.returnNoopFileWatcher,
onChangedAutomaticTypeDirectiveNames: ts.noop,
scheduleInvalidateResolutionsOfFailedLookupLocations: ts.noop,
getCachedDirectoryStructureHost: ts.returnUndefined,
writeLog: ts.noop,
};
const moduleResolutionCache = ts.createModuleResolutionCache(compilerHost.getCurrentDirectory(), compilerHost.getCanonicalFileName, project.getCompilerOptions());
compilerHost.resolveModuleNameLiterals = (moduleNames, containingFile, redirectedReference, options, containingSourceFile) =>
ts.loadWithModeAwareCache(
moduleNames,
containingFile,
redirectedReference,
options,
containingSourceFile,
compilerHost,
moduleResolutionCache,
(containingFile, redirectedReference, options) =>
ts.createModuleResolutionLoaderUsingGlobalCache(
containingFile,
redirectedReference,
options,
resolutionHostCacheHost,
moduleResolutionCache,
),
);
verifyProgramStructure(
ts.createProgram({
rootNames: project.getScriptFileNames(),
options: project.getCompilationSettings(),
projectReferences: project.getProjectReferences(),
host: compilerHost,
}),
project.getCurrentProgram()!,
project.projectName,
);
verifyResolutionCache(project.resolutionCache, project.getCurrentProgram()!, resolutionHostCacheHost, project.projectName);
}
export interface IncrementalVerifierCallbacks {
beforeVerification?(): any;
afterVerification?(dataFromBefore: any): void;
}
export function incrementalVerifier(service: ts.server.ProjectService) {
service.verifyDocumentRegistry = () => verifyDocumentRegistry(service);
service.verifyDocumentRegistry = withIncrementalVerifierCallbacks(service, verifyDocumentRegistry);
service.verifyProgram = withIncrementalVerifierCallbacks(service, verifyProgram);
}
function withIncrementalVerifierCallbacks(
service: ts.server.ProjectService,
callback: (service: ts.server.ProjectService, ...args: any[]) => void,
): (...args: any[]) => void {
return (...args: any[]) => {
const data = (service.host as IncrementalVerifierCallbacks).beforeVerification?.();
callback(service, ...args);
(service.host as IncrementalVerifierCallbacks).afterVerification?.(data);
};
}
+4 -2
View File
@@ -2,7 +2,9 @@
"extends": "../tsconfig-base",
"compilerOptions": {
"types": [
"node", "mocha", "chai"
"node",
"mocha",
"chai"
]
},
"references": [
@@ -11,7 +13,7 @@
{ "path": "../jsTyping" },
{ "path": "../server" },
{ "path": "../typingsInstallerCore" },
{ "path": "../deprecatedCompat" },
{ "path": "../deprecatedCompat" }
],
"include": ["**/*"]
+4
View File
@@ -1417,6 +1417,7 @@ interface RTCInboundRtpStreamStats extends RTCReceivedRtpStreamStats {
keyFramesDecoded?: number;
kind: string;
lastPacketReceivedTimestamp?: DOMHighResTimeStamp;
mid?: string;
nackCount?: number;
packetsDiscarded?: number;
pliCount?: number;
@@ -1431,6 +1432,7 @@ interface RTCInboundRtpStreamStats extends RTCReceivedRtpStreamStats {
totalSamplesDuration?: number;
totalSamplesReceived?: number;
totalSquaredInterFrameDelay?: number;
trackIdentifier: string;
}
interface RTCLocalSessionDescriptionInit {
@@ -21825,7 +21827,9 @@ interface SubtleCrypto {
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/exportKey) */
exportKey(format: "jwk", key: CryptoKey): Promise<JsonWebKey>;
exportKey(format: Exclude<KeyFormat, "jwk">, key: CryptoKey): Promise<ArrayBuffer>;
exportKey(format: KeyFormat, key: CryptoKey): Promise<ArrayBuffer | JsonWebKey>;
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/generateKey) */
generateKey(algorithm: "Ed25519", extractable: boolean, keyUsages: ReadonlyArray<"sign" | "verify">): Promise<CryptoKeyPair>;
generateKey(algorithm: RsaHashedKeyGenParams | EcKeyGenParams, extractable: boolean, keyUsages: ReadonlyArray<KeyUsage>): Promise<CryptoKeyPair>;
generateKey(algorithm: AesKeyGenParams | HmacKeyGenParams | Pbkdf2Params, extractable: boolean, keyUsages: ReadonlyArray<KeyUsage>): Promise<CryptoKey>;
generateKey(algorithm: AlgorithmIdentifier, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair | CryptoKey>;
+9 -1
View File
@@ -620,7 +620,8 @@ interface ImportMeta {
* augmented via interface merging.
*/
interface ImportCallOptions {
assert?: ImportAssertions;
/** @deprecated*/ assert?: ImportAssertions;
with?: ImportAttributes;
}
/**
@@ -630,6 +631,13 @@ interface ImportAssertions {
[key: string]: string;
}
/**
* The type for the `with` property of the optional second argument to `import()`.
*/
interface ImportAttributes {
[key: string]: string;
}
interface Math {
/** The mathematical constant e. This is Euler's number, the base of natural logarithms. */
readonly E: number;
+2
View File
@@ -5322,7 +5322,9 @@ interface SubtleCrypto {
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/exportKey) */
exportKey(format: "jwk", key: CryptoKey): Promise<JsonWebKey>;
exportKey(format: Exclude<KeyFormat, "jwk">, key: CryptoKey): Promise<ArrayBuffer>;
exportKey(format: KeyFormat, key: CryptoKey): Promise<ArrayBuffer | JsonWebKey>;
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/generateKey) */
generateKey(algorithm: "Ed25519", extractable: boolean, keyUsages: ReadonlyArray<"sign" | "verify">): Promise<CryptoKeyPair>;
generateKey(algorithm: RsaHashedKeyGenParams | EcKeyGenParams, extractable: boolean, keyUsages: ReadonlyArray<KeyUsage>): Promise<CryptoKeyPair>;
generateKey(algorithm: AesKeyGenParams | HmacKeyGenParams | Pbkdf2Params, extractable: boolean, keyUsages: ReadonlyArray<KeyUsage>): Promise<CryptoKey>;
generateKey(algorithm: AlgorithmIdentifier, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKeyPair | CryptoKey>;
+145 -4
View File
@@ -27,6 +27,7 @@ import {
Diagnostic,
directorySeparator,
DirectoryStructureHost,
DirectoryWatcherCallback,
DocumentPosition,
DocumentPositionMapper,
DocumentRegistry,
@@ -37,6 +38,7 @@ import {
FileExtensionInfo,
fileExtensionIs,
FileWatcher,
FileWatcherCallback,
FileWatcherEventKind,
find,
flatMap,
@@ -71,6 +73,7 @@ import {
isNodeModulesDirectory,
isRootedDiskPath,
isString,
JSDocParsingMode,
LanguageServiceMode,
length,
map,
@@ -126,6 +129,7 @@ import {
version,
WatchDirectoryFlags,
WatchFactory,
WatchFactoryHost,
WatchLogLevel,
WatchOptions,
WatchType,
@@ -192,6 +196,9 @@ export const ConfigFileDiagEvent = "configFileDiag";
export const ProjectLanguageServiceStateEvent = "projectLanguageServiceState";
export const ProjectInfoTelemetryEvent = "projectInfo";
export const OpenFileInfoTelemetryEvent = "openFileInfo";
export const CreateFileWatcherEvent: protocol.CreateFileWatcherEventName = "createFileWatcher";
export const CreateDirectoryWatcherEvent: protocol.CreateDirectoryWatcherEventName = "createDirectoryWatcher";
export const CloseFileWatcherEvent: protocol.CloseFileWatcherEventName = "closeFileWatcher";
const ensureProjectForOpenFileSchedule = "*ensureProjectForOpenFiles*";
export interface ProjectsUpdatedInBackgroundEvent {
@@ -319,6 +326,21 @@ export interface OpenFileInfo {
readonly checkJs: boolean;
}
export interface CreateFileWatcherEvent {
readonly eventName: protocol.CreateFileWatcherEventName;
readonly data: protocol.CreateFileWatcherEventBody;
}
export interface CreateDirectoryWatcherEvent {
readonly eventName: protocol.CreateDirectoryWatcherEventName;
readonly data: protocol.CreateDirectoryWatcherEventBody;
}
export interface CloseFileWatcherEvent {
readonly eventName: protocol.CloseFileWatcherEventName;
readonly data: protocol.CloseFileWatcherEventBody;
}
export type ProjectServiceEvent =
| LargeFileReferencedEvent
| ProjectsUpdatedInBackgroundEvent
@@ -327,7 +349,10 @@ export type ProjectServiceEvent =
| ConfigFileDiagEvent
| ProjectLanguageServiceStateEvent
| ProjectInfoTelemetryEvent
| OpenFileInfoTelemetryEvent;
| OpenFileInfoTelemetryEvent
| CreateFileWatcherEvent
| CreateDirectoryWatcherEvent
| CloseFileWatcherEvent;
export type ProjectServiceEventHandler = (event: ProjectServiceEvent) => void;
@@ -582,6 +607,7 @@ export interface ProjectServiceOptions {
useInferredProjectPerProjectRoot: boolean;
typingsInstaller?: ITypingsInstaller;
eventHandler?: ProjectServiceEventHandler;
canUseWatchEvents?: boolean;
suppressDiagnosticEvents?: boolean;
throttleWaitMilliseconds?: number;
globalPlugins?: readonly string[];
@@ -591,6 +617,7 @@ export interface ProjectServiceOptions {
serverMode?: LanguageServiceMode;
session: Session<unknown> | undefined;
/** @internal */ incrementalVerifier?: (service: ProjectService) => void;
jsDocParsingMode?: JSDocParsingMode;
}
interface OriginalFileInfo {
@@ -855,6 +882,109 @@ function createProjectNameFactoryWithCounter(nameFactory: (counter: number) => s
return () => nameFactory(nextId++);
}
interface HostWatcherMap<T> {
idToCallbacks: Map<number, Set<T>>;
pathToId: Map<Path, number>;
}
function getHostWatcherMap<T>(): HostWatcherMap<T> {
return { idToCallbacks: new Map(), pathToId: new Map() };
}
function createWatchFactoryHostUsingWatchEvents(service: ProjectService, canUseWatchEvents: boolean | undefined): WatchFactoryHost | undefined {
if (!canUseWatchEvents || !service.eventHandler || !service.session) return undefined;
const watchedFiles = getHostWatcherMap<FileWatcherCallback>();
const watchedDirectories = getHostWatcherMap<DirectoryWatcherCallback>();
const watchedDirectoriesRecursive = getHostWatcherMap<DirectoryWatcherCallback>();
let ids = 1;
service.session.addProtocolHandler(protocol.CommandTypes.WatchChange, req => {
onWatchChange((req as protocol.WatchChangeRequest).arguments);
return { responseRequired: false };
});
return {
watchFile,
watchDirectory,
getCurrentDirectory: () => service.host.getCurrentDirectory(),
useCaseSensitiveFileNames: service.host.useCaseSensitiveFileNames,
};
function watchFile(path: string, callback: FileWatcherCallback): FileWatcher {
return getOrCreateFileWatcher(
watchedFiles,
path,
callback,
id => ({ eventName: CreateFileWatcherEvent, data: { id, path } }),
);
}
function watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher {
return getOrCreateFileWatcher(
recursive ? watchedDirectoriesRecursive : watchedDirectories,
path,
callback,
id => ({ eventName: CreateDirectoryWatcherEvent, data: { id, path, recursive: !!recursive } }),
);
}
function getOrCreateFileWatcher<T>(
{ pathToId, idToCallbacks }: HostWatcherMap<T>,
path: string,
callback: T,
event: (id: number) => CreateFileWatcherEvent | CreateDirectoryWatcherEvent,
) {
const key = service.toPath(path);
let id = pathToId.get(key);
if (!id) pathToId.set(key, id = ids++);
let callbacks = idToCallbacks.get(id);
if (!callbacks) {
idToCallbacks.set(id, callbacks = new Set());
// Add watcher
service.eventHandler!(event(id));
}
callbacks.add(callback);
return {
close() {
const callbacks = idToCallbacks.get(id!);
if (!callbacks?.delete(callback)) return;
if (callbacks.size) return;
idToCallbacks.delete(id!);
pathToId.delete(key);
service.eventHandler!({ eventName: CloseFileWatcherEvent, data: { id: id! } });
},
};
}
function onWatchChange({ id, path, eventType }: protocol.WatchChangeRequestArgs) {
// console.log(`typescript-vscode-watcher:: Invoke:: ${id}:: ${path}:: ${eventType}`);
onFileWatcherCallback(id, path, eventType);
onDirectoryWatcherCallback(watchedDirectories, id, path, eventType);
onDirectoryWatcherCallback(watchedDirectoriesRecursive, id, path, eventType);
}
function onFileWatcherCallback(
id: number,
eventPath: string,
eventType: "create" | "delete" | "update",
) {
watchedFiles.idToCallbacks.get(id)?.forEach(callback => {
const eventKind = eventType === "create" ?
FileWatcherEventKind.Created :
eventType === "delete" ?
FileWatcherEventKind.Deleted :
FileWatcherEventKind.Changed;
callback(eventPath, eventKind);
});
}
function onDirectoryWatcherCallback(
{ idToCallbacks }: HostWatcherMap<DirectoryWatcherCallback>,
id: number,
eventPath: string,
eventType: "create" | "delete" | "update",
) {
if (eventType === "update") return;
idToCallbacks.get(id)?.forEach(callback => {
callback(eventPath);
});
}
}
export class ProjectService {
/** @internal */
readonly typingsCache: TypingsCache;
@@ -959,7 +1089,8 @@ export class ProjectService {
public readonly typingsInstaller: ITypingsInstaller;
private readonly globalCacheLocationDirectoryPath: Path | undefined;
public readonly throttleWaitMilliseconds?: number;
private readonly eventHandler?: ProjectServiceEventHandler;
/** @internal */
readonly eventHandler?: ProjectServiceEventHandler;
private readonly suppressDiagnosticEvents?: boolean;
public readonly globalPlugins: readonly string[];
@@ -997,6 +1128,9 @@ export class ProjectService {
private currentPluginEnablementPromise?: Promise<void>;
/** @internal */ verifyDocumentRegistry = noop;
/** @internal */ verifyProgram: (project: Project) => void = noop;
readonly jsDocParsingMode: JSDocParsingMode | undefined;
constructor(opts: ProjectServiceOptions) {
this.host = opts.host;
@@ -1013,6 +1147,7 @@ export class ProjectService {
this.allowLocalPluginLoads = !!opts.allowLocalPluginLoads;
this.typesMapLocation = (opts.typesMapLocation === undefined) ? combinePaths(getDirectoryPath(this.getExecutingFilePath()), "typesMap.json") : opts.typesMapLocation;
this.session = opts.session;
this.jsDocParsingMode = opts.jsDocParsingMode;
if (opts.serverMode !== undefined) {
this.serverMode = opts.serverMode;
@@ -1049,7 +1184,7 @@ export class ProjectService {
extraFileExtensions: [],
};
this.documentRegistry = createDocumentRegistryInternal(this.host.useCaseSensitiveFileNames, this.currentDirectory, this);
this.documentRegistry = createDocumentRegistryInternal(this.host.useCaseSensitiveFileNames, this.currentDirectory, this.jsDocParsingMode, this);
const watchLogLevel = this.logger.hasLevel(LogLevel.verbose) ? WatchLogLevel.Verbose :
this.logger.loggingEnabled() ? WatchLogLevel.TriggerOnly : WatchLogLevel.None;
const log: (s: string) => void = watchLogLevel !== WatchLogLevel.None ? (s => this.logger.info(s)) : noop;
@@ -1059,7 +1194,12 @@ export class ProjectService {
watchFile: returnNoopFileWatcher,
watchDirectory: returnNoopFileWatcher,
} :
getWatchFactory(this.host, watchLogLevel, log, getDetailWatchInfo);
getWatchFactory(
createWatchFactoryHostUsingWatchEvents(this, opts.canUseWatchEvents) || this.host,
watchLogLevel,
log,
getDetailWatchInfo,
);
opts.incrementalVerifier?.(this);
}
@@ -1526,6 +1666,7 @@ export class ProjectService {
useCaseSensitiveFileNames: this.host.useCaseSensitiveFileNames,
writeLog: s => this.logger.info(s),
toPath: s => this.toPath(s),
getScriptKind: configuredProjectForConfig ? (fileName => configuredProjectForConfig.getScriptKind(fileName)) : undefined,
})
) return;
+40 -17
View File
@@ -30,6 +30,7 @@ import {
DirectoryWatcherCallback,
DocumentPositionMapper,
DocumentRegistry,
ensureTrailingDirectorySeparator,
enumerateInsertsAndDeletes,
every,
explainFiles,
@@ -71,6 +72,7 @@ import {
isDeclarationFileName,
isExternalModuleNameRelative,
isInsideNodeModules,
JSDocParsingMode,
JsTyping,
LanguageService,
LanguageServiceHost,
@@ -506,6 +508,8 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
/** @internal */
createHash = maybeBind(this.projectService.host, this.projectService.host.createHash);
readonly jsDocParsingMode: JSDocParsingMode | undefined;
/** @internal */
constructor(
projectName: string,
@@ -524,6 +528,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
this.directoryStructureHost = directoryStructureHost;
this.currentDirectory = this.projectService.getNormalizedAbsolutePath(currentDirectory);
this.getCanonicalFileName = this.projectService.toCanonicalFileName;
this.jsDocParsingMode = this.projectService.jsDocParsingMode;
this.cancellationToken = new ThrottledCancellationToken(this.projectService.cancellationToken, this.projectService.throttleWaitMilliseconds);
if (!this.compilerOptions) {
@@ -535,7 +540,6 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
// If files are listed explicitly or allowJs is specified, allow all extensions
this.compilerOptions.allowNonTsExtensions = true;
}
switch (projectService.serverMode) {
case LanguageServiceMode.Semantic:
this.languageServiceEnabled = true;
@@ -603,7 +607,8 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
}
if (this.program && !this.symlinks.hasProcessedResolutions()) {
this.symlinks.setSymlinksFromResolutions(
this.program.getSourceFiles(),
this.program.forEachResolvedModule,
this.program.forEachResolvedTypeReferenceDirective,
this.program.getAutomaticTypeDirectiveResolutions(),
);
}
@@ -663,7 +668,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
}
getScriptKind(fileName: string) {
const info = this.getOrCreateScriptInfoAndAttachToProject(fileName);
const info = this.projectService.getScriptInfoForPath(this.toPath(fileName));
return (info && info.scriptKind)!; // TODO: GH#18217
}
@@ -1536,13 +1541,13 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
if (!newFile || (f.resolvedPath === f.path && newFile.resolvedPath !== f.path)) {
// new program does not contain this file - detach it from the project
// - remove resolutions only if the new program doesnt contain source file by the path (not resolvedPath since path is used for resolution)
this.detachScriptInfoFromProject(f.fileName, !!this.program.getSourceFileByPath(f.path));
this.detachScriptInfoFromProject(f.fileName, !!this.program.getSourceFileByPath(f.path), /*syncDirWatcherRemove*/ true);
}
}
oldProgram.forEachResolvedProjectReference(resolvedProjectReference => {
if (!this.program!.getResolvedProjectReferenceByPath(resolvedProjectReference.sourceFile.path)) {
this.detachScriptInfoFromProject(resolvedProjectReference.sourceFile.fileName);
this.detachScriptInfoFromProject(resolvedProjectReference.sourceFile.fileName, /*noRemoveResolution*/ undefined, /*syncDirWatcherRemove*/ true);
}
});
}
@@ -1598,6 +1603,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
}
}
this.projectService.verifyProgram(this);
if (this.exportMapCache && !this.exportMapCache.isEmpty()) {
this.exportMapCache.releaseSymbols();
if (this.hasAddedorRemovedFiles || oldProgram && !this.program!.structureIsReused) {
@@ -1666,12 +1672,12 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
this.projectService.sendPerformanceEvent(kind, durationMs);
}
private detachScriptInfoFromProject(uncheckedFileName: string, noRemoveResolution?: boolean) {
private detachScriptInfoFromProject(uncheckedFileName: string, noRemoveResolution?: boolean, syncDirWatcherRemove?: boolean) {
const scriptInfoToDetach = this.projectService.getScriptInfo(uncheckedFileName);
if (scriptInfoToDetach) {
scriptInfoToDetach.detachFromProject(this);
if (!noRemoveResolution) {
this.resolutionCache.removeResolutionsOfFile(scriptInfoToDetach.path);
this.resolutionCache.removeResolutionsOfFile(scriptInfoToDetach.path, syncDirWatcherRemove);
}
}
}
@@ -2232,15 +2238,25 @@ function getUnresolvedImports(program: Program, cachedUnresolvedImportsPerFile:
const sourceFiles = program.getSourceFiles();
tracing?.push(tracing.Phase.Session, "getUnresolvedImports", { count: sourceFiles.length });
const ambientModules = program.getTypeChecker().getAmbientModules().map(mod => stripQuotes(mod.getName()));
const result = sortAndDeduplicate(flatMap(sourceFiles, sourceFile => extractUnresolvedImportsFromSourceFile(sourceFile, ambientModules, cachedUnresolvedImportsPerFile)));
const result = sortAndDeduplicate(flatMap(sourceFiles, sourceFile =>
extractUnresolvedImportsFromSourceFile(
program,
sourceFile,
ambientModules,
cachedUnresolvedImportsPerFile,
)));
tracing?.pop();
return result;
}
function extractUnresolvedImportsFromSourceFile(file: SourceFile, ambientModules: readonly string[], cachedUnresolvedImportsPerFile: Map<Path, readonly string[]>): readonly string[] {
function extractUnresolvedImportsFromSourceFile(
program: Program,
file: SourceFile,
ambientModules: readonly string[],
cachedUnresolvedImportsPerFile: Map<Path, readonly string[]>,
): readonly string[] {
return getOrUpdate(cachedUnresolvedImportsPerFile, file.path, () => {
if (!file.resolvedModules) return emptyArray;
let unresolvedImports: string[] | undefined;
file.resolvedModules.forEach(({ resolvedModule }, name) => {
program.forEachResolvedModule(({ resolvedModule }, name) => {
// pick unresolved non-relative names
if (
(!resolvedModule || !resolutionExtensionIsTSOrJson(resolvedModule.extension)) &&
@@ -2249,7 +2265,7 @@ function extractUnresolvedImportsFromSourceFile(file: SourceFile, ambientModules
) {
unresolvedImports = append(unresolvedImports, parsePackageName(name).packageName);
}
});
}, file);
return unresolvedImports || emptyArray;
});
}
@@ -2501,16 +2517,17 @@ export class AutoImportProviderProject extends Project {
);
if (entrypoints) {
const real = host.realpath?.(packageJson.packageDirectory);
const isSymlink = real && real !== packageJson.packageDirectory;
const realPath = real ? hostProject.toPath(real) : undefined;
const isSymlink = realPath && realPath !== hostProject.toPath(packageJson.packageDirectory);
if (isSymlink) {
symlinkCache.setSymlinkedDirectory(packageJson.packageDirectory, {
real,
realPath: hostProject.toPath(real),
real: ensureTrailingDirectorySeparator(real!),
realPath: ensureTrailingDirectorySeparator(realPath),
});
}
return mapDefined(entrypoints, entrypoint => {
const resolvedFileName = isSymlink ? entrypoint.replace(packageJson.packageDirectory, real) : entrypoint;
const resolvedFileName = isSymlink ? entrypoint.replace(packageJson.packageDirectory, real!) : entrypoint;
if (!program.getSourceFile(resolvedFileName) && !(isSymlink && program.getSourceFile(entrypoint))) {
return resolvedFileName;
}
@@ -2697,7 +2714,13 @@ export class ConfiguredProject extends Project {
private compilerHost?: CompilerHost;
/** @internal */
constructor(configFileName: NormalizedPath, readonly canonicalConfigFilePath: NormalizedPath, projectService: ProjectService, documentRegistry: DocumentRegistry, cachedDirectoryStructureHost: CachedDirectoryStructureHost) {
constructor(
configFileName: NormalizedPath,
readonly canonicalConfigFilePath: NormalizedPath,
projectService: ProjectService,
documentRegistry: DocumentRegistry,
cachedDirectoryStructureHost: CachedDirectoryStructureHost,
) {
super(configFileName, ProjectKind.Configured, projectService, documentRegistry, /*hasExplicitListOfFiles*/ false, /*lastFileExceededProgramSize*/ undefined, /*compilerOptions*/ {}, /*compileOnSaveEnabled*/ false, /*watchOptions*/ undefined, cachedDirectoryStructureHost, getDirectoryPath(configFileName));
}
+54 -1
View File
@@ -173,6 +173,7 @@ export const enum CommandTypes {
ProvideCallHierarchyIncomingCalls = "provideCallHierarchyIncomingCalls",
ProvideCallHierarchyOutgoingCalls = "provideCallHierarchyOutgoingCalls",
ProvideInlayHints = "provideInlayHints",
WatchChange = "watchChange",
}
/**
@@ -1956,6 +1957,17 @@ export interface CloseRequest extends FileRequest {
command: CommandTypes.Close;
}
export interface WatchChangeRequest extends Request {
command: CommandTypes.WatchChange;
arguments: WatchChangeRequestArgs;
}
export interface WatchChangeRequestArgs {
id: number;
path: string;
eventType: "create" | "delete" | "update";
}
/**
* Request to obtain the list of files that should be regenerated if target file is recompiled.
* NOTE: this us query-only operation and does not generate any output on disk.
@@ -3018,6 +3030,39 @@ export interface LargeFileReferencedEventBody {
maxFileSize: number;
}
export type CreateFileWatcherEventName = "createFileWatcher";
export interface CreateFileWatcherEvent extends Event {
readonly event: CreateFileWatcherEventName;
readonly body: CreateFileWatcherEventBody;
}
export interface CreateFileWatcherEventBody {
readonly id: number;
readonly path: string;
}
export type CreateDirectoryWatcherEventName = "createDirectoryWatcher";
export interface CreateDirectoryWatcherEvent extends Event {
readonly event: CreateDirectoryWatcherEventName;
readonly body: CreateDirectoryWatcherEventBody;
}
export interface CreateDirectoryWatcherEventBody {
readonly id: number;
readonly path: string;
readonly recursive: boolean;
}
export type CloseFileWatcherEventName = "closeFileWatcher";
export interface CloseFileWatcherEvent extends Event {
readonly event: CloseFileWatcherEventName;
readonly body: CloseFileWatcherEventBody;
}
export interface CloseFileWatcherEventBody {
readonly id: number;
}
/** @internal */
export type AnyEvent =
| RequestCompletedEvent
@@ -3029,7 +3074,10 @@ export type AnyEvent =
| ProjectLoadingStartEvent
| ProjectLoadingFinishEvent
| SurveyReadyEvent
| LargeFileReferencedEvent;
| LargeFileReferencedEvent
| CreateFileWatcherEvent
| CreateDirectoryWatcherEvent
| CloseFileWatcherEvent;
/**
* Arguments for reload request.
@@ -3599,6 +3647,11 @@ export interface UserPreferences {
* Indicates whether {@link ReferencesResponseItem.lineText} is supported.
*/
readonly disableLineTextInReferences?: boolean;
/**
* Indicates whether to exclude standard library and node_modules file symbols from navTo results.
*/
readonly excludeLibrarySymbolsInNavTo?: boolean;
}
export interface CompilerOptions {
+30 -20
View File
@@ -139,11 +139,14 @@ import {
WithMetadata,
} from "./_namespaces/ts";
import {
CloseFileWatcherEvent,
ConfigFileDiagEvent,
ConfiguredProject,
convertFormatOptions,
convertScriptKindName,
convertUserPreferences,
CreateDirectoryWatcherEvent,
CreateFileWatcherEvent,
EmitResult,
emptyArray,
Errors,
@@ -949,6 +952,7 @@ export interface SessionOptions {
* If falsy, all events are suppressed.
*/
canUseEvents: boolean;
canUseWatchEvents?: boolean;
eventHandler?: ProjectServiceEventHandler;
/** Has no effect if eventHandler is also specified. */
suppressDiagnosticEvents?: boolean;
@@ -1026,6 +1030,7 @@ export class Session<TMessage = string> implements EventSender {
typesMapLocation: opts.typesMapLocation,
serverMode: opts.serverMode,
session: this,
canUseWatchEvents: opts.canUseWatchEvents,
incrementalVerifier: opts.incrementalVerifier,
};
this.projectService = new ProjectService(settings);
@@ -1080,39 +1085,37 @@ export class Session<TMessage = string> implements EventSender {
private defaultEventHandler(event: ProjectServiceEvent) {
switch (event.eventName) {
case ProjectsUpdatedInBackgroundEvent:
const { openFiles } = event.data;
this.projectsUpdatedInBackgroundEvent(openFiles);
this.projectsUpdatedInBackgroundEvent(event.data.openFiles);
break;
case ProjectLoadingStartEvent:
const { project, reason } = event.data;
this.event<protocol.ProjectLoadingStartEventBody>(
{ projectName: project.getProjectName(), reason },
ProjectLoadingStartEvent,
);
this.event<protocol.ProjectLoadingStartEventBody>({
projectName: event.data.project.getProjectName(),
reason: event.data.reason,
}, event.eventName);
break;
case ProjectLoadingFinishEvent:
const { project: finishProject } = event.data;
this.event<protocol.ProjectLoadingFinishEventBody>({ projectName: finishProject.getProjectName() }, ProjectLoadingFinishEvent);
this.event<protocol.ProjectLoadingFinishEventBody>({
projectName: event.data.project.getProjectName(),
}, event.eventName);
break;
case LargeFileReferencedEvent:
const { file, fileSize, maxFileSize } = event.data;
this.event<protocol.LargeFileReferencedEventBody>({ file, fileSize, maxFileSize }, LargeFileReferencedEvent);
case CreateFileWatcherEvent:
case CreateDirectoryWatcherEvent:
case CloseFileWatcherEvent:
this.event(event.data, event.eventName);
break;
case ConfigFileDiagEvent:
const { triggerFile, configFileName: configFile, diagnostics } = event.data;
const bakedDiags = map(diagnostics, diagnostic => formatDiagnosticToProtocol(diagnostic, /*includeFileName*/ true));
this.event<protocol.ConfigFileDiagnosticEventBody>({
triggerFile,
configFile,
diagnostics: bakedDiags,
}, ConfigFileDiagEvent);
triggerFile: event.data.triggerFile,
configFile: event.data.configFileName,
diagnostics: map(event.data.diagnostics, diagnostic => formatDiagnosticToProtocol(diagnostic, /*includeFileName*/ true)),
}, event.eventName);
break;
case ProjectLanguageServiceStateEvent: {
const eventName: protocol.ProjectLanguageServiceStateEventName = ProjectLanguageServiceStateEvent;
this.event<protocol.ProjectLanguageServiceStateEventBody>({
projectName: event.data.project.getProjectName(),
languageServiceEnabled: event.data.languageServiceEnabled,
}, eventName);
}, event.eventName);
break;
}
case ProjectInfoTelemetryEvent: {
@@ -2613,6 +2616,7 @@ export class Session<TMessage = string> implements EventSender {
const { file, project } = this.getFileAndProject(args as protocol.FileRequestArgs);
return [{ project, navigateToItems: project.getLanguageService().getNavigateToItems(searchValue, maxResultCount, file) }];
}
const preferences = this.getHostPreferences();
const outputs: ProjectNavigateToItems[] = [];
@@ -2646,7 +2650,13 @@ export class Session<TMessage = string> implements EventSender {
// Mutates `outputs`
function addItemsForProject(project: Project) {
const projectItems = project.getLanguageService().getNavigateToItems(searchValue, maxResultCount, /*fileName*/ undefined, /*excludeDts*/ project.isNonTsProject());
const projectItems = project.getLanguageService().getNavigateToItems(
searchValue,
maxResultCount,
/*fileName*/ undefined,
/*excludeDts*/ project.isNonTsProject(),
/*excludeLibFiles*/ preferences.excludeLibrarySymbolsInNavTo,
);
const unseenItems = filter(projectItems, item => tryAddSeenItem(item) && !getMappedLocationForProject(documentSpanLocation(item), project));
if (unseenItems.length) {
outputs.push({ project, navigateToItems: unseenItems });
+2 -2
View File
@@ -361,7 +361,7 @@
"passport": "passport",
"passport-local": "passport-local",
"path": "pathjs",
"pdfkit":"pdfkit",
"pdfkit": "pdfkit",
"peer": "peerjs",
"peg": "pegjs",
"photoswipe": "photoswipe",
@@ -494,4 +494,4 @@
"ZeroClipboard": "zeroclipboard",
"ZSchema-browser": "z-schema"
}
}
}
@@ -1,12 +1,19 @@
import {
createRange,
Debug,
Diagnostics,
factory,
findNextToken,
getTokenAtPosition,
Identifier,
isArrayBindingPattern,
isArrayTypeNode,
isParameter,
ParameterDeclaration,
SourceFile,
SyntaxKind,
textChanges,
TypeNode,
} from "../_namespaces/ts";
import {
codeFixAll,
@@ -26,8 +33,8 @@ registerCodeFix({
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);
function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, start: number) {
const token = getTokenAtPosition(sourceFile, start);
const param = token.parent;
if (!isParameter(param)) {
return Debug.fail("Tried to add a parameter name to a non-parameter: " + Debug.formatSyntaxKind(token.kind));
@@ -37,14 +44,33 @@ function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: Source
Debug.assert(!param.type, "Tried to add a parameter name to a parameter that already had one.");
Debug.assert(i > -1, "Parameter not found in parent parameter list.");
const typeNode = factory.createTypeReferenceNode(param.name as Identifier, /*typeArguments*/ undefined);
let end = param.name.getEnd();
let typeNode: TypeNode = factory.createTypeReferenceNode(param.name as Identifier, /*typeArguments*/ undefined);
let nextParam = tryGetNextParam(sourceFile, param);
while (nextParam) {
typeNode = factory.createArrayTypeNode(typeNode);
end = nextParam.getEnd();
nextParam = tryGetNextParam(sourceFile, nextParam);
}
const replacement = factory.createParameterDeclaration(
param.modifiers,
param.dotDotDotToken,
"arg" + i,
param.questionToken,
param.dotDotDotToken ? factory.createArrayTypeNode(typeNode) : typeNode,
param.dotDotDotToken && !isArrayTypeNode(typeNode) ? factory.createArrayTypeNode(typeNode) : typeNode,
param.initializer,
);
changeTracker.replaceNode(sourceFile, param, replacement);
changeTracker.replaceRange(sourceFile, createRange(param.getStart(sourceFile), end), replacement);
}
function tryGetNextParam(sourceFile: SourceFile, param: ParameterDeclaration) {
const nextToken = findNextToken(param.name, param.parent, sourceFile);
if (
nextToken && nextToken.kind === SyntaxKind.OpenBracketToken
&& isArrayBindingPattern(nextToken.parent) && isParameter(nextToken.parent.parent)
) {
return nextToken.parent.parent;
}
return undefined;
}
+10 -4
View File
@@ -28,7 +28,6 @@ import {
getEmitScriptTarget,
getModeForUsageLocation,
getQuotePreference,
getResolvedModule,
getSynthesizedDeepClone,
getSynthesizedDeepClones,
getSynthesizedDeepClonesWithReplacements,
@@ -61,6 +60,7 @@ import {
NodeFlags,
ObjectLiteralElementLike,
ObjectLiteralExpression,
Program,
PropertyAccessExpression,
QuotePreference,
rangeContainsRange,
@@ -90,7 +90,7 @@ registerCodeFix({
const moduleExportsChangedToDefault = convertFileToEsModule(sourceFile, program.getTypeChecker(), changes, getEmitScriptTarget(program.getCompilerOptions()), getQuotePreference(sourceFile, preferences));
if (moduleExportsChangedToDefault) {
for (const importingFile of program.getSourceFiles()) {
fixImportOfModuleExports(importingFile, sourceFile, changes, getQuotePreference(importingFile, preferences));
fixImportOfModuleExports(importingFile, sourceFile, program, changes, getQuotePreference(importingFile, preferences));
}
}
});
@@ -99,9 +99,15 @@ registerCodeFix({
},
});
function fixImportOfModuleExports(importingFile: SourceFile, exportingFile: SourceFile, changes: textChanges.ChangeTracker, quotePreference: QuotePreference) {
function fixImportOfModuleExports(
importingFile: SourceFile,
exportingFile: SourceFile,
program: Program,
changes: textChanges.ChangeTracker,
quotePreference: QuotePreference,
) {
for (const moduleSpecifier of importingFile.imports) {
const imported = getResolvedModule(importingFile, moduleSpecifier.text, getModeForUsageLocation(importingFile, moduleSpecifier));
const imported = program.getResolvedModule(importingFile, moduleSpecifier.text, getModeForUsageLocation(importingFile, moduleSpecifier))?.resolvedModule;
if (!imported || imported.resolvedFileName !== exportingFile.fileName) {
continue;
}
@@ -68,14 +68,14 @@ function fixSingleExportDeclaration(changes: textChanges.ChangeTracker, exportSp
/*isTypeOnly*/ false,
factory.updateNamedExports(exportClause, filter(exportClause.elements, e => !contains(typeExportSpecifiers, e))),
exportDeclaration.moduleSpecifier,
/*assertClause*/ undefined,
/*attributes*/ undefined,
);
const typeExportDeclaration = factory.createExportDeclaration(
/*modifiers*/ undefined,
/*isTypeOnly*/ true,
factory.createNamedExports(typeExportSpecifiers),
exportDeclaration.moduleSpecifier,
/*assertClause*/ undefined,
/*attributes*/ undefined,
);
changes.replaceNode(context.sourceFile, exportDeclaration, valueExportDeclaration, {
@@ -125,13 +125,13 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, de
getSynthesizedDeepClones(declaration.modifiers, /*includeTrivia*/ true),
factory.createImportClause(/*isTypeOnly*/ true, getSynthesizedDeepClone(importClause.name, /*includeTrivia*/ true), /*namedBindings*/ undefined),
getSynthesizedDeepClone(declaration.moduleSpecifier, /*includeTrivia*/ true),
getSynthesizedDeepClone(declaration.assertClause, /*includeTrivia*/ true),
getSynthesizedDeepClone(declaration.attributes, /*includeTrivia*/ true),
),
factory.createImportDeclaration(
getSynthesizedDeepClones(declaration.modifiers, /*includeTrivia*/ true),
factory.createImportClause(/*isTypeOnly*/ true, /*name*/ undefined, getSynthesizedDeepClone(importClause.namedBindings, /*includeTrivia*/ true)),
getSynthesizedDeepClone(declaration.moduleSpecifier, /*includeTrivia*/ true),
getSynthesizedDeepClone(declaration.assertClause, /*includeTrivia*/ true),
getSynthesizedDeepClone(declaration.attributes, /*includeTrivia*/ true),
),
]);
}
@@ -142,7 +142,7 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, de
sameMap(importClause.namedBindings.elements, e => factory.updateImportSpecifier(e, /*isTypeOnly*/ false, e.propertyName, e.name)),
)
: importClause.namedBindings;
const importDeclaration = factory.updateImportDeclaration(declaration, declaration.modifiers, factory.updateImportClause(importClause, /*isTypeOnly*/ true, importClause.name, newNamedBindings), declaration.moduleSpecifier, declaration.assertClause);
const importDeclaration = factory.updateImportDeclaration(declaration, declaration.modifiers, factory.updateImportClause(importClause, /*isTypeOnly*/ true, importClause.name, newNamedBindings), declaration.moduleSpecifier, declaration.attributes);
changes.replaceNode(sourceFile, declaration, importDeclaration);
}
}
@@ -772,7 +772,8 @@ function createPropertyNameFromSymbol(symbol: Symbol, target: ScriptTarget, quot
const prop = checker.symbolToNode(symbol, SymbolFlags.Value, /*enclosingDeclaration*/ undefined, NodeBuilderFlags.WriteComputedProps);
if (prop && isComputedPropertyName(prop)) return prop;
}
return createPropertyNameNodeForIdentifierOrLiteral(symbol.name, target, quotePreference === QuotePreference.Single);
// We're using these nodes as property names in an object literal; no need to quote names when not needed.
return createPropertyNameNodeForIdentifierOrLiteral(symbol.name, target, quotePreference === QuotePreference.Single, /*stringNamed*/ false, /*isMethod*/ false);
}
function findScope(node: Node) {
@@ -38,6 +38,6 @@ function getImportTypeNode(sourceFile: SourceFile, pos: number): ImportTypeNode
}
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, importType: ImportTypeNode) {
const newTypeNode = factory.updateImportTypeNode(importType, importType.argument, importType.assertions, importType.qualifier, importType.typeArguments, /*isTypeOf*/ true);
const newTypeNode = factory.updateImportTypeNode(importType, importType.argument, importType.attributes, importType.qualifier, importType.typeArguments, /*isTypeOf*/ true);
changes.replaceNode(sourceFile, importType, newTypeNode);
}
@@ -10,7 +10,6 @@ import {
findLast,
firstOrUndefined,
getIsolatedModules,
getResolvedModule,
getTokenAtPosition,
Identifier,
isExportDeclaration,
@@ -120,7 +119,7 @@ function getInfo(sourceFile: SourceFile, pos: number, program: Program): Info |
const moduleSpecifier = isStringLiteral(importDeclaration.moduleSpecifier) ? importDeclaration.moduleSpecifier.text : undefined;
if (moduleSpecifier === undefined) return undefined;
const resolvedModule = getResolvedModule(sourceFile, moduleSpecifier, /*mode*/ undefined);
const resolvedModule = program.getResolvedModule(sourceFile, moduleSpecifier, /*mode*/ undefined)?.resolvedModule;
if (resolvedModule === undefined) return undefined;
const moduleSourceFile = program.getSourceFile(resolvedModule.resolvedFileName);
@@ -185,13 +184,13 @@ function updateExport(changes: textChanges.ChangeTracker, program: Program, sour
factory.createNodeArray([...namedExports, ...createExportSpecifiers(names, allowTypeModifier)], /*hasTrailingComma*/ namedExports.hasTrailingComma),
),
node.moduleSpecifier,
node.assertClause,
node.attributes,
),
);
}
function createExport(changes: textChanges.ChangeTracker, program: Program, sourceFile: SourceFile, names: ExportName[]) {
changes.insertNodeAtEndOfScope(sourceFile, sourceFile, factory.createExportDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, factory.createNamedExports(createExportSpecifiers(names, /*allowTypeModifier*/ getIsolatedModules(program.getCompilerOptions()))), /*moduleSpecifier*/ undefined, /*assertClause*/ undefined));
changes.insertNodeAtEndOfScope(sourceFile, sourceFile, factory.createExportDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, factory.createNamedExports(createExportSpecifiers(names, /*allowTypeModifier*/ getIsolatedModules(program.getCompilerOptions()))), /*moduleSpecifier*/ undefined, /*attributes*/ undefined));
}
function createExportSpecifiers(names: ExportName[], allowTypeModifier: boolean) {
+1 -2
View File
@@ -8,7 +8,6 @@ import {
getEmitScriptTarget,
getMeaningFromLocation,
getModeForUsageLocation,
getResolvedModule,
getTextOfNode,
getTokenAtPosition,
hasSyntacticModifier,
@@ -183,7 +182,7 @@ function convertSemanticMeaningToSymbolFlags(meaning: SemanticMeaning): SymbolFl
function getResolvedSourceFileFromImportDeclaration(sourceFile: SourceFile, context: CodeFixContextBase, importDeclaration: ImportDeclaration): SourceFile | undefined {
if (!importDeclaration || !isStringLiteralLike(importDeclaration.moduleSpecifier)) return undefined;
const resolvedModule = getResolvedModule(sourceFile, importDeclaration.moduleSpecifier.text, getModeForUsageLocation(sourceFile, importDeclaration.moduleSpecifier));
const resolvedModule = context.program.getResolvedModule(sourceFile, importDeclaration.moduleSpecifier.text, getModeForUsageLocation(sourceFile, importDeclaration.moduleSpecifier))?.resolvedModule;
if (!resolvedModule) return undefined;
return context.program.getSourceFile(resolvedModule.resolvedFileName);
+50 -19
View File
@@ -25,6 +25,7 @@ import {
emptyArray,
every,
ExportKind,
ExportMapInfoKey,
factory,
first,
firstDefined,
@@ -49,7 +50,6 @@ import {
getOutputExtension,
getQuoteFromPreference,
getQuotePreference,
getResolvedModule,
getSourceFileOfNode,
getSymbolId,
getTokenAtPosition,
@@ -178,7 +178,7 @@ registerCodeFix({
symbolName,
fix,
/*includeSymbolNameInDescription*/ symbolName !== errorIdentifierText,
program.getCompilerOptions(),
program,
preferences,
)
);
@@ -514,7 +514,7 @@ interface FixAddToExistingImportInfo {
export function getImportCompletionAction(
targetSymbol: Symbol,
moduleSymbol: Symbol,
exportMapKey: string | undefined,
exportMapKey: ExportMapInfoKey | undefined,
sourceFile: SourceFile,
symbolName: string,
isJsxTagName: boolean,
@@ -525,7 +525,6 @@ export function getImportCompletionAction(
preferences: UserPreferences,
cancellationToken: CancellationToken,
): { readonly moduleSpecifier: string; readonly codeAction: CodeAction; } {
const compilerOptions = program.getCompilerOptions();
let exportInfos;
if (exportMapKey) {
@@ -553,7 +552,7 @@ export function getImportCompletionAction(
symbolName,
fix,
/*includeSymbolNameInDescription*/ false,
compilerOptions,
program,
preferences,
)),
};
@@ -565,7 +564,15 @@ export function getPromoteTypeOnlyCompletionAction(sourceFile: SourceFile, symbo
const symbolName = single(getSymbolNamesToImport(sourceFile, program.getTypeChecker(), symbolToken, compilerOptions));
const fix = getTypeOnlyPromotionFix(sourceFile, symbolToken, symbolName, program);
const includeSymbolNameInDescription = symbolName !== symbolToken.text;
return fix && codeFixActionToCodeAction(codeActionForFix({ host, formatContext, preferences }, sourceFile, symbolName, fix, includeSymbolNameInDescription, compilerOptions, preferences));
return fix && codeFixActionToCodeAction(codeActionForFix(
{ host, formatContext, preferences },
sourceFile,
symbolName,
fix,
includeSymbolNameInDescription,
program,
preferences,
));
}
function getImportFixForSymbol(sourceFile: SourceFile, exportInfos: readonly SymbolExportInfo[], program: Program, position: number | undefined, isValidTypeOnlyUseSite: boolean, useRequire: boolean, host: LanguageServiceHost, preferences: UserPreferences) {
@@ -1276,14 +1283,30 @@ function getExportEqualsImportKind(importingFile: SourceFile, compilerOptions: C
return allowSyntheticDefaults ? ImportKind.Default : ImportKind.CommonJS;
}
function codeActionForFix(context: textChanges.TextChangesContext, sourceFile: SourceFile, symbolName: string, fix: ImportFix, includeSymbolNameInDescription: boolean, compilerOptions: CompilerOptions, preferences: UserPreferences): CodeFixAction {
function codeActionForFix(
context: textChanges.TextChangesContext,
sourceFile: SourceFile,
symbolName: string,
fix: ImportFix,
includeSymbolNameInDescription: boolean,
program: Program,
preferences: UserPreferences,
): CodeFixAction {
let diag!: DiagnosticOrDiagnosticAndArguments;
const changes = textChanges.ChangeTracker.with(context, tracker => {
diag = codeActionForFixWorker(tracker, sourceFile, symbolName, fix, includeSymbolNameInDescription, compilerOptions, preferences);
diag = codeActionForFixWorker(tracker, sourceFile, symbolName, fix, includeSymbolNameInDescription, program, preferences);
});
return createCodeFixAction(importFixName, changes, diag, importFixId, Diagnostics.Add_all_missing_imports);
}
function codeActionForFixWorker(changes: textChanges.ChangeTracker, sourceFile: SourceFile, symbolName: string, fix: ImportFix, includeSymbolNameInDescription: boolean, compilerOptions: CompilerOptions, preferences: UserPreferences): DiagnosticOrDiagnosticAndArguments {
function codeActionForFixWorker(
changes: textChanges.ChangeTracker,
sourceFile: SourceFile,
symbolName: string,
fix: ImportFix,
includeSymbolNameInDescription: boolean,
program: Program,
preferences: UserPreferences,
): DiagnosticOrDiagnosticAndArguments {
const quotePreference = getQuotePreference(sourceFile, preferences);
switch (fix.kind) {
case ImportFixKind.UseNamespace:
@@ -1324,7 +1347,7 @@ function codeActionForFixWorker(changes: textChanges.ChangeTracker, sourceFile:
defaultImport,
namedImports,
namespaceLikeImport,
compilerOptions,
program.getCompilerOptions(),
),
/*blankLineBetween*/ true,
preferences,
@@ -1338,7 +1361,7 @@ function codeActionForFixWorker(changes: textChanges.ChangeTracker, sourceFile:
}
case ImportFixKind.PromoteTypeOnly: {
const { typeOnlyAliasDeclaration } = fix;
const promotedDeclaration = promoteFromTypeOnly(changes, typeOnlyAliasDeclaration, compilerOptions, sourceFile, preferences);
const promotedDeclaration = promoteFromTypeOnly(changes, typeOnlyAliasDeclaration, program, sourceFile, preferences);
return promotedDeclaration.kind === SyntaxKind.ImportSpecifier
? [Diagnostics.Remove_type_from_import_of_0_from_1, symbolName, getModuleSpecifierText(promotedDeclaration.parent.parent)]
: [Diagnostics.Remove_type_from_import_declaration_from_0, getModuleSpecifierText(promotedDeclaration)];
@@ -1354,7 +1377,14 @@ function getModuleSpecifierText(promotedDeclaration: ImportClause | ImportEquals
: cast(promotedDeclaration.parent.moduleSpecifier, isStringLiteral).text;
}
function promoteFromTypeOnly(changes: textChanges.ChangeTracker, aliasDeclaration: TypeOnlyAliasDeclaration, compilerOptions: CompilerOptions, sourceFile: SourceFile, preferences: UserPreferences) {
function promoteFromTypeOnly(
changes: textChanges.ChangeTracker,
aliasDeclaration: TypeOnlyAliasDeclaration,
program: Program,
sourceFile: SourceFile,
preferences: UserPreferences,
) {
const compilerOptions = program.getCompilerOptions();
// See comment in `doAddExistingFix` on constant with the same name.
const convertExistingToTypeOnly = importNameElisionDisabled(compilerOptions);
switch (aliasDeclaration.kind) {
@@ -1362,15 +1392,16 @@ function promoteFromTypeOnly(changes: textChanges.ChangeTracker, aliasDeclaratio
if (aliasDeclaration.isTypeOnly) {
const sortKind = OrganizeImports.detectImportSpecifierSorting(aliasDeclaration.parent.elements, preferences);
if (aliasDeclaration.parent.elements.length > 1 && sortKind) {
changes.delete(sourceFile, aliasDeclaration);
const newSpecifier = factory.updateImportSpecifier(aliasDeclaration, /*isTypeOnly*/ false, aliasDeclaration.propertyName, aliasDeclaration.name);
const comparer = OrganizeImports.getOrganizeImportsComparer(preferences, sortKind === SortKind.CaseInsensitive);
const insertionIndex = OrganizeImports.getImportSpecifierInsertionIndex(aliasDeclaration.parent.elements, newSpecifier, comparer);
changes.insertImportSpecifierAtIndex(sourceFile, newSpecifier, aliasDeclaration.parent, insertionIndex);
}
else {
changes.deleteRange(sourceFile, aliasDeclaration.getFirstToken()!);
if (aliasDeclaration.parent.elements.indexOf(aliasDeclaration) !== insertionIndex) {
changes.delete(sourceFile, aliasDeclaration);
changes.insertImportSpecifierAtIndex(sourceFile, newSpecifier, aliasDeclaration.parent, insertionIndex);
return aliasDeclaration;
}
}
changes.deleteRange(sourceFile, aliasDeclaration.getFirstToken()!);
return aliasDeclaration;
}
else {
@@ -1396,7 +1427,7 @@ function promoteFromTypeOnly(changes: textChanges.ChangeTracker, aliasDeclaratio
// Change .ts extension to .js if necessary
if (!compilerOptions.allowImportingTsExtensions) {
const moduleSpecifier = tryGetModuleSpecifierFromDeclaration(importClause.parent);
const resolvedModule = moduleSpecifier && getResolvedModule(sourceFile, moduleSpecifier.text, getModeForUsageLocation(sourceFile, moduleSpecifier));
const resolvedModule = moduleSpecifier && program.getResolvedModule(sourceFile, moduleSpecifier.text, getModeForUsageLocation(sourceFile, moduleSpecifier))?.resolvedModule;
if (resolvedModule?.resolvedUsingTsExtension) {
const changedExtension = changeAnyExtension(moduleSpecifier!.text, getOutputExtension(moduleSpecifier!.text, compilerOptions));
changes.replaceNode(sourceFile, moduleSpecifier!, factory.createStringLiteral(changedExtension));
@@ -1624,7 +1655,7 @@ function getNewImports(
factory.createNamespaceImport(factory.createIdentifier(namespaceLikeImport.name)),
),
quotedModuleSpecifier,
/*assertClause*/ undefined,
/*attributes*/ undefined,
);
statements = combine(statements, declaration);
}
+1 -1
View File
@@ -57,7 +57,7 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, in
statement,
defaultImportName && !allowSyntheticDefaults
? factory.createImportEqualsDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, defaultImportName, factory.createExternalModuleReference(required))
: factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, namedImports), required, /*assertClause*/ undefined),
: factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, namedImports), required, /*attributes*/ undefined),
);
}
@@ -53,7 +53,7 @@ function splitTypeOnlyImport(changes: textChanges.ChangeTracker, importDeclarati
importDeclaration.modifiers,
factory.updateImportClause(importClause, importClause.isTypeOnly, importClause.name, /*namedBindings*/ undefined),
importDeclaration.moduleSpecifier,
importDeclaration.assertClause,
importDeclaration.attributes,
),
);
@@ -64,7 +64,7 @@ function splitTypeOnlyImport(changes: textChanges.ChangeTracker, importDeclarati
/*modifiers*/ undefined,
factory.updateImportClause(importClause, importClause.isTypeOnly, /*name*/ undefined, importClause.namedBindings),
importDeclaration.moduleSpecifier,
importDeclaration.assertClause,
importDeclaration.attributes,
),
);
}
+3 -2
View File
@@ -58,6 +58,7 @@ import {
escapeSnippetText,
every,
ExportKind,
ExportMapInfoKey,
Expression,
ExpressionWithTypeArguments,
factory,
@@ -485,14 +486,14 @@ interface SymbolOriginInfoExport extends SymbolOriginInfo {
moduleSymbol: Symbol;
isDefaultExport: boolean;
exportName: string;
exportMapKey: string;
exportMapKey: ExportMapInfoKey;
}
interface SymbolOriginInfoResolvedExport extends SymbolOriginInfo {
symbolName: string;
moduleSymbol: Symbol;
exportName: string;
exportMapKey?: string;
exportMapKey?: ExportMapInfoKey;
moduleSpecifier: string;
}
+6 -3
View File
@@ -16,6 +16,7 @@ import {
identity,
IScriptSnapshot,
isDeclarationFileName,
JSDocParsingMode,
MinimalResolutionCacheHost,
Path,
ResolutionMode,
@@ -178,14 +179,14 @@ export function isDocumentRegistryEntry(entry: BucketEntry): entry is DocumentRe
return !!(entry as DocumentRegistryEntry).sourceFile;
}
export function createDocumentRegistry(useCaseSensitiveFileNames?: boolean, currentDirectory?: string): DocumentRegistry {
return createDocumentRegistryInternal(useCaseSensitiveFileNames, currentDirectory);
export function createDocumentRegistry(useCaseSensitiveFileNames?: boolean, currentDirectory?: string, jsDocParsingMode?: JSDocParsingMode): DocumentRegistry {
return createDocumentRegistryInternal(useCaseSensitiveFileNames, currentDirectory, jsDocParsingMode);
}
/** @internal */
export type DocumentRegistryBucketKeyWithMode = string & { __documentRegistryBucketKeyWithMode: any; };
/** @internal */
export function createDocumentRegistryInternal(useCaseSensitiveFileNames?: boolean, currentDirectory = "", externalCache?: ExternalDocumentCache): DocumentRegistry {
export function createDocumentRegistryInternal(useCaseSensitiveFileNames?: boolean, currentDirectory = "", jsDocParsingMode?: JSDocParsingMode, externalCache?: ExternalDocumentCache): DocumentRegistry {
// Maps from compiler setting target (ES3, ES5, etc.) to all the cached documents we have
// for those settings.
const buckets = new Map<DocumentRegistryBucketKeyWithMode, Map<Path, BucketEntry>>();
@@ -270,8 +271,10 @@ export function createDocumentRegistryInternal(useCaseSensitiveFileNames?: boole
languageVersion: scriptTarget,
impliedNodeFormat: host && getImpliedNodeFormatForFile(path, host.getCompilerHost?.()?.getModuleResolutionCache?.()?.getPackageJsonInfoCache(), host, compilationSettings),
setExternalModuleIndicator: getSetExternalModuleIndicator(compilationSettings),
jsDocParsingMode,
};
sourceFileOptions.languageVersion = scriptTarget;
Debug.assertEqual(jsDocParsingMode, sourceFileOptions.jsDocParsingMode);
const oldBucketCount = buckets.size;
const keyWithMode = getDocumentRegistryBucketKeyWithMode(key, sourceFileOptions.impliedNodeFormat);
const bucket = getOrUpdate(buckets, keyWithMode, () => new Map());
+15 -9
View File
@@ -112,8 +112,8 @@ export interface ExportInfoMap {
isUsableByFile(importingFile: Path): boolean;
clear(): void;
add(importingFile: Path, symbol: Symbol, key: __String, moduleSymbol: Symbol, moduleFile: SourceFile | undefined, exportKind: ExportKind, isFromPackageJson: boolean, checker: TypeChecker): void;
get(importingFile: Path, key: string): readonly SymbolExportInfo[] | undefined;
search<T>(importingFile: Path, preferCapitalized: boolean, matches: (name: string, targetFlags: SymbolFlags) => boolean, action: (info: readonly SymbolExportInfo[], symbolName: string, isFromAmbientModule: boolean, key: string) => T | undefined): T | undefined;
get(importingFile: Path, key: ExportMapInfoKey): readonly SymbolExportInfo[] | undefined;
search<T>(importingFile: Path, preferCapitalized: boolean, matches: (name: string, targetFlags: SymbolFlags) => boolean, action: (info: readonly SymbolExportInfo[], symbolName: string, isFromAmbientModule: boolean, key: ExportMapInfoKey) => T | undefined): T | undefined;
releaseSymbols(): void;
isEmpty(): boolean;
/** @returns Whether the change resulted in the cache being cleared */
@@ -127,10 +127,11 @@ export interface CacheableExportInfoMapHost {
getGlobalTypingsCacheLocation(): string | undefined;
}
export type ExportMapInfoKey = string & { __exportInfoKey: void; };
/** @internal */
export function createCacheableExportInfoMap(host: CacheableExportInfoMapHost): ExportInfoMap {
let exportInfoId = 1;
const exportInfo = createMultiMap<string, CachedSymbolExportInfo>();
const exportInfo = createMultiMap<ExportMapInfoKey, CachedSymbolExportInfo>();
const symbols = new Map<number, [symbol: Symbol, moduleSymbol: Symbol]>();
/**
* Key: node_modules package name (no @types).
@@ -266,7 +267,7 @@ export function createCacheableExportInfoMap(host: CacheableExportInfoMapHost):
},
};
if (Debug.isDebugging) {
Object.defineProperty(cache, "__cache", { get: () => exportInfo });
Object.defineProperty(cache, "__cache", { value: exportInfo });
}
return cache;
@@ -309,14 +310,19 @@ export function createCacheableExportInfoMap(host: CacheableExportInfoMapHost):
};
}
function key(importedName: string, symbol: Symbol, ambientModuleName: string | undefined, checker: TypeChecker): string {
function key(importedName: string, symbol: Symbol, ambientModuleName: string | undefined, checker: TypeChecker) {
const moduleKey = ambientModuleName || "";
return `${importedName}|${getSymbolId(skipAlias(symbol, checker))}|${moduleKey}`;
return `${importedName.length} ${getSymbolId(skipAlias(symbol, checker))} ${importedName} ${moduleKey}` as ExportMapInfoKey;
}
function parseKey(key: string) {
const symbolName = key.substring(0, key.indexOf("|"));
const moduleKey = key.substring(key.lastIndexOf("|") + 1);
function parseKey(key: ExportMapInfoKey) {
const firstSpace = key.indexOf(" ");
const secondSpace = key.indexOf(" ", firstSpace + 1);
const symbolNameLength = parseInt(key.substring(0, firstSpace), 10);
const data = key.substring(secondSpace + 1);
const symbolName = data.substring(0, symbolNameLength);
const moduleKey = data.substring(symbolNameLength + 1);
const ambientModuleName = moduleKey === "" ? undefined : moduleKey;
return { symbolName, ambientModuleName };
}
+2 -2
View File
@@ -1009,7 +1009,7 @@ export namespace Core {
if (!options.implementations && isStringLiteralLike(node)) {
if (isModuleSpecifierLike(node)) {
const fileIncludeReasons = program.getFileIncludeReasons();
const referencedFileName = node.getSourceFile().resolvedModules?.get(node.text, getModeForUsageLocation(node.getSourceFile(), node))?.resolvedModule?.resolvedFileName;
const referencedFileName = program.getResolvedModule(node.getSourceFile(), node.text, getModeForUsageLocation(node.getSourceFile(), node))?.resolvedModule?.resolvedFileName;
const referencedFile = referencedFileName ? program.getSourceFile(referencedFileName) : undefined;
if (referencedFile) {
return [{ definition: { type: DefinitionKind.String, node }, references: getReferencesForNonModule(referencedFile, fileIncludeReasons, program) || emptyArray }];
@@ -1066,7 +1066,7 @@ export namespace Core {
for (const ref of references) {
if (isReferencedFile(ref)) {
const referencingFile = program.getSourceFileByPath(ref.file)!;
const location = getReferencedFileLocation(program.getSourceFileByPath, ref);
const location = getReferencedFileLocation(program, ref);
if (isReferenceFileLocation(location)) {
entries = append(entries, {
kind: EntryKind.Span,
+9 -1
View File
@@ -106,7 +106,7 @@ export function getAllRules(): RuleSpec[] {
rule("SpaceAfterQuestionMarkInConditionalOperator", SyntaxKind.QuestionToken, anyToken, [isNonJsxSameLineTokenContext, isConditionalOperatorContext], RuleAction.InsertSpace),
// in other cases there should be no space between '?' and next token
rule("NoSpaceAfterQuestionMark", SyntaxKind.QuestionToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace),
rule("NoSpaceAfterQuestionMark", SyntaxKind.QuestionToken, anyToken, [isNonJsxSameLineTokenContext, isNonOptionalPropertyContext], RuleAction.DeleteSpace),
rule("NoSpaceBeforeDot", anyToken, [SyntaxKind.DotToken, SyntaxKind.QuestionDotToken], [isNonJsxSameLineTokenContext, isNotPropertyAccessOnIntegerLiteral], RuleAction.DeleteSpace),
rule("NoSpaceAfterDot", [SyntaxKind.DotToken, SyntaxKind.QuestionDotToken], anyToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace),
@@ -561,6 +561,14 @@ function isTypeAnnotationContext(context: FormattingContext): boolean {
isFunctionLikeKind(contextKind);
}
function isOptionalPropertyContext(context: FormattingContext) {
return isPropertyDeclaration(context.contextNode) && context.contextNode.questionToken;
}
function isNonOptionalPropertyContext(context: FormattingContext) {
return !isOptionalPropertyContext(context);
}
function isConditionalOperatorContext(context: FormattingContext): boolean {
return context.contextNode.kind === SyntaxKind.ConditionalExpression ||
context.contextNode.kind === SyntaxKind.ConditionalType;
+1 -1
View File
@@ -249,7 +249,7 @@ function getSourceFileToImport(
else {
const mode = getModeForUsageLocation(importingSourceFile, importLiteral);
const resolved = host.resolveModuleNameLiterals || !host.resolveModuleNames ?
importingSourceFile.resolvedModules?.get(importLiteral.text, mode) :
program.getResolvedModule(importingSourceFile, importLiteral.text, mode) :
host.getResolvedModuleWithFailedLookupLocationsFromCache && host.getResolvedModuleWithFailedLookupLocationsFromCache(importLiteral.text, importingSourceFile.fileName, mode);
return getSourceFileToImportFromResolved(importLiteral, resolved, oldToNew, program.getSourceFiles());
}
+6 -4
View File
@@ -82,6 +82,7 @@ import {
NodeFlags,
ObjectFlags,
Program,
ResolvedModuleWithFailedLookupLocations,
resolvePath,
ScriptElementKind,
SignatureDeclaration,
@@ -179,7 +180,7 @@ export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile
if (!symbol && isModuleSpecifierLike(fallbackNode)) {
// We couldn't resolve the module specifier as an external module, but it could
// be that module resolution succeeded but the target was not a module.
const ref = sourceFile.resolvedModules?.get(fallbackNode.text, getModeForUsageLocation(sourceFile, fallbackNode))?.resolvedModule;
const ref = program.getResolvedModule(sourceFile, fallbackNode.text, getModeForUsageLocation(sourceFile, fallbackNode))?.resolvedModule;
if (ref) {
return [{
name: fallbackNode.text,
@@ -332,10 +333,11 @@ export function getReferenceAtPosition(sourceFile: SourceFile, position: number,
return file && { reference: libReferenceDirective, fileName: file.fileName, file, unverified: false };
}
if (sourceFile.resolvedModules?.size()) {
if (sourceFile.imports.length || sourceFile.moduleAugmentations.length) {
const node = getTouchingToken(sourceFile, position);
if (isModuleSpecifierLike(node) && isExternalModuleNameRelative(node.text) && sourceFile.resolvedModules.has(node.text, getModeForUsageLocation(sourceFile, node))) {
const verifiedFileName = sourceFile.resolvedModules.get(node.text, getModeForUsageLocation(sourceFile, node))?.resolvedModule?.resolvedFileName;
let resolution: ResolvedModuleWithFailedLookupLocations | undefined;
if (isModuleSpecifierLike(node) && isExternalModuleNameRelative(node.text) && (resolution = program.getResolvedModule(sourceFile, node.text, getModeForUsageLocation(sourceFile, node)))) {
const verifiedFileName = resolution.resolvedModule?.resolvedFileName;
const fileName = verifiedFileName || resolvePath(getDirectoryPath(sourceFile.fileName), node.text);
return {
file: program.getSourceFile(fileName),
+343 -13
View File
@@ -1,7 +1,10 @@
import {
__String,
ArrayTypeNode,
ArrowFunction,
CallExpression,
ConditionalTypeNode,
ConstructorTypeNode,
createPrinterWithRemoveComments,
createTextSpanFromNode,
Debug,
@@ -16,17 +19,24 @@ import {
FunctionDeclaration,
FunctionExpression,
FunctionLikeDeclaration,
FunctionTypeNode,
GetAccessorDeclaration,
getEffectiveReturnTypeNode,
getEffectiveTypeAnnotationNode,
getLanguageVariant,
getLeadingCommentRanges,
getNameOfDeclaration,
hasContextSensitiveParameters,
Identifier,
idText,
ImportTypeNode,
IndexedAccessTypeNode,
InferTypeNode,
InlayHint,
InlayHintDisplayPart,
InlayHintKind,
InlayHintsContext,
IntersectionTypeNode,
isArrowFunction,
isAssertionExpression,
isBindingPattern,
@@ -52,30 +62,48 @@ import {
isTypeNode,
isVarConst,
isVariableDeclaration,
LiteralTypeNode,
MappedTypeNode,
MethodDeclaration,
NamedTupleMember,
NewExpression,
Node,
NodeArray,
NodeBuilderFlags,
NumericLiteral,
OptionalTypeNode,
ParameterDeclaration,
ParenthesizedTypeNode,
PrefixUnaryExpression,
PropertyDeclaration,
PropertySignature,
QualifiedName,
RestTypeNode,
Signature,
skipParentheses,
some,
StringLiteral,
Symbol,
SymbolFlags,
SyntaxKind,
textSpanIntersectsWith,
tokenToString,
TupleTypeNode,
TupleTypeReference,
Type,
TypeLiteralNode,
TypeOperatorNode,
TypeParameterDeclaration,
TypePredicateNode,
TypeQueryNode,
TypeReferenceNode,
unescapeLeadingUnderscores,
UnionTypeNode,
UserPreferences,
usingSingleLineStringWriter,
VariableDeclaration,
} from "./_namespaces/ts";
const maxTypeHintLength = 30;
const leadingParameterNameCommentRegexFactory = (name: string) => {
return new RegExp(`^\\s?/\\*\\*?\\s?${name}\\s?\\*\\/\\s?$`);
};
@@ -176,9 +204,10 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] {
});
}
function addTypeHints(text: string, position: number) {
function addTypeHints(hintText: string | InlayHintDisplayPart[], position: number) {
result.push({
text: `: ${text.length > maxTypeHintLength ? text.substr(0, maxTypeHintLength - "...".length) + "..." : text}`,
text: typeof hintText === "string" ? `: ${hintText}` : "",
displayParts: typeof hintText === "string" ? undefined : [{ text: ": " }, ...hintText],
position,
kind: InlayHintKind.Type,
whitespaceBefore: true,
@@ -224,13 +253,14 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] {
return;
}
const typeDisplayString = printTypeInSingleLine(declarationType);
if (typeDisplayString) {
const isVariableNameMatchesType = preferences.includeInlayVariableTypeHintsWhenTypeMatchesName === false && equateStringsCaseInsensitive(decl.name.getText(), typeDisplayString);
const hints = typeToInlayHintParts(declarationType);
if (hints) {
const hintText = typeof hints === "string" ? hints : hints.map(part => part.text).join("");
const isVariableNameMatchesType = preferences.includeInlayVariableTypeHintsWhenTypeMatchesName === false && equateStringsCaseInsensitive(decl.name.getText(), hintText);
if (isVariableNameMatchesType) {
return;
}
addTypeHints(typeDisplayString, decl.name.end);
addTypeHints(hints, decl.name.end);
}
}
@@ -355,12 +385,10 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] {
return;
}
const typeDisplayString = printTypeInSingleLine(returnType);
if (!typeDisplayString) {
return;
const hint = typeToInlayHintParts(returnType);
if (hint) {
addTypeHints(hint, getTypeAnnotationPosition(decl));
}
addTypeHints(typeDisplayString, getTypeAnnotationPosition(decl));
}
function getTypeAnnotationPosition(decl: FunctionDeclaration | ArrowFunction | FunctionExpression | MethodDeclaration | GetAccessorDeclaration) {
@@ -422,6 +450,308 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] {
});
}
function typeToInlayHintParts(type: Type): InlayHintDisplayPart[] | string {
if (!shouldUseInteractiveInlayHints(preferences)) {
return printTypeInSingleLine(type);
}
const flags = NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.AllowUniqueESSymbolType | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;
const typeNode = checker.typeToTypeNode(type, /*enclosingDeclaration*/ undefined, flags);
Debug.assertIsDefined(typeNode, "should always get typenode");
const parts: InlayHintDisplayPart[] = [];
visitForDisplayParts(typeNode);
return parts;
function visitForDisplayParts(node: Node) {
if (!node) {
return;
}
const tokenString = tokenToString(node.kind);
if (tokenString) {
parts.push({ text: tokenString });
return;
}
switch (node.kind) {
case SyntaxKind.Identifier:
const identifier = node as Identifier;
const identifierText = idText(identifier);
const name = identifier.symbol && identifier.symbol.declarations && identifier.symbol.declarations.length && getNameOfDeclaration(identifier.symbol.declarations[0]);
if (name) {
parts.push(getNodeDisplayPart(identifierText, name));
}
else {
parts.push({ text: identifierText });
}
break;
case SyntaxKind.NumericLiteral:
parts.push({ text: (node as NumericLiteral).text });
break;
case SyntaxKind.StringLiteral:
parts.push({ text: `"${(node as StringLiteral).text}"` });
break;
case SyntaxKind.QualifiedName:
const qualifiedName = node as QualifiedName;
visitForDisplayParts(qualifiedName.left);
parts.push({ text: "." });
visitForDisplayParts(qualifiedName.right);
break;
case SyntaxKind.TypePredicate:
const predicate = node as TypePredicateNode;
if (predicate.assertsModifier) {
parts.push({ text: "asserts " });
}
visitForDisplayParts(predicate.parameterName);
if (predicate.type) {
parts.push({ text: " is " });
visitForDisplayParts(predicate.type);
}
break;
case SyntaxKind.TypeReference:
const typeReference = node as TypeReferenceNode;
visitForDisplayParts(typeReference.typeName);
if (typeReference.typeArguments) {
parts.push({ text: "<" });
visitDisplayPartList(typeReference.typeArguments, ", ");
parts.push({ text: ">" });
}
break;
case SyntaxKind.TypeParameter:
const typeParameter = node as TypeParameterDeclaration;
if (typeParameter.modifiers) {
visitDisplayPartList(typeParameter.modifiers, " ");
}
visitForDisplayParts(typeParameter.name);
if (typeParameter.constraint) {
parts.push({ text: " extends " });
visitForDisplayParts(typeParameter.constraint);
}
if (typeParameter.default) {
parts.push({ text: " = " });
visitForDisplayParts(typeParameter.default);
}
break;
case SyntaxKind.Parameter:
const parameter = node as ParameterDeclaration;
if (parameter.modifiers) {
visitDisplayPartList(parameter.modifiers, " ");
}
if (parameter.dotDotDotToken) {
parts.push({ text: "..." });
}
visitForDisplayParts(parameter.name);
if (parameter.questionToken) {
parts.push({ text: "?" });
}
if (parameter.type) {
parts.push({ text: ": " });
visitForDisplayParts(parameter.type);
}
break;
case SyntaxKind.ConstructorType:
const constructorType = node as ConstructorTypeNode;
parts.push({ text: "new " });
if (constructorType.typeParameters) {
parts.push({ text: "<" });
visitDisplayPartList(constructorType.typeParameters, ", ");
parts.push({ text: ">" });
}
parts.push({ text: "(" });
visitDisplayPartList(constructorType.parameters, ", ");
parts.push({ text: ")" });
parts.push({ text: " => " });
visitForDisplayParts(constructorType.type);
break;
case SyntaxKind.TypeQuery:
const typeQuery = node as TypeQueryNode;
parts.push({ text: "typeof " });
visitForDisplayParts(typeQuery.exprName);
if (typeQuery.typeArguments) {
parts.push({ text: "<" });
visitDisplayPartList(typeQuery.typeArguments, ", ");
parts.push({ text: ">" });
}
break;
case SyntaxKind.TypeLiteral:
const typeLiteral = node as TypeLiteralNode;
parts.push({ text: "{" });
if (typeLiteral.members.length) {
parts.push({ text: " " });
visitDisplayPartList(typeLiteral.members, "; ");
parts.push({ text: " " });
}
parts.push({ text: "}" });
break;
case SyntaxKind.ArrayType:
visitForDisplayParts((node as ArrayTypeNode).elementType);
parts.push({ text: "[]" });
break;
case SyntaxKind.TupleType:
parts.push({ text: "[" });
visitDisplayPartList((node as TupleTypeNode).elements, ", ");
parts.push({ text: "]" });
break;
case SyntaxKind.NamedTupleMember:
const member = node as NamedTupleMember;
if (member.dotDotDotToken) {
parts.push({ text: "..." });
}
visitForDisplayParts(member.name);
if (member.questionToken) {
parts.push({ text: "?" });
}
parts.push({ text: ": " });
visitForDisplayParts(member.type);
break;
case SyntaxKind.OptionalType:
visitForDisplayParts((node as OptionalTypeNode).type);
parts.push({ text: "?" });
break;
case SyntaxKind.RestType:
parts.push({ text: "..." });
visitForDisplayParts((node as RestTypeNode).type);
break;
case SyntaxKind.UnionType:
visitDisplayPartList((node as UnionTypeNode).types, " | ");
break;
case SyntaxKind.IntersectionType:
visitDisplayPartList((node as IntersectionTypeNode).types, " & ");
break;
case SyntaxKind.ConditionalType:
const conditionalType = node as ConditionalTypeNode;
visitForDisplayParts(conditionalType.checkType);
parts.push({ text: " extends " });
visitForDisplayParts(conditionalType.extendsType);
parts.push({ text: " ? " });
visitForDisplayParts(conditionalType.trueType);
parts.push({ text: " : " });
visitForDisplayParts(conditionalType.falseType);
break;
case SyntaxKind.InferType:
parts.push({ text: "infer " });
visitForDisplayParts((node as InferTypeNode).typeParameter);
break;
case SyntaxKind.ParenthesizedType:
parts.push({ text: "(" });
visitForDisplayParts((node as ParenthesizedTypeNode).type);
parts.push({ text: ")" });
break;
case SyntaxKind.TypeOperator:
const typeOperator = node as TypeOperatorNode;
parts.push({ text: `${tokenToString(typeOperator.operator)} ` });
visitForDisplayParts(typeOperator.type);
break;
case SyntaxKind.IndexedAccessType:
const indexedAccess = node as IndexedAccessTypeNode;
visitForDisplayParts(indexedAccess.objectType);
parts.push({ text: "[" });
visitForDisplayParts(indexedAccess.indexType);
parts.push({ text: "]" });
break;
case SyntaxKind.MappedType:
const mappedType = node as MappedTypeNode;
parts.push({ text: "{ " });
if (mappedType.readonlyToken) {
if (mappedType.readonlyToken.kind === SyntaxKind.PlusToken) {
parts.push({ text: "+" });
}
else if (mappedType.readonlyToken.kind === SyntaxKind.MinusToken) {
parts.push({ text: "-" });
}
parts.push({ text: "readonly " });
}
parts.push({ text: "[" });
visitForDisplayParts(mappedType.typeParameter);
if (mappedType.nameType) {
parts.push({ text: " as " });
visitForDisplayParts(mappedType.nameType);
}
parts.push({ text: "]" });
if (mappedType.questionToken) {
if (mappedType.questionToken.kind === SyntaxKind.PlusToken) {
parts.push({ text: "+" });
}
else if (mappedType.questionToken.kind === SyntaxKind.MinusToken) {
parts.push({ text: "-" });
}
parts.push({ text: "?" });
}
parts.push({ text: ": " });
if (mappedType.type) {
visitForDisplayParts(mappedType.type);
}
parts.push({ text: "; }" });
break;
case SyntaxKind.LiteralType:
visitForDisplayParts((node as LiteralTypeNode).literal);
break;
case SyntaxKind.FunctionType:
const functionType = node as FunctionTypeNode;
if (functionType.typeParameters) {
parts.push({ text: "<" });
visitDisplayPartList(functionType.typeParameters, ", ");
parts.push({ text: ">" });
}
parts.push({ text: "(" });
visitDisplayPartList(functionType.parameters, ", ");
parts.push({ text: ")" });
parts.push({ text: " => " });
visitForDisplayParts(functionType.type);
break;
case SyntaxKind.ImportType:
const importType = node as ImportTypeNode;
if (importType.isTypeOf) {
parts.push({ text: "typeof " });
}
parts.push({ text: "import(" });
visitForDisplayParts(importType.argument);
if (importType.assertions) {
parts.push({ text: ", { assert: " });
visitDisplayPartList(importType.assertions.assertClause.elements, ", ");
parts.push({ text: " }" });
}
parts.push({ text: ")" });
if (importType.qualifier) {
parts.push({ text: "." });
visitForDisplayParts(importType.qualifier);
}
if (importType.typeArguments) {
parts.push({ text: "<" });
visitDisplayPartList(importType.typeArguments, ", ");
parts.push({ text: ">" });
}
break;
case SyntaxKind.PropertySignature:
const propertySignature = node as PropertySignature;
if (propertySignature.modifiers) {
visitDisplayPartList(propertySignature.modifiers, " ");
}
visitForDisplayParts(propertySignature.name);
if (propertySignature.questionToken) {
parts.push({ text: "?" });
}
if (propertySignature.type) {
parts.push({ text: ": " });
visitForDisplayParts(propertySignature.type);
}
break;
default:
Debug.failBadSyntaxKind(node);
}
}
function visitDisplayPartList<T extends Node>(nodes: NodeArray<T>, separator: string) {
nodes.forEach((node, index) => {
if (index > 0) {
parts.push({ text: separator });
}
visitForDisplayParts(node);
});
}
}
function isUndefined(name: __String) {
return name === "undefined";
}
+8
View File
@@ -44,6 +44,8 @@ import {
isIdentifier,
isJSDoc,
isJSDocParameterTag,
isJSDocPropertyLikeTag,
isJSDocTypeLiteral,
isWhiteSpaceSingleLine,
JSDoc,
JSDocAugmentsTag,
@@ -250,6 +252,12 @@ export function getJsDocTagsFromDeclarations(declarations?: Declaration[], check
}
for (const tag of tags) {
infos.push({ name: tag.tagName.text, text: getCommentDisplayParts(tag, checker) });
if (isJSDocPropertyLikeTag(tag) && tag.isNameFirst && tag.typeExpression && isJSDocTypeLiteral(tag.typeExpression.type)) {
forEach(tag.typeExpression.type.jsDocPropertyTags, propTag => {
infos.push({ name: propTag.tagName.text, text: getCommentDisplayParts(propTag, checker) });
});
}
}
});
return infos;
+35 -7
View File
@@ -16,6 +16,7 @@ import {
ImportClause,
ImportEqualsDeclaration,
ImportSpecifier,
isInsideNodeModules,
isPropertyAccessExpression,
isPropertyNameLiteral,
NavigateToItem,
@@ -37,11 +38,11 @@ interface RawNavigateToItem {
}
/** @internal */
export function getNavigateToItems(sourceFiles: readonly SourceFile[], checker: TypeChecker, cancellationToken: CancellationToken, searchValue: string, maxResultCount: number | undefined, excludeDtsFiles: boolean): NavigateToItem[] {
export function getNavigateToItems(sourceFiles: readonly SourceFile[], checker: TypeChecker, cancellationToken: CancellationToken, searchValue: string, maxResultCount: number | undefined, excludeDtsFiles: boolean, excludeLibFiles?: boolean): NavigateToItem[] {
const patternMatcher = createPatternMatcher(searchValue);
if (!patternMatcher) return emptyArray;
const rawItems: RawNavigateToItem[] = [];
const singleCurrentFile = sourceFiles.length === 1 ? sourceFiles[0] : undefined;
// Search the declarations in all files and output matched NavigateToItem into array of NavigateToItem[]
for (const sourceFile of sourceFiles) {
cancellationToken.throwIfCancellationRequested();
@@ -50,8 +51,12 @@ export function getNavigateToItems(sourceFiles: readonly SourceFile[], checker:
continue;
}
if (shouldExcludeFile(sourceFile, !!excludeLibFiles, singleCurrentFile)) {
continue;
}
sourceFile.getNamedDeclarations().forEach((declarations, name) => {
getItemsFromNamedDeclaration(patternMatcher, name, declarations, checker, sourceFile.fileName, rawItems);
getItemsFromNamedDeclaration(patternMatcher, name, declarations, checker, sourceFile.fileName, !!excludeLibFiles, singleCurrentFile, rawItems);
});
}
@@ -59,7 +64,24 @@ export function getNavigateToItems(sourceFiles: readonly SourceFile[], checker:
return (maxResultCount === undefined ? rawItems : rawItems.slice(0, maxResultCount)).map(createNavigateToItem);
}
function getItemsFromNamedDeclaration(patternMatcher: PatternMatcher, name: string, declarations: readonly Declaration[], checker: TypeChecker, fileName: string, rawItems: RawNavigateToItem[]): void {
/**
* Exclude 'node_modules/' files and standard library files if 'excludeLibFiles' is true.
* If we're in current file only mode, we don't exclude the current file, even if it is a library file.
*/
function shouldExcludeFile(file: SourceFile, excludeLibFiles: boolean, singleCurrentFile: SourceFile | undefined): boolean {
return file !== singleCurrentFile && excludeLibFiles && (isInsideNodeModules(file.path) || file.hasNoDefaultLib);
}
function getItemsFromNamedDeclaration(
patternMatcher: PatternMatcher,
name: string,
declarations: readonly Declaration[],
checker: TypeChecker,
fileName: string,
excludeLibFiles: boolean,
singleCurrentFile: SourceFile | undefined,
rawItems: RawNavigateToItem[],
): void {
// First do a quick check to see if the name of the declaration matches the
// last portion of the (possibly) dotted name they're searching for.
const match = patternMatcher.getMatchForLastSegmentOfPattern(name);
@@ -68,7 +90,7 @@ function getItemsFromNamedDeclaration(patternMatcher: PatternMatcher, name: stri
}
for (const declaration of declarations) {
if (!shouldKeepItem(declaration, checker)) continue;
if (!shouldKeepItem(declaration, checker, excludeLibFiles, singleCurrentFile)) continue;
if (patternMatcher.patternContainsDots) {
// If the pattern has dots in it, then also see if the declaration container matches as well.
@@ -83,14 +105,20 @@ function getItemsFromNamedDeclaration(patternMatcher: PatternMatcher, name: stri
}
}
function shouldKeepItem(declaration: Declaration, checker: TypeChecker): boolean {
function shouldKeepItem(
declaration: Declaration,
checker: TypeChecker,
excludeLibFiles: boolean,
singleCurrentFile: SourceFile | undefined,
): boolean {
switch (declaration.kind) {
case SyntaxKind.ImportClause:
case SyntaxKind.ImportSpecifier:
case SyntaxKind.ImportEqualsDeclaration:
const importer = checker.getSymbolAtLocation((declaration as ImportClause | ImportSpecifier | ImportEqualsDeclaration).name!)!; // TODO: GH#18217
const imported = checker.getAliasedSymbol(importer);
return importer.escapedName !== imported.escapedName;
return importer.escapedName !== imported.escapedName
&& !imported.declarations?.every(d => shouldExcludeFile(d.getSourceFile(), excludeLibFiles, singleCurrentFile));
default:
return true;
}
+12 -14
View File
@@ -47,10 +47,8 @@ import {
getSyntacticModifierFlags,
getTextOfIdentifierOrLiteral,
getTextOfNode,
hasDynamicName,
hasJSDocNodes,
Identifier,
idText,
ImportClause,
InterfaceDeclaration,
InternalSymbolName,
@@ -62,8 +60,10 @@ import {
isCallExpression,
isClassDeclaration,
isClassLike,
isComputedPropertyName,
isDeclaration,
isElementAccessExpression,
isEntityNameExpression,
isExportAssignment,
isExpression,
isExternalModule,
@@ -73,6 +73,7 @@ import {
isJSDocTypeAlias,
isModuleBlock,
isModuleDeclaration,
isNumericLiteral,
isObjectLiteralExpression,
isParameterPropertyDeclaration,
isPrivateIdentifier,
@@ -82,6 +83,7 @@ import {
isPropertyNameLiteral,
isStatic,
isStringLiteralLike,
isStringOrNumericLiteralLike,
isToken,
isVariableDeclaration,
lastOrUndefined,
@@ -306,19 +308,15 @@ function addNodeWithRecursiveInitializer(node: VariableDeclaration | PropertyAss
}
}
/**
* Historically, we've elided dynamic names from the nav tree (including late bound names),
* but included certain "well known" symbol names. While we no longer distinguish those well-known
* symbols from other unique symbols, we do the below to retain those members in the nav tree.
*/
function hasNavigationBarName(node: Declaration) {
return !hasDynamicName(node) ||
(
node.kind !== SyntaxKind.BinaryExpression &&
isPropertyAccessExpression(node.name.expression) &&
isIdentifier(node.name.expression.expression) &&
idText(node.name.expression.expression) === "Symbol"
);
const name = getNameOfDeclaration(node);
if (name === undefined) return false;
if (isComputedPropertyName(name)) {
const expression = name.expression;
return isEntityNameExpression(expression) || isNumericLiteral(expression) || isStringOrNumericLiteralLike(expression);
}
return !!name;
}
/** Look for navigation bar items in node's subtree, adding them to the current `parent`. */
+3 -3
View File
@@ -269,7 +269,7 @@ function removeUnusedImports(oldImports: readonly ImportDeclaration[], sourceFil
importDecl.modifiers,
/*importClause*/ undefined,
moduleSpecifier,
/*assertClause*/ undefined,
/*attributes*/ undefined,
));
}
// If we're not in a declaration file, we can't remove the import clause even though
@@ -530,7 +530,7 @@ function coalesceExportsWorker(exportGroup: readonly ExportDeclaration[], compar
factory.updateNamespaceExport(exportDecl.exportClause, exportDecl.exportClause.name)
),
exportDecl.moduleSpecifier,
exportDecl.assertClause,
exportDecl.attributes,
),
);
}
@@ -579,7 +579,7 @@ function updateImportDeclarationAndClause(
importDeclaration.modifiers,
factory.updateImportClause(importDeclaration.importClause!, importDeclaration.importClause!.isTypeOnly, name, namedBindings), // TODO: GH#18217
importDeclaration.moduleSpecifier,
importDeclaration.assertClause,
importDeclaration.attributes,
);
}
+4 -2
View File
@@ -12,6 +12,7 @@ import {
DefaultClause,
findChildOfKind,
getLeadingCommentRanges,
ImportAttributes,
isAnyImportSyntax,
isArrayLiteralExpression,
isBinaryExpression,
@@ -300,11 +301,12 @@ function getOutliningSpanForNode(n: Node, sourceFile: SourceFile): OutliningSpan
return spanForParenthesizedExpression(n as ParenthesizedExpression);
case SyntaxKind.NamedImports:
case SyntaxKind.NamedExports:
case SyntaxKind.ImportAttributes:
case SyntaxKind.AssertClause:
return spanForNamedImportsOrExportsOrAssertClause(n as NamedImports | NamedExports | AssertClause);
return spanForImportExportElements(n as NamedImports | NamedExports | AssertClause | ImportAttributes);
}
function spanForNamedImportsOrExportsOrAssertClause(node: NamedImports | NamedExports | AssertClause) {
function spanForImportExportElements(node: NamedImports | NamedExports | AssertClause | ImportAttributes) {
if (!node.elements.length) {
return undefined;
}
+9
View File
@@ -121,6 +121,15 @@ export function createPatternMatcher(pattern: string): PatternMatcher | undefine
const stringToWordSpans = new Map<string, TextSpan[]>();
const dotSeparatedSegments = pattern.trim().split(".").map(p => createSegment(p.trim()));
// The pattern is an empty string, and it matches everything.
if (dotSeparatedSegments.length === 1 && dotSeparatedSegments[0].totalTextChunk.text === "") {
return {
getMatchForLastSegmentOfPattern: () => createPatternMatch(PatternMatchKind.substring, /*isCaseSensitive*/ true),
getFullMatch: () => createPatternMatch(PatternMatchKind.substring, /*isCaseSensitive*/ true),
patternContainsDots: false,
};
}
// A segment is considered invalid if we couldn't find any words in it.
if (dotSeparatedSegments.some(segment => !segment.subWordTextChunks.length)) return undefined;
@@ -12,11 +12,13 @@ import {
factory,
first,
getContainingFunction,
getLeftmostExpression,
getLocaleSpecificMessage,
getTokenAtPosition,
isArrowFunction,
isBlock,
isExpression,
isObjectLiteralExpression,
isReturnStatement,
needsParentheses,
rangeContainsRange,
@@ -147,7 +149,8 @@ function getConvertibleArrowFunctionAtPosition(file: SourceFile, startPosition:
else if (refactorKindBeginsWith(removeBracesAction.kind, kind) && isBlock(func.body) && func.body.statements.length === 1) {
const firstStatement = first(func.body.statements);
if (isReturnStatement(firstStatement)) {
return { func, addBraces: false, expression: firstStatement.expression, returnStatement: firstStatement };
const expression = firstStatement.expression && isObjectLiteralExpression(getLeftmostExpression(firstStatement.expression, /*stopAtCallExpressions*/ false)) ? factory.createParenthesizedExpression(firstStatement.expression) : firstStatement.expression;
return { func, addBraces: false, expression, returnStatement: firstStatement };
}
}
return undefined;
+1 -1
View File
@@ -275,7 +275,7 @@ function changeDefaultToNamedImport(importingSourceFile: SourceFile, ref: Identi
}
case SyntaxKind.ImportType:
const importTypeNode = parent as ImportTypeNode;
changes.replaceNode(importingSourceFile, parent, factory.createImportTypeNode(importTypeNode.argument, importTypeNode.assertions, factory.createIdentifier(exportName), importTypeNode.typeArguments, importTypeNode.isTypeOf));
changes.replaceNode(importingSourceFile, parent, factory.createImportTypeNode(importTypeNode.argument, importTypeNode.attributes, factory.createIdentifier(exportName), importTypeNode.typeArguments, importTypeNode.isTypeOf));
break;
default:
Debug.failBadSyntaxKind(parent);
+1 -1
View File
@@ -280,5 +280,5 @@ function isExportEqualsModule(moduleSpecifier: Expression, checker: TypeChecker)
}
function updateImport(old: ImportDeclaration, defaultImportName: Identifier | undefined, elements: readonly ImportSpecifier[] | undefined): ImportDeclaration {
return factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, elements && elements.length ? factory.createNamedImports(elements) : undefined), old.moduleSpecifier, /*assertClause*/ undefined);
return factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, elements && elements.length ? factory.createNamedImports(elements) : undefined), old.moduleSpecifier, /*attributes*/ undefined);
}
@@ -15,6 +15,7 @@ import {
getTokenAtPosition,
getTrailingCommentRanges,
isBinaryExpression,
isExpressionNode,
isNoSubstitutionTemplateLiteral,
isParenthesizedExpression,
isStringLiteral,
@@ -58,14 +59,19 @@ function getRefactorActionsToConvertToTemplateString(context: RefactorContext):
const { file, startPosition } = context;
const node = getNodeOrParentOfParentheses(file, startPosition);
const maybeBinary = getParentBinaryExpression(node);
const nodeIsStringLiteral = isStringLiteral(maybeBinary);
const refactorInfo: ApplicableRefactorInfo = { name: refactorName, description: refactorDescription, actions: [] };
if (isBinaryExpression(maybeBinary) && treeToArray(maybeBinary).isValidConcatenation) {
if (nodeIsStringLiteral && context.triggerReason !== "invoked") {
return emptyArray;
}
if (isExpressionNode(maybeBinary) && (nodeIsStringLiteral || isBinaryExpression(maybeBinary) && treeToArray(maybeBinary).isValidConcatenation)) {
refactorInfo.actions.push(convertStringAction);
return [refactorInfo];
}
else if (context.preferences.provideRefactorNotApplicableReason) {
refactorInfo.actions.push({ ...convertStringAction, notApplicableReason: getLocaleSpecificMessage(Diagnostics.Can_only_convert_string_concatenation) });
refactorInfo.actions.push({ ...convertStringAction, notApplicableReason: getLocaleSpecificMessage(Diagnostics.Can_only_convert_string_concatenations_and_string_literals) });
return [refactorInfo];
}
return emptyArray;
+4 -4
View File
@@ -310,7 +310,7 @@ function getTargetFileImportsAndAddExportInOldFile(
forEachImportInStatement(oldStatement, i => {
// Recomputing module specifier
const moduleSpecifier = moduleSpecifierFromImport(i);
const resolved = oldFile.resolvedModules?.get(moduleSpecifier.text, getModeForUsageLocation(oldFile, moduleSpecifier));
const resolved = program.getResolvedModule(oldFile, moduleSpecifier.text, getModeForUsageLocation(oldFile, moduleSpecifier));
const fileName = resolved?.resolvedModule?.resolvedFileName;
if (fileName && targetSourceFile) {
const newModuleSpecifier = getModuleSpecifier(program.getCompilerOptions(), targetSourceFile, targetSourceFile.path, fileName, createModuleSpecifierResolutionHost(program, host));
@@ -479,7 +479,7 @@ function updateNamespaceLikeImportNode(node: SupportedImport, newNamespaceName:
/*modifiers*/ undefined,
factory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, factory.createNamespaceImport(newNamespaceId)),
newModuleString,
/*assertClause*/ undefined,
/*attributes*/ undefined,
);
case SyntaxKind.ImportEqualsDeclaration:
return factory.createImportEqualsDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, newNamespaceId, factory.createExternalModuleReference(newModuleString));
@@ -772,7 +772,7 @@ export function filterImport(i: SupportedImport, moduleSpecifier: StringLiteralL
const defaultImport = clause.name && keep(clause.name) ? clause.name : undefined;
const namedBindings = clause.namedBindings && filterNamedBindings(clause.namedBindings, keep);
return defaultImport || namedBindings
? factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(clause.isTypeOnly, defaultImport, namedBindings), getSynthesizedDeepClone(moduleSpecifier), /*assertClause*/ undefined)
? factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(clause.isTypeOnly, defaultImport, namedBindings), getSynthesizedDeepClone(moduleSpecifier), /*attributes*/ undefined)
: undefined;
}
case SyntaxKind.ImportEqualsDeclaration:
@@ -1198,7 +1198,7 @@ function moveStatementsToTargetFile(changes: textChanges.ChangeTracker, program:
}
if (length(updatedElements) < length(elements)) {
changes.replaceNode(targetFile, exportDeclaration, factory.updateExportDeclaration(exportDeclaration, exportDeclaration.modifiers, exportDeclaration.isTypeOnly, factory.updateNamedExports(exportDeclaration.exportClause, factory.createNodeArray(updatedElements, elements.hasTrailingComma)), exportDeclaration.moduleSpecifier, exportDeclaration.assertClause));
changes.replaceNode(targetFile, exportDeclaration, factory.updateExportDeclaration(exportDeclaration, exportDeclaration.modifiers, exportDeclaration.isTypeOnly, factory.updateNamedExports(exportDeclaration.exportClause, factory.createNodeArray(updatedElements, elements.hasTrailingComma)), exportDeclaration.moduleSpecifier, exportDeclaration.attributes));
}
}
}
+15 -8
View File
@@ -189,6 +189,7 @@ import {
JSDoc,
JsDoc,
JSDocContainer,
JSDocParsingMode,
JSDocTagInfo,
JsonSourceFile,
JsxAttributes,
@@ -212,7 +213,6 @@ import {
mapOneOrMany,
maybeBind,
maybeSetLocalizedDiagnosticMessages,
ModeAwareCache,
ModifierFlags,
ModuleDeclaration,
NavigateToItem,
@@ -256,9 +256,7 @@ import {
RenameInfo,
RenameInfoOptions,
RenameLocation,
ResolvedModuleWithFailedLookupLocations,
ResolvedProjectReference,
ResolvedTypeReferenceDirectiveWithFailedLookupLocations,
returnFalse,
scanner,
ScriptElementKind,
@@ -1042,8 +1040,6 @@ class SourceFileObject extends NodeObject implements SourceFile {
public languageVariant!: LanguageVariant;
public identifiers!: Map<string, string>;
public nameTable: Map<__String, number> | undefined;
public resolvedModules: ModeAwareCache<ResolvedModuleWithFailedLookupLocations> | undefined;
public resolvedTypeReferenceDirectiveNames!: ModeAwareCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>;
public imports!: readonly StringLiteralLike[];
public moduleAugmentations!: StringLiteral[];
private namedDeclarations: Map<string, Declaration[]> | undefined;
@@ -1361,6 +1357,8 @@ class SyntaxTreeCache {
this.host.getCompilationSettings(),
),
setExternalModuleIndicator: getSetExternalModuleIndicator(this.host.getCompilationSettings()),
// These files are used to produce syntax-based highlighting, which reads JSDoc, so we must use ParseAll.
jsDocParsingMode: JSDocParsingMode.ParseAll,
};
sourceFile = createLanguageServiceSourceFile(fileName, scriptSnapshot, options, version, /*setNodeParents*/ true, scriptKind);
}
@@ -1387,7 +1385,14 @@ function setSourceFileFields(sourceFile: SourceFile, scriptSnapshot: IScriptSnap
sourceFile.scriptSnapshot = scriptSnapshot;
}
export function createLanguageServiceSourceFile(fileName: string, scriptSnapshot: IScriptSnapshot, scriptTargetOrOptions: ScriptTarget | CreateSourceFileOptions, version: string, setNodeParents: boolean, scriptKind?: ScriptKind): SourceFile {
export function createLanguageServiceSourceFile(
fileName: string,
scriptSnapshot: IScriptSnapshot,
scriptTargetOrOptions: ScriptTarget | CreateSourceFileOptions,
version: string,
setNodeParents: boolean,
scriptKind?: ScriptKind,
): SourceFile {
const sourceFile = createSourceFile(fileName, getSnapshotText(scriptSnapshot), scriptTargetOrOptions, setNodeParents, scriptKind);
setSourceFileFields(sourceFile, scriptSnapshot, version);
return sourceFile;
@@ -1448,6 +1453,7 @@ export function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSn
languageVersion: sourceFile.languageVersion,
impliedNodeFormat: sourceFile.impliedNodeFormat,
setExternalModuleIndicator: sourceFile.setExternalModuleIndicator,
jsDocParsingMode: sourceFile.jsDocParsingMode,
};
// Otherwise, just create a new source file.
return createLanguageServiceSourceFile(sourceFile.fileName, scriptSnapshot, options, version, /*setNodeParents*/ true, sourceFile.scriptKind);
@@ -1687,6 +1693,7 @@ export function createLanguageService(
resolveLibrary: maybeBind(host, host.resolveLibrary),
useSourceOfProjectReferenceRedirect: maybeBind(host, host.useSourceOfProjectReferenceRedirect),
getParsedCommandLine,
jsDocParsingMode: host.jsDocParsingMode,
};
const originalGetSourceFile = compilerHost.getSourceFile;
@@ -2192,10 +2199,10 @@ export function createLanguageService(
return FindAllReferences.Core.getReferencesForFileName(fileName, program, program.getSourceFiles()).map(FindAllReferences.toReferenceEntry);
}
function getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles = false): NavigateToItem[] {
function getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles = false, excludeLibFiles = false): NavigateToItem[] {
synchronizeHostData();
const sourceFiles = fileName ? [getValidSourceFile(fileName)] : program.getSourceFiles();
return NavigateTo.getNavigateToItems(sourceFiles, program.getTypeChecker(), cancellationToken, searchValue, maxResultCount, excludeDtsFiles);
return NavigateTo.getNavigateToItems(sourceFiles, program.getTypeChecker(), cancellationToken, searchValue, maxResultCount, excludeDtsFiles, excludeLibFiles);
}
function getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean, forceDtsEmit?: boolean) {
+8
View File
@@ -36,6 +36,7 @@ import {
HostCancellationToken,
IScriptSnapshot,
isString,
JSDocParsingMode,
JsTyping,
LanguageService,
LanguageServiceHost,
@@ -159,6 +160,8 @@ export interface LanguageServiceShimHost extends Logger {
getModuleResolutionsForFile?(fileName: string): string;
getTypeReferenceDirectiveResolutionsForFile?(fileName: string): string;
directoryExists(directoryName: string): boolean;
jsDocParsingMode?: JSDocParsingMode;
}
/**
@@ -437,6 +440,8 @@ export class LanguageServiceShimHostAdapter implements LanguageServiceHost {
public resolveTypeReferenceDirectives: ((typeDirectiveNames: string[] | readonly FileReference[], containingFile: string) => (ResolvedTypeReferenceDirective | undefined)[]) | undefined;
public directoryExists: ((directoryName: string) => boolean) | undefined;
public jsDocParsingMode: JSDocParsingMode | undefined;
constructor(private shimHost: LanguageServiceShimHost) {
// if shimHost is a COM object then property check will become method call with no arguments.
// 'in' does not have this effect.
@@ -458,6 +463,9 @@ export class LanguageServiceShimHostAdapter implements LanguageServiceHost {
return map(typeDirectiveNames as (string | FileReference)[], name => getProperty(typeDirectivesForFile, isString(name) ? name : toFileNameLowerCase(name.fileName)));
};
}
if ("jsDocParsingMode" in this.shimHost) {
this.jsDocParsingMode = this.shimHost.jsDocParsingMode;
}
}
public log(s: string): void {
+13 -9
View File
@@ -7,7 +7,6 @@ import {
CaseClause,
changeExtension,
CharacterCodes,
CheckMode,
combinePaths,
comparePaths,
comparePatternKeys,
@@ -32,6 +31,7 @@ import {
endsWith,
ensureTrailingDirectorySeparator,
equateStringsCaseSensitive,
escapeString,
Extension,
fileExtensionIsOneOf,
filter,
@@ -63,6 +63,7 @@ import {
getSupportedExtensions,
getSupportedExtensionsWithJsonIfResolveJsonModule,
getTextOfJsxAttributeName,
getTextOfNode,
getTokenAtPosition,
hasIndexSignature,
hasProperty,
@@ -117,7 +118,6 @@ import {
ScriptElementKind,
ScriptElementKindModifier,
ScriptTarget,
Signature,
signatureHasRestParameter,
SignatureHelp,
singleElementArray,
@@ -262,8 +262,13 @@ function convertStringLiteralCompletions(
return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: completion.hasIndexSignature, optionalReplacementSpan, entries };
}
case StringLiteralCompletionKind.Types: {
const quoteChar = contextToken.kind === SyntaxKind.NoSubstitutionTemplateLiteral
? CharacterCodes.backtick
: startsWith(getTextOfNode(contextToken), "'")
? CharacterCodes.singleQuote
: CharacterCodes.doubleQuote;
const entries = completion.types.map(type => ({
name: type.value,
name: escapeString(type.value, quoteChar),
kindModifiers: ScriptElementKindModifier.none,
kind: ScriptElementKind.string,
sortText: SortText.LocationPriority,
@@ -407,7 +412,7 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL
// Get string literal completions from specialized signatures of the target
// i.e. declare function f(a: 'A');
// f("/*completion position*/")
return argumentInfo && (getStringLiteralCompletionsFromSignature(argumentInfo.invocation, node, argumentInfo, typeChecker) || getStringLiteralCompletionsFromSignature(argumentInfo.invocation, node, argumentInfo, typeChecker, CheckMode.Normal)) || fromContextualType(ContextFlags.None);
return argumentInfo && getStringLiteralCompletionsFromSignature(argumentInfo.invocation, node, argumentInfo, typeChecker) || fromContextualType(ContextFlags.None);
}
// falls through (is `require("")` or `require(""` or `import("")`)
@@ -497,12 +502,11 @@ function getAlreadyUsedTypesInStringLiteralUnion(union: UnionTypeNode, current:
return mapDefined(union.types, type => type !== current && isLiteralTypeNode(type) && isStringLiteral(type.literal) ? type.literal.text : undefined);
}
function getStringLiteralCompletionsFromSignature(call: CallLikeExpression, arg: StringLiteralLike, argumentInfo: SignatureHelp.ArgumentInfoForCompletions, checker: TypeChecker, checkMode = CheckMode.IsForStringLiteralArgumentCompletions): StringLiteralCompletionsFromTypes | undefined {
function getStringLiteralCompletionsFromSignature(call: CallLikeExpression, arg: StringLiteralLike, argumentInfo: SignatureHelp.ArgumentInfoForCompletions, checker: TypeChecker): StringLiteralCompletionsFromTypes | undefined {
let isNewIdentifier = false;
const uniques = new Map<string, true>();
const candidates: Signature[] = [];
const editingArgument = isJsxOpeningLikeElement(call) ? Debug.checkDefined(findAncestor(arg.parent, isJsxAttribute)) : arg;
checker.getResolvedSignatureForStringLiteralCompletions(call, editingArgument, candidates, checkMode);
const candidates = checker.getCandidateSignaturesForStringLiteralCompletions(call, editingArgument);
const types = flatMap(candidates, candidate => {
if (!signatureHasRestParameter(candidate) && argumentInfo.argumentCount > candidate.parameters.length) return;
let type = candidate.getTypeParameterAtPosition(argumentInfo.argumentIndex);
@@ -646,14 +650,14 @@ function getSupportedExtensionsForModuleResolution(compilerOptions: CompilerOpti
*/
function getBaseDirectoriesFromRootDirs(rootDirs: string[], basePath: string, scriptDirectory: string, ignoreCase: boolean): readonly string[] {
// Make all paths absolute/normalized if they are not already
rootDirs = rootDirs.map(rootDirectory => normalizePath(isRootedDiskPath(rootDirectory) ? rootDirectory : combinePaths(basePath, rootDirectory)));
rootDirs = rootDirs.map(rootDirectory => ensureTrailingDirectorySeparator(normalizePath(isRootedDiskPath(rootDirectory) ? rootDirectory : combinePaths(basePath, rootDirectory))));
// Determine the path to the directory containing the script relative to the root directory it is contained within
const relativeDirectory = firstDefined(rootDirs, rootDirectory => containsPath(rootDirectory, scriptDirectory, basePath, ignoreCase) ? scriptDirectory.substr(rootDirectory.length) : undefined)!; // TODO: GH#18217
// Now find a path for each potential directory that is to be merged with the one containing the script
return deduplicate<string>(
[...rootDirs.map(rootDirectory => combinePaths(rootDirectory, relativeDirectory)), scriptDirectory],
[...rootDirs.map(rootDirectory => combinePaths(rootDirectory, relativeDirectory)), scriptDirectory].map(baseDir => removeTrailingDirectorySeparator(baseDir)),
equateStringsCaseSensitive,
compareStringsCaseSensitive,
);

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