mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'main' into o-no-inode
This commit is contained in:
+1
-1
@@ -4,4 +4,4 @@
|
||||
"include": ["src/**", "built/local/**"],
|
||||
"exclude": ["**/node_modules/**"],
|
||||
"mergeAsync": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,10 @@
|
||||
}
|
||||
},
|
||||
"extensions": [
|
||||
"dbaeumer.vscode-eslint"
|
||||
"dbaeumer.vscode-eslint",
|
||||
"dprint.dprint"
|
||||
]
|
||||
}
|
||||
},
|
||||
"remoteUser": "node"
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -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
@@ -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" },
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Vendored
+1
-1
@@ -8,4 +8,4 @@
|
||||
"unwantedRecommendations": [
|
||||
"ms-vscode.vscode-typescript-tslint-plugin"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+49
-49
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Vendored
+7
-5
@@ -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": [
|
||||
|
||||
Vendored
+1
-1
@@ -49,6 +49,6 @@
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+7
-7
@@ -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 -->
|
||||
|
||||
Generated
+491
-421
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -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",
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,2 +1,2 @@
|
||||
#!/bin/sh
|
||||
npm run npx hereby -- generate-diagnostics
|
||||
./node_modules/.bin/hereby generate-diagnostics || true
|
||||
|
||||
Executable
+4
@@ -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
|
||||
@@ -11,6 +11,7 @@ const __dirname = path.dirname(__filename);
|
||||
|
||||
const hooks = [
|
||||
"post-checkout",
|
||||
"pre-commit",
|
||||
];
|
||||
|
||||
hooks.forEach(hook => {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
},
|
||||
|
||||
"include": [
|
||||
"**/*.mjs", "**/*.cjs"
|
||||
"**/*.mjs",
|
||||
"**/*.cjs"
|
||||
]
|
||||
}
|
||||
|
||||
+2
-1
@@ -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" },
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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));
|
||||
|
||||
@@ -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" :
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
"types": ["node"]
|
||||
},
|
||||
|
||||
"references": [
|
||||
],
|
||||
"references": [],
|
||||
|
||||
"include": ["**/*"]
|
||||
}
|
||||
|
||||
+116
-37
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,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),
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 => ({
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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" });
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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": ["**/*"]
|
||||
|
||||
Vendored
+4
@@ -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>;
|
||||
|
||||
Vendored
+9
-1
@@ -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;
|
||||
|
||||
Vendored
+2
@@ -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>;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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 });
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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`. */
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user