Merge branch 'main' into fix11498

# Conflicts:
#	tests/baselines/reference/asyncYieldStarContextualType.types
#	tests/baselines/reference/awaitedType.types
#	tests/baselines/reference/contextuallyTypeAsyncFunctionReturnTypeFromUnion.types
#	tests/baselines/reference/declarationEmitExportAliasVisibiilityMarking.types
#	tests/baselines/reference/declarationEmitUsingAlternativeContainingModules1.types
#	tests/baselines/reference/declarationEmitUsingAlternativeContainingModules2.types
#	tests/baselines/reference/destructureOfVariableSameAsShorthand.types
#	tests/baselines/reference/es2018ObjectAssign.types
#	tests/baselines/reference/esModuleInteropImportCall.types
#	tests/baselines/reference/genericFunctionInference1.types
#	tests/baselines/reference/importCallExpression1ES2020.types
#	tests/baselines/reference/importCallExpression2ES2020.types
#	tests/baselines/reference/importCallExpression4ES2020.types
#	tests/baselines/reference/importCallExpressionES5AMD.types
#	tests/baselines/reference/importCallExpressionES5CJS.types
#	tests/baselines/reference/importCallExpressionES5System.types
#	tests/baselines/reference/importCallExpressionES5UMD.types
#	tests/baselines/reference/importCallExpressionES6AMD.types
#	tests/baselines/reference/importCallExpressionES6CJS.types
#	tests/baselines/reference/importCallExpressionES6System.types
#	tests/baselines/reference/importCallExpressionES6UMD.types
#	tests/baselines/reference/importCallExpressionErrorInES2015.types
#	tests/baselines/reference/importCallExpressionInAMD1.types
#	tests/baselines/reference/importCallExpressionInAMD2.types
#	tests/baselines/reference/importCallExpressionInAMD4.types
#	tests/baselines/reference/importCallExpressionInCJS1.types
#	tests/baselines/reference/importCallExpressionInCJS3.types
#	tests/baselines/reference/importCallExpressionInCJS5.types
#	tests/baselines/reference/importCallExpressionInSystem1.types
#	tests/baselines/reference/importCallExpressionInSystem2.types
#	tests/baselines/reference/importCallExpressionInSystem4.types
#	tests/baselines/reference/importCallExpressionInUMD1.types
#	tests/baselines/reference/importCallExpressionInUMD2.types
#	tests/baselines/reference/importCallExpressionInUMD4.types
#	tests/baselines/reference/importCallExpressionNoModuleKindSpecified.types
#	tests/baselines/reference/importCallExpressionReturnPromiseOfAny.types
#	tests/baselines/reference/importCallExpressionShouldNotGetParen.types
#	tests/baselines/reference/importCallExpressionSpecifierNotStringTypeError.types
#	tests/baselines/reference/inferenceLimit.types
#	tests/baselines/reference/instantiateContextualTypes.types
#	tests/baselines/reference/mappedTypesGenericTuples2.types
#	tests/baselines/reference/modularizeLibrary_Dom.asynciterable.types
#	tests/baselines/reference/modularizeLibrary_NoErrorDuplicateLibOptions1.types
#	tests/baselines/reference/modularizeLibrary_NoErrorDuplicateLibOptions2.types
#	tests/baselines/reference/modularizeLibrary_TargetES5UsingES6Lib.types
#	tests/baselines/reference/modularizeLibrary_Worker.asynciterable.types
#	tests/baselines/reference/moduleResolutionWithoutExtension5.types
#	tests/baselines/reference/moduleResolutionWithoutExtension8.types
#	tests/baselines/reference/privateNameMethodAsync.types
#	tests/baselines/reference/promisePermutations.types
#	tests/baselines/reference/promisePermutations2.types
#	tests/baselines/reference/promisePermutations3.types
#	tests/baselines/reference/promiseTest.types
#	tests/baselines/reference/promiseType.types
#	tests/baselines/reference/promiseTypeStrictNull.types
#	tests/baselines/reference/promiseVoidErrorCallback.types
#	tests/baselines/reference/syntheticDefaultExportsWithDynamicImports.types
#	tests/baselines/reference/truthinessPromiseCoercion.types
#	tests/baselines/reference/unionAndIntersectionInference1.types
#	tests/baselines/reference/unionOfClassCalls.types
#	tests/baselines/reference/usePromiseFinally.types
This commit is contained in:
Anders Hejlsberg
2024-07-10 07:18:48 -07:00
2140 changed files with 270255 additions and 15522 deletions
-12
View File
@@ -1,12 +0,0 @@
const fs = require("fs");
const path = require("path");
const rulesDir = path.join(__dirname, "scripts", "eslint", "rules");
const ext = ".cjs";
const ruleFiles = fs.readdirSync(rulesDir).filter(p => p.endsWith(ext));
module.exports = {
rules: Object.fromEntries(ruleFiles.map(p => {
return [p.slice(0, -ext.length), require(path.join(rulesDir, p))];
})),
};
-177
View File
@@ -1,177 +0,0 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"warnOnUnsupportedTypeScriptVersion": false,
"sourceType": "module"
},
"env": {
"browser": false,
"node": true,
"es6": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/stylistic"
],
"plugins": [
"@typescript-eslint",
"eslint-plugin-local"
],
"ignorePatterns": [
"**/node_modules/**",
"/built/**",
"/tests/**",
"/lib/**",
"/src/lib/*.generated.d.ts",
"/scripts/**/*.js",
"/scripts/**/*.d.*",
"/internal/**",
"/coverage/**"
],
"rules": {
// eslint
"dot-notation": "error",
"eqeqeq": "error",
"no-caller": "error",
"no-constant-condition": ["error", { "checkLoops": false }],
"no-eval": "error",
"no-extra-bind": "error",
"no-new-func": "error",
"no-new-wrappers": "error",
"no-return-await": "error",
"no-restricted-globals": [
"error",
{ "name": "setTimeout" },
{ "name": "clearTimeout" },
{ "name": "setInterval" },
{ "name": "clearInterval" },
{ "name": "setImmediate" },
{ "name": "clearImmediate" }
],
"no-template-curly-in-string": "error",
"no-throw-literal": "error",
"no-undef-init": "error",
"no-var": "error",
"object-shorthand": "error",
"prefer-const": "error",
"prefer-object-spread": "error",
"unicode-bom": ["error", "never"],
"no-restricted-syntax": [
"error",
{
"selector": "Literal[raw=null]",
"message": "Avoid using null; use undefined instead."
},
{
"selector": "TSNullKeyword",
"message": "Avoid using null; use undefined instead."
}
],
// Enabled in eslint:recommended, but not applicable here
"no-extra-boolean-cast": "off",
"no-case-declarations": "off",
"no-cond-assign": "off",
"no-control-regex": "off",
"no-inner-declarations": "off",
// @typescript-eslint/eslint-plugin
"@typescript-eslint/naming-convention": [
"error",
{ "selector": "typeLike", "format": ["PascalCase"], "filter": { "regex": "^(__String|[A-Za-z]+_[A-Za-z]+)$", "match": false } },
{ "selector": "interface", "format": ["PascalCase"], "custom": { "regex": "^I[A-Z]", "match": false }, "filter": { "regex": "^I(Arguments|TextWriter|O([A-Z][a-z]+[A-Za-z]*)?)$", "match": false } },
{ "selector": "variable", "format": ["camelCase", "PascalCase", "UPPER_CASE"], "leadingUnderscore": "allow", "filter": { "regex": "^(_{1,2}filename|_{1,2}dirname|_+|[A-Za-z]+_[A-Za-z]+)$", "match": false } },
{ "selector": "function", "format": ["camelCase", "PascalCase"], "leadingUnderscore": "allow", "filter": { "regex": "^[A-Za-z]+_[A-Za-z]+$", "match": false } },
{ "selector": "parameter", "format": ["camelCase"], "leadingUnderscore": "allow", "filter": { "regex": "^(_+|[A-Za-z]+_[A-Z][a-z]+)$", "match": false } },
{ "selector": "method", "format": ["camelCase", "PascalCase"], "leadingUnderscore": "allow", "filter": { "regex": "^([0-9]+|[A-Za-z]+_[A-Za-z]+)$", "match": false } },
{ "selector": "memberLike", "format": ["camelCase"], "leadingUnderscore": "allow", "filter": { "regex": "^([0-9]+|[A-Za-z]+_[A-Za-z]+)$", "match": false } },
{ "selector": "enumMember", "format": ["camelCase", "PascalCase"], "leadingUnderscore": "allow", "filter": { "regex": "^[A-Za-z]+_[A-Za-z]+$", "match": false } },
{ "selector": "property", "format": null }
],
"@typescript-eslint/unified-signatures": "error",
"no-unused-expressions": "off",
"@typescript-eslint/no-unused-expressions": ["error", { "allowTernary": true }],
// Rules enabled in typescript-eslint configs that are not applicable here
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/class-literal-property-style": "off",
"@typescript-eslint/consistent-indexed-object-style": "off",
"@typescript-eslint/no-duplicate-enum-values": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-non-null-asserted-optional-chain": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/ban-types": [
"error",
{
"extendDefaults": true,
"types": {
// This is theoretically good, but ts-eslint appears to mistake our declaration of Symbol for the global Symbol type.
// See: https://github.com/typescript-eslint/typescript-eslint/issues/7306
"Symbol": false,
"{}": false // {} is a totally useful and valid type.
}
}
],
"@typescript-eslint/no-unused-vars": [
"warn",
{
// Ignore: (solely underscores | starting with exactly one underscore)
"argsIgnorePattern": "^(_+$|_[^_])",
"varsIgnorePattern": "^(_+$|_[^_])"
}
],
"@typescript-eslint/no-inferrable-types": "off",
// Pending https://github.com/typescript-eslint/typescript-eslint/issues/4820
"@typescript-eslint/prefer-optional-chain": "off",
// scripts/eslint/rules
"local/only-arrow-functions": [
"error",
{
"allowNamedFunctions": true,
"allowDeclarations": true
}
],
"local/argument-trivia": "error",
"local/no-in-operator": "error",
"local/debug-assert": "error",
"local/no-keywords": "error",
"local/jsdoc-format": "error",
"local/js-extensions": "error"
},
"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
// 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.
//
// ESLint in VS Code will lint any opened file (so long as it's not eslintignore'd), so
// that will work regardless of the below.
//
// The same applies to mjs files; ESLint appears to not scan those either.
{ "files": ["*.ts", "*.mts", "*.cts", "*.mjs", "*.cjs"] },
{
"files": ["*.mjs", "*.mts"],
"rules": {
// These globals don't exist outside of CJS files.
"no-restricted-globals": [
"error",
{ "name": "__filename" },
{ "name": "__dirname" },
{ "name": "require" },
{ "name": "module" },
{ "name": "exports" }
]
}
}
]
}
@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
token: ${{ secrets.TS_BOT_GITHUB_TOKEN }}
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
+25 -11
View File
@@ -49,7 +49,7 @@ jobs:
name: Test Node ${{ matrix.node-version }} on ${{ matrix.os }}${{ (!matrix.bundle && ' with --no-bundle') || '' }}
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: Use node version ${{ matrix.node-version }}
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
@@ -73,7 +73,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: '*'
@@ -83,11 +83,25 @@ jobs:
- name: Linter
run: npm run lint
knip:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: '*'
check-latest: true
- run: npm ci
- name: Unused exports
run: npm run knip
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: '*'
@@ -108,7 +122,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: '*'
@@ -125,7 +139,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: '*'
@@ -139,7 +153,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
@@ -181,11 +195,11 @@ jobs:
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
path: pr
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
path: base
ref: ${{ github.base_ref }}
@@ -223,7 +237,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: '*'
@@ -240,7 +254,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: '*'
@@ -260,7 +274,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: '*'
+4 -4
View File
@@ -42,11 +42,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # v3.25.8
uses: github/codeql-action/init@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11
with:
config-file: ./.github/codeql/codeql-configuration.yml
# Override language selection by uncommenting this and choosing your languages
@@ -56,7 +56,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below).
- name: Autobuild
uses: github/codeql-action/autobuild@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # v3.25.8
uses: github/codeql-action/autobuild@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11
# ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -70,4 +70,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # v3.25.8
uses: github/codeql-action/analyze@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11
+1 -1
View File
@@ -47,7 +47,7 @@ jobs:
if: github.repository == 'microsoft/TypeScript'
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
filter: blob:none # https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/
fetch-depth: 0 # Default is 1; need to set to 0 to get the benefits of blob:none.
+2 -2
View File
@@ -20,7 +20,7 @@ jobs:
if: github.repository == 'microsoft/TypeScript'
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 'lts/*'
@@ -42,7 +42,7 @@ jobs:
if: github.repository == 'microsoft/TypeScript'
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 'lts/*'
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
exit 1
fi
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
ref: ${{ inputs.branch_name }}
token: ${{ secrets.TS_BOT_GITHUB_TOKEN }}
+1 -1
View File
@@ -50,7 +50,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
filter: blob:none # https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/
fetch-depth: 0 # Default is 1; need to set to 0 to get the benefits of blob:none.
+2 -2
View File
@@ -21,7 +21,7 @@ jobs:
if: github.repository == 'microsoft/TypeScript'
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 'lts/*'
@@ -42,7 +42,7 @@ jobs:
if: github.repository == 'microsoft/TypeScript'
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 'lts/*'
@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 'lts/*'
+2 -2
View File
@@ -29,7 +29,7 @@ jobs:
steps:
- name: 'Checkout code'
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
persist-credentials: false
@@ -55,6 +55,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: 'Upload to code-scanning'
uses: github/codeql-action/upload-sarif@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # v3.25.8
uses: github/codeql-action/upload-sarif@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11
with:
sarif_file: results.sarif
+1 -1
View File
@@ -49,7 +49,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
ref: ${{ inputs.branch_name }}
token: ${{ secrets.TS_BOT_GITHUB_TOKEN }}
+1 -1
View File
@@ -45,7 +45,7 @@ jobs:
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 'lts/*'
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
ref: ${{ inputs.branch_name }}
filter: blob:none # https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
- name: Get repo name
run: R=${GITHUB_REPOSITORY%?wiki}; echo "BASENAME=${R##*/}" >> $GITHUB_ENV
- name: Checkout ${{ env.BASENAME }}-wiki
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
repository: '${{ GITHUB.repository_owner }}/${{ env.BASENAME }}-wiki'
token: ${{ secrets.TS_BOT_GITHUB_TOKEN }}
+2 -2
View File
@@ -49,12 +49,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- if: ${{ github.event.inputs.bisect }}
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
filter: blob:none # https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/
fetch-depth: 0 # Default is 1; need to set to 0 to get the benefits of blob:none.
- if: ${{ !github.event.inputs.bisect }}
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 'lts/*'
+1 -1
View File
@@ -22,7 +22,7 @@ jobs:
if: github.repository == 'microsoft/TypeScript'
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
token: ${{ secrets.TS_BOT_GITHUB_TOKEN }}
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
+7
View File
@@ -565,6 +565,13 @@ export const checkFormat = task({
run: () => exec(process.execPath, ["node_modules/dprint/bin.js", "check"], { ignoreStdout: true }),
});
export const knip = task({
name: "knip",
description: "Runs knip.",
dependencies: [generateDiagnostics],
run: () => exec(process.execPath, ["node_modules/knip/bin/knip.js", "--tags=+internal,-knipignore", "--exclude=duplicates,enumMembers", ...(cmdLineOptions.fix ? ["--fix"] : [])]),
});
const { main: cancellationToken, watch: watchCancellationToken } = entrypointBuildTask({
name: "cancellation-token",
project: "src/cancellationToken",
+253
View File
@@ -0,0 +1,253 @@
// @ts-check
import eslint from "@eslint/js";
import fs from "fs";
import globals from "globals";
import { createRequire } from "module";
import path from "path";
import tseslint from "typescript-eslint";
import url from "url";
const __filename = url.fileURLToPath(new URL(import.meta.url));
const __dirname = path.dirname(__filename);
const require = createRequire(import.meta.url);
const rulesDir = path.join(__dirname, "scripts", "eslint", "rules");
const ext = ".cjs";
const ruleFiles = fs.readdirSync(rulesDir).filter(p => p.endsWith(ext));
export default tseslint.config(
{
files: ["**/*.{ts,tsx,cts,mts,js,cjs,mjs}"],
},
{
ignores: [
"**/node_modules/**",
"built/**",
"tests/**",
"lib/**",
"src/lib/*.generated.d.ts",
"scripts/**/*.js",
"scripts/**/*.d.*",
"internal/**",
"coverage/**",
],
},
eslint.configs.recommended,
...tseslint.configs.recommended,
...tseslint.configs.stylistic,
{
plugins: {
local: {
rules: Object.fromEntries(ruleFiles.map(p => {
return [p.slice(0, -ext.length), require(path.join(rulesDir, p))];
})),
},
},
},
{
languageOptions: {
parserOptions: {
warnOnUnsupportedTypeScriptVersion: false,
},
globals: globals.node,
},
},
{
rules: {
// eslint
"dot-notation": "error",
"eqeqeq": "error",
"no-caller": "error",
"no-constant-condition": ["error", { checkLoops: false }],
"no-eval": "error",
"no-extra-bind": "error",
"no-new-func": "error",
"no-new-wrappers": "error",
"no-return-await": "error",
"no-template-curly-in-string": "error",
"no-throw-literal": "error",
"no-undef-init": "error",
"no-var": "error",
"object-shorthand": "error",
"prefer-const": "error",
"prefer-object-spread": "error",
"unicode-bom": ["error", "never"],
"no-restricted-syntax": [
"error",
{
selector: "Literal[raw=null]",
message: "Avoid using null; use undefined instead.",
},
{
selector: "TSNullKeyword",
message: "Avoid using null; use undefined instead.",
},
],
// Enabled in eslint:recommended, but not applicable here
"no-extra-boolean-cast": "off",
"no-case-declarations": "off",
"no-cond-assign": "off",
"no-control-regex": "off",
"no-inner-declarations": "off",
// @typescript-eslint/eslint-plugin
"@typescript-eslint/naming-convention": [
"error",
{ selector: "typeLike", format: ["PascalCase"], filter: { regex: "^(__String|[A-Za-z]+_[A-Za-z]+)$", match: false } },
{ selector: "interface", format: ["PascalCase"], custom: { regex: "^I[A-Z]", match: false }, filter: { regex: "^I(Arguments|TextWriter|O([A-Z][a-z]+[A-Za-z]*)?)$", match: false } },
{ selector: "variable", format: ["camelCase", "PascalCase", "UPPER_CASE"], leadingUnderscore: "allow", filter: { regex: "^(_{1,2}filename|_{1,2}dirname|_+|[A-Za-z]+_[A-Za-z]+)$", match: false } },
{ selector: "function", format: ["camelCase", "PascalCase"], leadingUnderscore: "allow", filter: { regex: "^[A-Za-z]+_[A-Za-z]+$", match: false } },
{ selector: "parameter", format: ["camelCase"], leadingUnderscore: "allow", filter: { regex: "^(_+|[A-Za-z]+_[A-Z][a-z]+)$", match: false } },
{ selector: "method", format: ["camelCase", "PascalCase"], leadingUnderscore: "allow", filter: { regex: "^([0-9]+|[A-Za-z]+_[A-Za-z]+)$", match: false } },
{ selector: "memberLike", format: ["camelCase"], leadingUnderscore: "allow", filter: { regex: "^([0-9]+|[A-Za-z]+_[A-Za-z]+)$", match: false } },
{ selector: "enumMember", format: ["camelCase", "PascalCase"], leadingUnderscore: "allow", filter: { regex: "^[A-Za-z]+_[A-Za-z]+$", match: false } },
// eslint-disable-next-line no-restricted-syntax
{ selector: "property", format: null },
],
"@typescript-eslint/unified-signatures": "error",
"no-unused-expressions": "off",
"@typescript-eslint/no-unused-expressions": ["error", { allowTernary: true }],
// Rules enabled in typescript-eslint configs that are not applicable here
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/class-literal-property-style": "off",
"@typescript-eslint/consistent-indexed-object-style": "off",
"@typescript-eslint/no-duplicate-enum-values": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-non-null-asserted-optional-chain": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/ban-types": [
"error",
{
extendDefaults: true,
types: {
// This is theoretically good, but ts-eslint appears to mistake our declaration of Symbol for the global Symbol type.
// See: https://github.com/typescript-eslint/typescript-eslint/issues/7306
"Symbol": false,
"{}": false, // {} is a totally useful and valid type.
},
},
],
"@typescript-eslint/no-unused-vars": [
"warn",
{
// Ignore: (solely underscores | starting with exactly one underscore)
argsIgnorePattern: "^(_+$|_[^_])",
varsIgnorePattern: "^(_+$|_[^_])",
},
],
"@typescript-eslint/no-inferrable-types": "off",
// Pending https://github.com/typescript-eslint/typescript-eslint/issues/4820
"@typescript-eslint/prefer-optional-chain": "off",
// scripts/eslint/rules
"local/only-arrow-functions": [
"error",
{
allowNamedFunctions: true,
allowDeclarations: true,
},
],
"local/argument-trivia": "error",
"local/no-in-operator": "error",
"local/debug-assert": "error",
"local/no-keywords": "error",
"local/jsdoc-format": "error",
"local/js-extensions": "error",
},
},
{
files: ["**/*.mjs", "**/*.mts"],
rules: {
// These globals don't exist outside of CJS files.
"no-restricted-globals": [
"error",
{ name: "__filename" },
{ name: "__dirname" },
{ name: "require" },
{ name: "module" },
{ name: "exports" },
],
},
},
{
files: ["src/**"],
languageOptions: {
parserOptions: {
tsconfigRootDir: __dirname,
project: "./src/tsconfig-eslint.json",
},
},
},
{
files: ["scripts/**"],
languageOptions: {
parserOptions: {
tsconfigRootDir: __dirname,
project: "./scripts/tsconfig.json",
},
},
},
{
files: ["src/**"],
rules: {
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"no-restricted-globals": [
"error",
{ name: "setTimeout" },
{ name: "clearTimeout" },
{ name: "setInterval" },
{ name: "clearInterval" },
{ name: "setImmediate" },
{ name: "clearImmediate" },
{ name: "performance" },
],
},
},
{
files: ["src/harness/**", "src/testRunner/**"],
rules: {
"no-restricted-globals": "off",
},
},
{
files: ["src/lib/*.d.ts"],
...tseslint.configs.disableTypeChecked,
},
{
files: ["src/lib/*.d.ts"],
languageOptions: {
globals: {},
},
rules: {
"@typescript-eslint/interface-name-prefix": "off",
"@typescript-eslint/prefer-function-type": "off",
"@typescript-eslint/unified-signatures": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-unused-vars": "off",
// scripts/eslint/rules
"local/no-keywords": "off",
// eslint
"no-var": "off",
"no-restricted-globals": "off",
"no-shadow-restricted-names": "off",
"no-restricted-syntax": "off",
},
},
{
files: ["src/lib/es2019.array.d.ts"],
rules: {
"@typescript-eslint/array-type": "off",
},
},
);
+38
View File
@@ -0,0 +1,38 @@
{
"$schema": "https://unpkg.com/knip@5/schema.json",
"includeEntryExports": true,
"entry": [
"Herebyfile.mjs",
"src/cancellationToken/cancellationToken.ts",
"src/testRunner/_namespaces/Harness.ts",
"src/tsc/tsc.ts",
"src/tsserver/server.ts",
"src/typescript/typescript.ts",
"src/typingsInstaller/nodeTypingsInstaller.ts",
"src/watchGuard/watchGuard.ts",
"src/testRunner/tests.ts",
"src/testRunner/_namespaces/Harness.ts",
// The rest of the entry files, mostly to track used dependencies:
".eslint-plugin-local.cjs",
".gulp.js",
"scripts/eslint/{rules,tests}/*.cjs",
"scripts/*.{cjs,mjs}"
],
"project": [
"src/**",
"scripts/**",
"!src/lib/**/*.d.ts"
],
"ignore": [
"scripts/failed-tests.d.cts"
],
"ignoreDependencies": ["c8", "eslint-formatter-autolinkable-stylish", "mocha-fivemat-progress-reporter"],
"ignoreExportsUsedInFile": {
"enum": true,
"interface": true,
"type": true
},
"mocha": false
}
+1216 -616
View File
File diff suppressed because it is too large Load Diff
+18 -15
View File
@@ -13,11 +13,11 @@
"javascript"
],
"bugs": {
"url": "https://github.com/Microsoft/TypeScript/issues"
"url": "https://github.com/microsoft/TypeScript/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/TypeScript.git"
"url": "https://github.com/microsoft/TypeScript.git"
},
"main": "./lib/typescript.js",
"typings": "./lib/typescript.d.ts",
@@ -42,41 +42,43 @@
"@dprint/formatter": "^0.3.0",
"@dprint/typescript": "0.91.1",
"@esfx/canceltoken": "^1.0.0",
"@octokit/rest": "^20.1.1",
"@eslint/js": "^8.57.0",
"@octokit/rest": "^21.0.0",
"@types/chai": "^4.3.16",
"@types/diff": "^5.2.1",
"@types/minimist": "^1.2.5",
"@types/mocha": "^10.0.6",
"@types/mocha": "^10.0.7",
"@types/ms": "^0.7.34",
"@types/node": "latest",
"@types/source-map-support": "^0.5.10",
"@types/which": "^3.0.4",
"@typescript-eslint/eslint-plugin": "^7.13.1",
"@typescript-eslint/parser": "^7.13.1",
"@typescript-eslint/utils": "^7.13.1",
"azure-devops-node-api": "^13.0.0",
"@typescript-eslint/utils": "^7.14.1",
"azure-devops-node-api": "^14.0.1",
"c8": "^10.1.2",
"chai": "^4.4.1",
"chalk": "^4.1.2",
"chokidar": "^3.6.0",
"diff": "^5.2.0",
"dprint": "^0.46.3",
"esbuild": "^0.21.5",
"esbuild": "^0.22.0",
"eslint": "^8.57.0",
"eslint-formatter-autolinkable-stylish": "^1.3.0",
"eslint-plugin-local": "^4.2.2",
"fast-xml-parser": "^4.4.0",
"glob": "^10.4.1",
"glob": "^10.4.2",
"globals": "^13.24.0",
"hereby": "^1.8.9",
"jsonc-parser": "^3.2.1",
"jsonc-parser": "^3.3.1",
"knip": "^5.25.1",
"minimist": "^1.2.8",
"mocha": "^10.4.0",
"mocha": "^10.5.2",
"mocha-fivemat-progress-reporter": "^0.1.0",
"ms": "^2.1.3",
"node-fetch": "^3.3.2",
"playwright": "^1.44.1",
"playwright": "^1.45.0",
"source-map-support": "^0.5.21",
"tslib": "^2.6.3",
"typescript": "^5.4.5",
"typescript": "^5.5.2",
"typescript-eslint": "^7.14.1",
"which": "^3.0.1"
},
"overrides": {
@@ -92,6 +94,7 @@
"clean": "hereby clean",
"gulp": "hereby",
"lint": "hereby lint",
"knip": "hereby knip",
"format": "dprint fmt",
"setup-hooks": "node scripts/link-hooks.mjs"
},
+1
View File
@@ -68,6 +68,7 @@ export default options;
* @property {boolean} fix
* @property {string} browser
* @property {string} tests
* @property {boolean} skipSysTests
* @property {string | boolean} break
* @property {string | boolean} inspect
* @property {string} runners
+10 -4
View File
@@ -15,6 +15,9 @@ import {
rimraf,
} from "./utils.mjs";
/** @import { CancelToken } from "@esfx/canceltoken" */
void 0;
const mochaJs = path.resolve(findUpRoot(), "node_modules", "mocha", "bin", "_mocha");
export const localBaseline = "tests/baselines/local/";
export const refBaseline = "tests/baselines/reference/";
@@ -25,12 +28,13 @@ export const coverageDir = "coverage";
* @param {string} defaultReporter
* @param {boolean} runInParallel
* @param {object} options
* @param {import("@esfx/canceltoken").CancelToken} [options.token]
* @param {CancelToken} [options.token]
* @param {boolean} [options.watching]
*/
export async function runConsoleTests(runJs, defaultReporter, runInParallel, options = {}) {
const testTimeout = cmdLineOptions.timeout;
const tests = cmdLineOptions.tests;
const skipSysTests = cmdLineOptions.skipSysTests;
const inspect = cmdLineOptions.break || cmdLineOptions.inspect;
const runners = cmdLineOptions.runners;
const light = cmdLineOptions.light;
@@ -74,8 +78,8 @@ export async function runConsoleTests(runJs, defaultReporter, runInParallel, opt
console.log(chalk.yellowBright(`[watch] running tests...`));
}
if (tests || runners || light || testTimeout || taskConfigsFolder || keepFailed || shards || shardId) {
writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, testTimeout, keepFailed, shards, shardId);
if (tests || skipSysTests || runners || light || testTimeout || taskConfigsFolder || keepFailed || shards || shardId) {
writeTestConfigFile(tests, skipSysTests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, testTimeout, keepFailed, shards, shardId);
}
const colors = cmdLineOptions.colors;
@@ -180,6 +184,7 @@ export async function cleanTestDirs() {
/**
* used to pass data from command line directly to run.js
* @param {string} tests
* @param {boolean} skipSysTests
* @param {string} runners
* @param {boolean} light
* @param {string} [taskConfigsFolder]
@@ -190,9 +195,10 @@ export async function cleanTestDirs() {
* @param {number | undefined} [shards]
* @param {number | undefined} [shardId]
*/
export function writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, timeout, keepFailed, shards, shardId) {
export function writeTestConfigFile(tests, skipSysTests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, timeout, keepFailed, shards, shardId) {
const testConfigContents = JSON.stringify({
test: tests ? [tests] : undefined,
skipSysTests: skipSysTests ? skipSysTests : undefined,
runners: runners ? runners.split(",") : undefined,
light,
workerCount,
+4 -1
View File
@@ -6,6 +6,9 @@ import fs from "fs";
import JSONC from "jsonc-parser";
import which from "which";
/** @import { CancelToken } from "@esfx/canceltoken" */
void 0;
/**
* Executes the provided command once with the supplied arguments.
* @param {string} cmd
@@ -17,7 +20,7 @@ import which from "which";
* @property {boolean} [hidePrompt]
* @property {boolean} [waitForExit=true]
* @property {boolean} [ignoreStdout]
* @property {import("@esfx/canceltoken").CancelToken} [token]
* @property {CancelToken} [token]
*/
export async function exec(cmd, args, options = {}) {
return /**@type {Promise<{exitCode?: number}>}*/ (new Promise((resolve, reject) => {
+1 -1
View File
@@ -57,7 +57,7 @@ function main() {
// Finally write the changes to disk.
// Modify the package.json structure
packageJsonValue.version = `${majorMinor}.${prereleasePatch}`;
writeFileSync(packageJsonFilePath, JSON.stringify(packageJsonValue, /*replacer:*/ undefined, /*space:*/ 4));
writeFileSync(packageJsonFilePath, JSON.stringify(packageJsonValue, undefined, 4));
writeFileSync(tsFilePath, modifiedTsFileContents);
}
+6 -4
View File
@@ -3,8 +3,10 @@ const { createRule } = require("./utils.cjs");
const ts = require("typescript");
/**
* @typedef {import("@typescript-eslint/utils").TSESTree.CallExpression | import("@typescript-eslint/utils").TSESTree.NewExpression} CallOrNewExpression
* @import { TSESTree } from "@typescript-eslint/utils"
* @typedef {TSESTree.CallExpression | TSESTree.NewExpression} CallOrNewExpression
*/
void 0;
const unset = Symbol();
/**
@@ -46,7 +48,7 @@ module.exports = createRule({
/** @type {(name: string) => boolean} */
const isSetOrAssert = name => name.startsWith("set") || name.startsWith("assert");
/** @type {(node: import("@typescript-eslint/utils").TSESTree.Node) => boolean} */
/** @type {(node: TSESTree.Node) => boolean} */
const isTrivia = node => {
if (node.type === AST_NODE_TYPES.Identifier) {
return node.name === "undefined";
@@ -101,7 +103,7 @@ module.exports = createRule({
return false;
};
/** @type {(node: import("@typescript-eslint/utils").TSESTree.Node, i: number, getSignature: () => ts.Signature | undefined) => void} */
/** @type {(node: TSESTree.Node, i: number, getSignature: () => ts.Signature | undefined) => void} */
const checkArg = (node, i, getSignature) => {
if (!isTrivia(node)) {
return;
@@ -123,7 +125,7 @@ module.exports = createRule({
});
const comments = sourceCode.getCommentsBefore(node);
/** @type {import("@typescript-eslint/utils").TSESTree.Comment | undefined} */
/** @type {TSESTree.Comment | undefined} */
const comment = comments[comments.length - 1];
if (!comment || comment.type !== "Block") {
+7 -4
View File
@@ -1,6 +1,9 @@
const { AST_NODE_TYPES } = require("@typescript-eslint/utils");
const { createRule } = require("./utils.cjs");
/** @import { TSESTree } from "@typescript-eslint/utils" */
void 0;
module.exports = createRule({
name: "debug-assert",
meta: {
@@ -17,14 +20,14 @@ module.exports = createRule({
defaultOptions: [],
create(context) {
/** @type {(node: import("@typescript-eslint/utils").TSESTree.Node) => boolean} */
/** @type {(node: TSESTree.Node) => boolean} */
const isArrowFunction = node => node.type === AST_NODE_TYPES.ArrowFunctionExpression;
/** @type {(node: import("@typescript-eslint/utils").TSESTree.Node) => boolean} */
/** @type {(node: TSESTree.Node) => boolean} */
const isStringLiteral = node => (
(node.type === AST_NODE_TYPES.Literal && typeof node.value === "string") || node.type === AST_NODE_TYPES.TemplateLiteral
);
/** @type {(node: import("@typescript-eslint/utils").TSESTree.MemberExpression) => boolean} */
/** @type {(node: TSESTree.MemberExpression) => boolean} */
const isDebugAssert = node => (
node.object.type === AST_NODE_TYPES.Identifier
&& node.object.name === "Debug"
@@ -32,7 +35,7 @@ module.exports = createRule({
&& node.property.name === "assert"
);
/** @type {(node: import("@typescript-eslint/utils").TSESTree.CallExpression) => void} */
/** @type {(node: TSESTree.CallExpression) => void} */
const checkDebugAssert = node => {
const args = node.arguments;
const argsLen = args.length;
+8 -5
View File
@@ -1,5 +1,8 @@
const { createRule } = require("./utils.cjs");
/** @import { TSESTree } from "@typescript-eslint/utils" */
void 0;
module.exports = createRule({
name: "js-extensions",
meta: {
@@ -18,11 +21,11 @@ module.exports = createRule({
create(context) {
/** @type {(
* node:
* | import("@typescript-eslint/utils").TSESTree.ImportDeclaration
* | import("@typescript-eslint/utils").TSESTree.ExportAllDeclaration
* | import("@typescript-eslint/utils").TSESTree.ExportNamedDeclaration
* | import("@typescript-eslint/utils").TSESTree.TSImportEqualsDeclaration
* | import("@typescript-eslint/utils").TSESTree.TSModuleDeclaration
* | TSESTree.ImportDeclaration
* | TSESTree.ExportAllDeclaration
* | TSESTree.ExportNamedDeclaration
* | TSESTree.TSImportEqualsDeclaration
* | TSESTree.TSModuleDeclaration
* ) => void}
*/
const check = node => {
+9 -6
View File
@@ -1,5 +1,8 @@
const { createRule } = require("./utils.cjs");
/** @import { TSESTree } from "@typescript-eslint/utils" */
void 0;
module.exports = createRule({
name: "jsdoc-format",
meta: {
@@ -25,17 +28,17 @@ module.exports = createRule({
const atInternal = "@internal";
const jsdocStart = "/**";
/** @type {Map<import("@typescript-eslint/utils").TSESTree.Node, boolean>} */
/** @type {Map<TSESTree.Node, boolean>} */
const isExportedCache = new Map();
/** @type {(node: import("@typescript-eslint/utils").TSESTree.Node) => boolean} */
/** @type {(node: TSESTree.Node) => boolean} */
function isExported(node) {
const exported = isExportedCache.get(node);
if (exported !== undefined) {
return exported;
}
/** @type {import("@typescript-eslint/utils").TSESTree.Node | undefined} */
/** @type {TSESTree.Node | undefined} */
let current = node;
while (current) {
// https://github.com/typescript-eslint/typescript-eslint/blob/e44a1a280f08f9fd0d29f74e5c3e73b7b64a9606/packages/eslint-plugin/src/util/collectUnusedVariables.ts#L440
@@ -55,7 +58,7 @@ module.exports = createRule({
return text.startsWith(jsdocStart);
}
/** @type {(c: import("@typescript-eslint/utils").TSESTree.Comment, indexInComment: number) => import("@typescript-eslint/utils").TSESTree.SourceLocation} */
/** @type {(c: TSESTree.Comment, indexInComment: number) => TSESTree.SourceLocation} */
const getAtInternalLoc = (c, indexInComment) => {
return {
start: context.sourceCode.getLocFromIndex(c.range[0] + indexInComment),
@@ -63,7 +66,7 @@ module.exports = createRule({
};
};
/** @type {(c: import("@typescript-eslint/utils").TSESTree.Comment) => import("@typescript-eslint/utils").TSESTree.SourceLocation} */
/** @type {(c: TSESTree.Comment) => TSESTree.SourceLocation} */
const getJSDocStartLoc = c => {
return {
start: c.loc.start,
@@ -74,7 +77,7 @@ module.exports = createRule({
};
};
/** @type {(node: import("@typescript-eslint/utils").TSESTree.Node) => void} */
/** @type {(node: TSESTree.Node) => void} */
const checkDeclaration = node => {
const blockComments = sourceCode.getCommentsBefore(node).filter(c => c.type === "Block");
if (blockComments.length === 0) {
+4 -1
View File
@@ -1,5 +1,8 @@
const { createRule } = require("./utils.cjs");
/** @import { TSESTree } from "@typescript-eslint/utils" */
void 0;
module.exports = createRule({
name: "no-in-operator",
meta: {
@@ -16,7 +19,7 @@ module.exports = createRule({
create(context) {
const IN_OPERATOR = "in";
/** @type {(node: import("@typescript-eslint/utils").TSESTree.BinaryExpression) => void} */
/** @type {(node: TSESTree.BinaryExpression) => void} */
const checkInOperator = node => {
if (node.operator === IN_OPERATOR) {
context.report({ messageId: "noInOperatorError", node });
+7 -4
View File
@@ -1,6 +1,9 @@
const { AST_NODE_TYPES } = require("@typescript-eslint/utils");
const { createRule } = require("./utils.cjs");
/** @import { TSESTree } from "@typescript-eslint/utils" */
void 0;
module.exports = createRule({
name: "no-keywords",
meta: {
@@ -37,12 +40,12 @@ module.exports = createRule({
/** @type {(name: string) => boolean} */
const isKeyword = name => keywords.includes(name);
/** @type {(node: import("@typescript-eslint/utils").TSESTree.Identifier) => void} */
/** @type {(node: TSESTree.Identifier) => void} */
const report = node => {
context.report({ messageId: "noKeywordsError", data: { name: node.name }, node });
};
/** @type {(node: import("@typescript-eslint/utils").TSESTree.ObjectPattern) => void} */
/** @type {(node: TSESTree.ObjectPattern) => void} */
const checkProperties = node => {
node.properties.forEach(property => {
if (
@@ -56,7 +59,7 @@ module.exports = createRule({
});
};
/** @type {(node: import("@typescript-eslint/utils").TSESTree.ArrayPattern) => void} */
/** @type {(node: TSESTree.ArrayPattern) => void} */
const checkElements = node => {
node.elements.forEach(element => {
if (
@@ -69,7 +72,7 @@ module.exports = createRule({
});
};
/** @type {(node: import("@typescript-eslint/utils").TSESTree.ArrowFunctionExpression | import("@typescript-eslint/utils").TSESTree.FunctionDeclaration | import("@typescript-eslint/utils").TSESTree.FunctionExpression | import("@typescript-eslint/utils").TSESTree.TSMethodSignature | import("@typescript-eslint/utils").TSESTree.TSFunctionType) => void} */
/** @type {(node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionDeclaration | TSESTree.FunctionExpression | TSESTree.TSMethodSignature | TSESTree.TSFunctionType) => void} */
const checkParams = node => {
if (!node || !node.params || !node.params.length) {
return;
@@ -1,7 +1,11 @@
const { AST_NODE_TYPES } = require("@typescript-eslint/utils");
const { createRule } = require("./utils.cjs");
/** @typedef {import("@typescript-eslint/utils").TSESTree.FunctionDeclaration | import("@typescript-eslint/utils").TSESTree.FunctionExpression} FunctionDeclarationOrExpression */
/**
* @import { TSESTree } from "@typescript-eslint/utils"
* @typedef {TSESTree.FunctionDeclaration | TSESTree.FunctionExpression} FunctionDeclarationOrExpression
*/
void 0;
module.exports = createRule({
name: "only-arrow-functions",
@@ -32,7 +36,7 @@ module.exports = createRule({
/** @type {(node: FunctionDeclarationOrExpression) => boolean} */
const isThisParameter = node => !!node.params.length && !!node.params.find(param => param.type === AST_NODE_TYPES.Identifier && param.name === "this");
/** @type {(node: import("@typescript-eslint/utils").TSESTree.Node) => boolean} */
/** @type {(node: TSESTree.Node) => boolean} */
const isMethodType = node => {
const types = [
AST_NODE_TYPES.MethodDefinition,
-49
View File
@@ -1,49 +0,0 @@
{
"extends": "../.eslintrc.json",
"parserOptions": {
"tsconfigRootDir": "src",
"project": "./tsconfig-eslint.json"
},
"rules": {
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"no-restricted-globals": [
"error",
{ "name": "setTimeout" },
{ "name": "clearTimeout" },
{ "name": "setInterval" },
{ "name": "clearInterval" },
{ "name": "setImmediate" },
{ "name": "clearImmediate" },
{ "name": "performance" }
]
},
"overrides": [
{
"files": ["lib/*.d.ts"],
"rules": {
"@typescript-eslint/interface-name-prefix": "off",
"@typescript-eslint/prefer-function-type": "off",
"@typescript-eslint/unified-signatures": "off",
// scripts/eslint/rules
"local/no-keywords": "off",
// eslint
"no-var": "off",
"no-restricted-globals": "off"
}
},
{
"files": ["lib/es2019.array.d.ts"],
"rules": {
"@typescript-eslint/array-type": "off"
}
},
{
"files": ["debug/**", "harness/**", "testRunner/**"],
"rules": {
"no-restricted-globals": "off"
}
}
]
}
+217 -56
View File
@@ -59,6 +59,7 @@ import {
isJsonSourceFile,
isNumber,
isString,
map,
mapDefinedIterator,
maybeBind,
noop,
@@ -187,10 +188,13 @@ export const enum BuilderFileEmit {
Js = 1 << 0, // emit js file
JsMap = 1 << 1, // emit js.map file
JsInlineMap = 1 << 2, // emit inline source map in js file
Dts = 1 << 3, // emit d.ts file
DtsMap = 1 << 4, // emit d.ts.map file
DtsErrors = 1 << 3, // emit dts errors
DtsEmit = 1 << 4, // emit d.ts file
DtsMap = 1 << 5, // emit d.ts.map file
Dts = DtsErrors | DtsEmit,
AllJs = Js | JsMap | JsInlineMap,
AllDtsEmit = DtsEmit | DtsMap,
AllDts = Dts | DtsMap,
All = AllJs | AllDts,
}
@@ -283,12 +287,7 @@ export function getBuilderFileEmit(options: CompilerOptions) {
return result;
}
/**
* Determining what all is pending to be emitted based on previous options or previous file emit flags
*
* @internal
*/
export function getPendingEmitKind(
function getPendingEmitKind(
optionsOrEmitKind: CompilerOptions | BuilderFileEmit,
oldOptionsOrEmitKind: CompilerOptions | BuilderFileEmit | undefined,
): BuilderFileEmit {
@@ -300,8 +299,10 @@ export function getPendingEmitKind(
let result = BuilderFileEmit.None;
// If there is diff in Js emit, pending emit is js emit flags
if (diff & BuilderFileEmit.AllJs) result = emitKind & BuilderFileEmit.AllJs;
// If dts errors pending, add dts errors flag
if (diff & BuilderFileEmit.DtsErrors) result = result | (emitKind & BuilderFileEmit.DtsErrors);
// If there is diff in Dts emit, pending emit is dts emit flags
if (diff & BuilderFileEmit.AllDts) result = result | (emitKind & BuilderFileEmit.AllDts);
if (diff & BuilderFileEmit.AllDtsEmit) result = result | (emitKind & BuilderFileEmit.AllDtsEmit);
return result;
}
@@ -689,32 +690,61 @@ function getNextAffectedFile(
}
}
function clearAffectedFilesPendingEmit(state: BuilderProgramState, emitOnlyDtsFiles: boolean | undefined) {
function clearAffectedFilesPendingEmit(
state: BuilderProgramState,
emitOnlyDtsFiles: boolean | undefined,
isForDtsErrors: boolean,
) {
if (!state.affectedFilesPendingEmit?.size && !state.programEmitPending) return;
if (!emitOnlyDtsFiles) {
if (!emitOnlyDtsFiles && !isForDtsErrors) {
state.affectedFilesPendingEmit = undefined;
state.programEmitPending = undefined;
}
state.affectedFilesPendingEmit?.forEach((emitKind, path) => {
// Mark the files as pending only if they are pending on js files, remove the dts emit pending flag
const pending = emitKind & BuilderFileEmit.AllJs;
const pending = !isForDtsErrors ?
emitKind & BuilderFileEmit.AllJs :
emitKind & (BuilderFileEmit.AllJs | BuilderFileEmit.AllDtsEmit);
if (!pending) state.affectedFilesPendingEmit!.delete(path);
else state.affectedFilesPendingEmit!.set(path, pending);
});
// Mark the program as pending only if its pending on js files, remove the dts emit pending flag
if (state.programEmitPending) {
const pending = state.programEmitPending & BuilderFileEmit.AllJs;
const pending = !isForDtsErrors ?
state.programEmitPending & BuilderFileEmit.AllJs :
state.programEmitPending & (BuilderFileEmit.AllJs | BuilderFileEmit.AllDtsEmit);
if (!pending) state.programEmitPending = undefined;
else state.programEmitPending = pending;
}
}
/**
* Determining what all is pending to be emitted based on previous options or previous file emit flags
* @internal
*/
export function getPendingEmitKindWithSeen(
optionsOrEmitKind: CompilerOptions | BuilderFileEmit,
seenOldOptionsOrEmitKind: CompilerOptions | BuilderFileEmit | undefined,
emitOnlyDtsFiles: boolean | undefined,
isForDtsErrors: boolean,
) {
let pendingKind = getPendingEmitKind(optionsOrEmitKind, seenOldOptionsOrEmitKind);
if (emitOnlyDtsFiles) pendingKind = pendingKind & BuilderFileEmit.AllDts;
if (isForDtsErrors) pendingKind = pendingKind & BuilderFileEmit.DtsErrors;
return pendingKind;
}
function getBuilderFileEmitAllDts(isForDtsErrors: boolean) {
return !isForDtsErrors ? BuilderFileEmit.AllDts : BuilderFileEmit.DtsErrors;
}
/**
* Returns next file to be emitted from files that retrieved semantic diagnostics but did not emit yet
*/
function getNextAffectedFilePendingEmit(
state: BuilderProgramStateWithDefinedProgram,
emitOnlyDtsFiles: boolean | undefined,
isForDtsErrors: boolean,
) {
if (!state.affectedFilesPendingEmit?.size) return undefined;
return forEachEntry(state.affectedFilesPendingEmit, (emitKind, path) => {
@@ -724,13 +754,20 @@ function getNextAffectedFilePendingEmit(
return undefined;
}
const seenKind = state.seenEmittedFiles?.get(affectedFile.resolvedPath);
let pendingKind = getPendingEmitKind(emitKind, seenKind);
if (emitOnlyDtsFiles) pendingKind = pendingKind & BuilderFileEmit.AllDts;
const pendingKind = getPendingEmitKindWithSeen(
emitKind,
seenKind,
emitOnlyDtsFiles,
isForDtsErrors,
);
if (pendingKind) return { affectedFile, emitKind: pendingKind };
});
}
function getNextPendingEmitDiagnosticsFile(state: BuilderProgramStateWithDefinedProgram) {
function getNextPendingEmitDiagnosticsFile(
state: BuilderProgramStateWithDefinedProgram,
isForDtsErrors: boolean,
) {
if (!state.emitDiagnosticsPerFile?.size) return undefined;
return forEachEntry(state.emitDiagnosticsPerFile, (diagnostics, path) => {
const affectedFile = state.program.getSourceFileByPath(path);
@@ -739,7 +776,7 @@ function getNextPendingEmitDiagnosticsFile(state: BuilderProgramStateWithDefined
return undefined;
}
const seenKind = state.seenEmittedFiles?.get(affectedFile.resolvedPath) || BuilderFileEmit.None;
if (!(seenKind & BuilderFileEmit.AllDts)) return { affectedFile, diagnostics, seenKind };
if (!(seenKind & getBuilderFileEmitAllDts(isForDtsErrors))) return { affectedFile, diagnostics, seenKind };
});
}
@@ -1090,6 +1127,7 @@ export interface IncrementalBuildInfoBase extends BuildInfo {
options: CompilerOptions | undefined;
semanticDiagnosticsPerFile: IncrementalBuildInfoDiagnostic[] | undefined;
emitDiagnosticsPerFile: IncrementalBuildInfoEmitDiagnostic[] | undefined;
changeFileSet: readonly IncrementalBuildInfoFileId[] | undefined;
// Because this is only output file in the program, we dont need fileId to deduplicate name
latestChangedDtsFile?: string | undefined;
errors: true | undefined;
@@ -1144,8 +1182,7 @@ export interface NonIncrementalBuildInfo extends BuildInfo {
checkPending: true | undefined;
}
/** @internal */
export function isNonIncrementalBuildInfo(info: BuildInfo): info is NonIncrementalBuildInfo {
function isNonIncrementalBuildInfo(info: BuildInfo): info is NonIncrementalBuildInfo {
return !isIncrementalBuildInfo(info) && !!(info as NonIncrementalBuildInfo).root;
}
@@ -1225,8 +1262,9 @@ function getBuildInfo(state: BuilderProgramStateWithDefinedProgram): BuildInfo {
root,
resolvedRoot: toResolvedRoot(),
options: toIncrementalBuildInfoCompilerOptions(state.compilerOptions),
semanticDiagnosticsPerFile: toIncrementalBuildInfoDiagnostics(),
semanticDiagnosticsPerFile: !state.changedFilesSet.size ? toIncrementalBuildInfoDiagnostics() : undefined,
emitDiagnosticsPerFile: toIncrementalBuildInfoEmitDiagnostics(),
changeFileSet: toChangeFileSet(),
outSignature: state.outSignature,
latestChangedDtsFile,
pendingEmit: !state.programEmitPending ?
@@ -1322,6 +1360,7 @@ function getBuildInfo(state: BuilderProgramStateWithDefinedProgram): BuildInfo {
referencedMap,
semanticDiagnosticsPerFile,
emitDiagnosticsPerFile: toIncrementalBuildInfoEmitDiagnostics(),
changeFileSet: toChangeFileSet(),
affectedFilesPendingEmit,
emitSignatures,
latestChangedDtsFile,
@@ -1428,7 +1467,7 @@ function getBuildInfo(state: BuilderProgramStateWithDefinedProgram): BuildInfo {
state.fileInfos.forEach((_value, key) => {
const value = state.semanticDiagnosticsPerFile.get(key);
if (!value) {
result = append(result, toFileId(key));
if (!state.changedFilesSet.has(key)) result = append(result, toFileId(key));
}
else if (value.length) {
result = append(result, [
@@ -1508,6 +1547,16 @@ function getBuildInfo(state: BuilderProgramStateWithDefinedProgram): BuildInfo {
return result;
}) || array;
}
function toChangeFileSet() {
let changeFileSet: IncrementalBuildInfoFileId[] | undefined;
if (state.changedFilesSet.size) {
for (const path of arrayFrom(state.changedFilesSet.keys()).sort(compareStringsCaseSensitive)) {
changeFileSet = append(changeFileSet, toFileId(path));
}
}
return changeFileSet;
}
}
/** @internal */
@@ -1599,8 +1648,7 @@ export function computeSignatureWithDiagnostics(
}
}
/** @internal */
export function computeSignature(text: string, host: HostForComputeHash, data?: WriteFileCallbackData) {
function computeSignature(text: string, host: HostForComputeHash, data?: WriteFileCallbackData) {
return (host.createHash ?? generateDjb2Hash)(getTextHandlingSourceMapForSignature(text, data));
}
@@ -1645,6 +1693,7 @@ export function createBuilderProgram(
sourceFile,
);
builderProgram.getSemanticDiagnostics = getSemanticDiagnostics;
builderProgram.getDeclarationDiagnostics = getDeclarationDiagnostics;
builderProgram.emit = emit;
builderProgram.releaseProgram = () => releaseCache(state);
@@ -1682,28 +1731,42 @@ export function createBuilderProgram(
* The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host
* in that order would be used to write the files
*/
function emitNextAffectedFile(
function emitNextAffectedFileOrDtsErrors(
writeFile: WriteFileCallback | undefined,
cancellationToken: CancellationToken | undefined,
emitOnlyDtsFiles: boolean | undefined,
customTransformers: CustomTransformers | undefined,
isForDtsErrors: boolean,
): AffectedFileResult<EmitResult> {
Debug.assert(isBuilderProgramStateWithDefinedProgram(state));
let affected = getNextAffectedFile(state, cancellationToken, host);
const programEmitKind = getBuilderFileEmit(state.compilerOptions);
let emitKind: BuilderFileEmit = emitOnlyDtsFiles ?
programEmitKind & BuilderFileEmit.AllDts : programEmitKind;
let emitKind: BuilderFileEmit = !isForDtsErrors ?
emitOnlyDtsFiles ?
programEmitKind & BuilderFileEmit.AllDts :
programEmitKind :
BuilderFileEmit.DtsErrors;
if (!affected) {
if (!state.compilerOptions.outFile) {
const pendingAffectedFile = getNextAffectedFilePendingEmit(state, emitOnlyDtsFiles);
const pendingAffectedFile = getNextAffectedFilePendingEmit(
state,
emitOnlyDtsFiles,
isForDtsErrors,
);
if (pendingAffectedFile) {
// Emit pending affected file
({ affectedFile: affected, emitKind } = pendingAffectedFile);
}
else {
const pendingForDiagnostics = getNextPendingEmitDiagnosticsFile(state);
const pendingForDiagnostics = getNextPendingEmitDiagnosticsFile(
state,
isForDtsErrors,
);
if (pendingForDiagnostics) {
(state.seenEmittedFiles ??= new Map()).set(pendingForDiagnostics.affectedFile.resolvedPath, pendingForDiagnostics.seenKind | BuilderFileEmit.AllDts);
(state.seenEmittedFiles ??= new Map()).set(
pendingForDiagnostics.affectedFile.resolvedPath,
pendingForDiagnostics.seenKind | getBuilderFileEmitAllDts(isForDtsErrors),
);
return {
result: { emitSkipped: true, diagnostics: pendingForDiagnostics.diagnostics },
affected: pendingForDiagnostics.affectedFile,
@@ -1714,15 +1777,19 @@ export function createBuilderProgram(
else {
// Emit program if it was pending emit
if (state.programEmitPending) {
emitKind = state.programEmitPending;
if (emitOnlyDtsFiles) emitKind = emitKind & BuilderFileEmit.AllDts;
emitKind = getPendingEmitKindWithSeen(
state.programEmitPending,
state.seenProgramEmit,
emitOnlyDtsFiles,
isForDtsErrors,
);
if (emitKind) affected = state.program!;
}
// Pending emit diagnostics
if (!affected && state.emitDiagnosticsPerFile?.size) {
const seenKind = state.seenProgramEmit || BuilderFileEmit.None;
if (!(seenKind & BuilderFileEmit.AllDts)) {
state.seenProgramEmit = BuilderFileEmit.AllDts | seenKind;
if (!(seenKind & getBuilderFileEmitAllDts(isForDtsErrors))) {
state.seenProgramEmit = getBuilderFileEmitAllDts(isForDtsErrors) | seenKind;
const diagnostics: Diagnostic[] = [];
state.emitDiagnosticsPerFile.forEach(d => addRange(diagnostics, d));
return {
@@ -1735,7 +1802,7 @@ export function createBuilderProgram(
if (!affected) {
// Emit buildinfo if pending
if (!getBuildInfoEmitPending(state)) return undefined;
if (isForDtsErrors || !getBuildInfoEmitPending(state)) return undefined;
const affected = state.program;
const result = affected.emitBuildInfo(
writeFile || maybeBind(host, host.writeFile),
@@ -1750,15 +1817,23 @@ export function createBuilderProgram(
if (emitKind & BuilderFileEmit.AllJs) emitOnly = EmitOnly.Js;
if (emitKind & BuilderFileEmit.AllDts) emitOnly = emitOnly === undefined ? EmitOnly.Dts : undefined;
// Actual emit without buildInfo as we want to emit it later so the state is updated
const result = state.program.emit(
affected === state.program ? undefined : affected as SourceFile,
getWriteFileCallback(writeFile, customTransformers),
cancellationToken,
emitOnly,
customTransformers,
/*forceDtsEmit*/ undefined,
/*skipBuildInfo*/ true,
);
const result = !isForDtsErrors ?
state.program.emit(
affected === state.program ? undefined : affected as SourceFile,
getWriteFileCallback(writeFile, customTransformers),
cancellationToken,
emitOnly,
customTransformers,
/*forceDtsEmit*/ undefined,
/*skipBuildInfo*/ true,
) :
{
emitSkipped: true,
diagnostics: state.program.getDeclarationDiagnostics(
affected === state.program ? undefined : affected as SourceFile,
cancellationToken,
),
};
if (affected !== state.program) {
// update affected files
const affectedSourceFile = affected as SourceFile;
@@ -1785,21 +1860,45 @@ export function createBuilderProgram(
getPendingEmitKind(state.programEmitPending, emitKind) :
undefined;
state.seenProgramEmit = emitKind | (state.seenProgramEmit || BuilderFileEmit.None);
// Update the d.ts diagnostics since they always come with Location, skip diagnsotics without file,
// they could be semantic diagnsotic with noEmitOnError or other kind of diagnostics
let emitDiagnosticsPerFile: Map<Path, Diagnostic[]> | undefined;
result.diagnostics.forEach(d => {
if (!d.file) return; // Dont cache without fileName
let diagnostics = emitDiagnosticsPerFile?.get(d.file.resolvedPath);
if (!diagnostics) (emitDiagnosticsPerFile ??= new Map()).set(d.file.resolvedPath, diagnostics = []);
diagnostics.push(d);
});
if (emitDiagnosticsPerFile) state.emitDiagnosticsPerFile = emitDiagnosticsPerFile;
setEmitDiagnosticsPerFile(result.diagnostics);
state.buildInfoEmitPending = true;
}
return { result, affected };
}
function setEmitDiagnosticsPerFile(diagnostics: readonly Diagnostic[]) {
// Update the d.ts diagnostics since they always come with Location, skip diagnsotics without file,
// they could be semantic diagnsotic with noEmitOnError or other kind of diagnostics
let emitDiagnosticsPerFile: Map<Path, Diagnostic[]> | undefined;
diagnostics.forEach(d => {
if (!d.file) return; // Dont cache without fileName
let diagnostics = emitDiagnosticsPerFile?.get(d.file.resolvedPath);
if (!diagnostics) (emitDiagnosticsPerFile ??= new Map()).set(d.file.resolvedPath, diagnostics = []);
diagnostics.push(d);
});
if (emitDiagnosticsPerFile) state.emitDiagnosticsPerFile = emitDiagnosticsPerFile;
}
/**
* Emits the next affected file's emit result (EmitResult and sourceFiles emitted) or returns undefined if iteration is complete
* The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host
* in that order would be used to write the files
*/
function emitNextAffectedFile(
writeFile: WriteFileCallback | undefined,
cancellationToken: CancellationToken | undefined,
emitOnlyDtsFiles: boolean | undefined,
customTransformers: CustomTransformers | undefined,
): AffectedFileResult<EmitResult> {
return emitNextAffectedFileOrDtsErrors(
writeFile,
cancellationToken,
emitOnlyDtsFiles,
customTransformers,
/*isForDtsErrors*/ false,
);
}
function getWriteFileCallback(
writeFile: WriteFileCallback | undefined,
customTransformers: CustomTransformers | undefined,
@@ -1942,16 +2041,75 @@ export function createBuilderProgram(
}
// In non Emit builder, clear affected files pending emit
else {
clearAffectedFilesPendingEmit(state, emitOnlyDtsFiles);
clearAffectedFilesPendingEmit(
state,
emitOnlyDtsFiles,
/*isForDtsErrors*/ false,
);
}
}
return state.program.emit(
const emitResult = state.program.emit(
targetSourceFile,
getWriteFileCallback(writeFile, customTransformers),
cancellationToken,
emitOnlyDtsFiles,
customTransformers,
);
handleNonEmitBuilderWithEmitOrDtsErrors(
targetSourceFile,
emitOnlyDtsFiles,
/*isForDtsErrors*/ false,
emitResult.diagnostics,
);
return emitResult;
}
function handleNonEmitBuilderWithEmitOrDtsErrors(
targetSourceFile: SourceFile | undefined,
emitOnlyDtsFiles: boolean | undefined,
isForDtsErrors: boolean,
diagnostics: EmitResult["diagnostics"],
) {
if (!targetSourceFile && kind !== BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) {
clearAffectedFilesPendingEmit(state, emitOnlyDtsFiles, isForDtsErrors);
setEmitDiagnosticsPerFile(diagnostics);
}
}
function getDeclarationDiagnostics(
sourceFile?: SourceFile,
cancellationToken?: CancellationToken,
): readonly DiagnosticWithLocation[] {
Debug.assert(isBuilderProgramStateWithDefinedProgram(state));
if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) {
assertSourceFileOkWithoutNextAffectedCall(state, sourceFile);
let affectedEmitResult: AffectedFileResult<EmitResult>;
let diagnostics: Diagnostic[] | undefined;
while (
affectedEmitResult = emitNextAffectedFileOrDtsErrors(
/*writeFile*/ undefined,
cancellationToken,
/*emitOnlyDtsFiles*/ undefined,
/*customTransformers*/ undefined,
/*isForDtsErrors*/ true,
)
) {
if (!sourceFile) diagnostics = addRange(diagnostics, affectedEmitResult.result.diagnostics);
}
return (
!sourceFile ? diagnostics : state.emitDiagnosticsPerFile?.get(sourceFile.resolvedPath)
) as readonly DiagnosticWithLocation[] | undefined || emptyArray;
}
else {
const result = state.program.getDeclarationDiagnostics(sourceFile, cancellationToken);
handleNonEmitBuilderWithEmitOrDtsErrors(
sourceFile,
/*emitOnlyDtsFiles*/ undefined,
/*isForDtsErrors*/ true,
result,
);
return result;
}
}
/**
@@ -2099,6 +2257,7 @@ export function createBuilderProgramUsingIncrementalBuildInfo(
let filePathsSetList: Set<Path>[] | undefined;
const latestChangedDtsFile = buildInfo.latestChangedDtsFile ? toAbsolutePath(buildInfo.latestChangedDtsFile) : undefined;
const fileInfos = new Map<Path, BuilderState.FileInfo>();
const changedFilesSet = new Set(map(buildInfo.changeFileSet, toFilePath));
if (isIncrementalBundleEmitBuildInfo(buildInfo)) {
buildInfo.fileInfos.forEach((fileInfo, index) => {
const path = toFilePath(index + 1 as IncrementalBuildInfoFileId);
@@ -2110,6 +2269,7 @@ export function createBuilderProgramUsingIncrementalBuildInfo(
semanticDiagnosticsPerFile: toPerFileSemanticDiagnostics(buildInfo.semanticDiagnosticsPerFile),
emitDiagnosticsPerFile: toPerFileEmitDiagnostics(buildInfo.emitDiagnosticsPerFile),
hasReusableDiagnostic: true,
changedFilesSet,
latestChangedDtsFile,
outSignature: buildInfo.outSignature,
programEmitPending: buildInfo.pendingEmit === undefined ? undefined : toProgramEmitPending(buildInfo.pendingEmit, buildInfo.options),
@@ -2147,6 +2307,7 @@ export function createBuilderProgramUsingIncrementalBuildInfo(
semanticDiagnosticsPerFile: toPerFileSemanticDiagnostics(buildInfo.semanticDiagnosticsPerFile),
emitDiagnosticsPerFile: toPerFileEmitDiagnostics(buildInfo.emitDiagnosticsPerFile),
hasReusableDiagnostic: true,
changedFilesSet,
affectedFilesPendingEmit: buildInfo.affectedFilesPendingEmit && arrayToMap(buildInfo.affectedFilesPendingEmit, value => toFilePath(isNumber(value) ? value : value[0]), value => toBuilderFileEmit(value, fullEmitForOptions!)),
latestChangedDtsFile,
emitSignatures: emitSignatures?.size ? emitSignatures : undefined,
@@ -2208,7 +2369,7 @@ export function createBuilderProgramUsingIncrementalBuildInfo(
const semanticDiagnostics = new Map<Path, readonly ReusableDiagnostic[]>(
mapDefinedIterator(
fileInfos.keys(),
key => [key, emptyArray],
key => !changedFilesSet.has(key) ? [key, emptyArray] : undefined,
),
);
diagnostics?.forEach(value => {
+48 -29
View File
@@ -2787,7 +2787,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const moduleNotFoundError = !(moduleName.parent.parent.flags & NodeFlags.Ambient)
? Diagnostics.Invalid_module_name_in_augmentation_module_0_cannot_be_found
: undefined;
let mainModule = resolveExternalModuleNameWorker(moduleName, moduleName, moduleNotFoundError, /*isForAugmentation*/ true);
let mainModule = resolveExternalModuleNameWorker(moduleName, moduleName, moduleNotFoundError, /*ignoreErrors*/ false, /*isForAugmentation*/ true);
if (!mainModule) {
return;
}
@@ -4551,17 +4551,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const errorMessage = isClassic ?
Diagnostics.Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_nodenext_or_to_add_aliases_to_the_paths_option
: Diagnostics.Cannot_find_module_0_or_its_corresponding_type_declarations;
return resolveExternalModuleNameWorker(location, moduleReferenceExpression, ignoreErrors ? undefined : errorMessage);
return resolveExternalModuleNameWorker(location, moduleReferenceExpression, ignoreErrors ? undefined : errorMessage, ignoreErrors);
}
function resolveExternalModuleNameWorker(location: Node, moduleReferenceExpression: Expression, moduleNotFoundError: DiagnosticMessage | undefined, isForAugmentation = false): Symbol | undefined {
function resolveExternalModuleNameWorker(location: Node, moduleReferenceExpression: Expression, moduleNotFoundError: DiagnosticMessage | undefined, ignoreErrors = false, isForAugmentation = false): Symbol | undefined {
return isStringLiteralLike(moduleReferenceExpression)
? resolveExternalModule(location, moduleReferenceExpression.text, moduleNotFoundError, moduleReferenceExpression, isForAugmentation)
? resolveExternalModule(location, moduleReferenceExpression.text, moduleNotFoundError, !ignoreErrors ? moduleReferenceExpression : undefined, isForAugmentation)
: undefined;
}
function resolveExternalModule(location: Node, moduleReference: string, moduleNotFoundError: DiagnosticMessage | undefined, errorNode: Node, isForAugmentation = false): Symbol | undefined {
if (startsWith(moduleReference, "@types/")) {
function resolveExternalModule(location: Node, moduleReference: string, moduleNotFoundError: DiagnosticMessage | undefined, errorNode: Node | undefined, isForAugmentation = false): Symbol | undefined {
if (errorNode && startsWith(moduleReference, "@types/")) {
const diag = Diagnostics.Cannot_import_type_declaration_files_Consider_importing_0_instead_of_1;
const withoutAtTypePrefix = removePrefix(moduleReference, "@types/");
error(errorNode, diag, withoutAtTypePrefix, moduleReference);
@@ -4585,7 +4585,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const mode = contextSpecifier && isStringLiteralLike(contextSpecifier) ? host.getModeForUsageLocation(currentSourceFile, contextSpecifier) : currentSourceFile.impliedNodeFormat;
const moduleResolutionKind = getEmitModuleResolutionKind(compilerOptions);
const resolvedModule = host.getResolvedModule(currentSourceFile, moduleReference, mode)?.resolvedModule;
const resolutionDiagnostic = resolvedModule && getResolutionDiagnostic(compilerOptions, resolvedModule, currentSourceFile);
const resolutionDiagnostic = errorNode && resolvedModule && getResolutionDiagnostic(compilerOptions, resolvedModule, currentSourceFile);
const sourceFile = resolvedModule
&& (!resolutionDiagnostic || resolutionDiagnostic === Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set)
&& host.getSourceFile(resolvedModule.resolvedFileName);
@@ -4598,7 +4598,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (resolvedModule.resolvedUsingTsExtension && isDeclarationFileName(moduleReference)) {
const importOrExport = findAncestor(location, isImportDeclaration)?.importClause ||
findAncestor(location, or(isImportEqualsDeclaration, isExportDeclaration));
if (importOrExport && !importOrExport.isTypeOnly || findAncestor(location, isImportCall)) {
if (errorNode && importOrExport && !importOrExport.isTypeOnly || findAncestor(location, isImportCall)) {
error(
errorNode,
Diagnostics.A_declaration_file_cannot_be_imported_without_import_type_Did_you_mean_to_import_an_implementation_file_0_instead,
@@ -4609,19 +4609,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
else if (resolvedModule.resolvedUsingTsExtension && !shouldAllowImportingTsExtension(compilerOptions, currentSourceFile.fileName)) {
const importOrExport = findAncestor(location, isImportDeclaration)?.importClause ||
findAncestor(location, or(isImportEqualsDeclaration, isExportDeclaration));
if (!(importOrExport?.isTypeOnly || findAncestor(location, isImportTypeNode))) {
if (errorNode && !(importOrExport?.isTypeOnly || findAncestor(location, isImportTypeNode))) {
const tsExtension = Debug.checkDefined(tryExtractTSExtension(moduleReference));
error(errorNode, Diagnostics.An_import_path_can_only_end_with_a_0_extension_when_allowImportingTsExtensions_is_enabled, tsExtension);
}
}
if (sourceFile.symbol) {
if (resolvedModule.isExternalLibraryImport && !resolutionExtensionIsTSOrJson(resolvedModule.extension)) {
if (errorNode && resolvedModule.isExternalLibraryImport && !resolutionExtensionIsTSOrJson(resolvedModule.extension)) {
errorOnImplicitAnyModule(/*isError*/ false, errorNode, currentSourceFile, mode, resolvedModule, moduleReference);
}
if (moduleResolutionKind === ModuleResolutionKind.Node16 || moduleResolutionKind === ModuleResolutionKind.NodeNext) {
if (errorNode && (moduleResolutionKind === ModuleResolutionKind.Node16 || moduleResolutionKind === ModuleResolutionKind.NodeNext)) {
const isSyncImport = (currentSourceFile.impliedNodeFormat === ModuleKind.CommonJS && !findAncestor(location, isImportCall)) || !!findAncestor(location, isImportEqualsDeclaration);
const overrideHost = findAncestor(location, l => isImportTypeNode(l) || isExportDeclaration(l) || isImportDeclaration(l)) as ImportTypeNode | ImportDeclaration | ExportDeclaration | undefined;
const overrideHost = findAncestor(location, l => isImportTypeNode(l) || isExportDeclaration(l) || isImportDeclaration(l) || isJSDocImportTag(l));
// An override clause will take effect for type-only imports and import types, and allows importing the types across formats, regardless of
// normal mode restrictions
if (isSyncImport && sourceFile.impliedNodeFormat === ModuleKind.ESNext && !hasResolutionModeOverride(overrideHost)) {
@@ -4684,7 +4684,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// merged symbol is module declaration symbol combined with all augmentations
return getMergedSymbol(sourceFile.symbol);
}
if (moduleNotFoundError) {
if (errorNode && moduleNotFoundError) {
// report errors only if it was requested
error(errorNode, Diagnostics.File_0_is_not_a_module, sourceFile.fileName);
}
@@ -4706,6 +4706,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}
if (!errorNode) {
return undefined;
}
// May be an untyped module. If so, ignore resolutionDiagnostic.
if (resolvedModule && !resolutionExtensionIsTSOrJson(resolvedModule.extension) && resolutionDiagnostic === undefined || resolutionDiagnostic === Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type) {
if (isForAugmentation) {
@@ -8322,11 +8326,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const typePredicate = getTypePredicateOfSignature(signature);
const type = getReturnTypeOfSignature(signature);
if (context.enclosingDeclaration && (!isErrorType(type) || (context.flags & NodeBuilderFlags.AllowUnresolvedNames)) && signature.declaration && !nodeIsSynthesized(signature.declaration)) {
const annotation = signature.declaration && getNonlocalEffectiveReturnTypeAnnotationNode(signature.declaration);
// Default constructor signatures inherited from base classes return the derived class but have the base class declaration
// To ensure we don't serialize the wrong type we check that that return type of the signature corresponds to the declaration return type signature
if (annotation && getTypeFromTypeNode(context, annotation) === type) {
const result = tryReuseExistingTypeNodeHelper(context, annotation);
const annotation = getNonlocalEffectiveReturnTypeAnnotationNode(signature.declaration);
if (annotation) {
const result = tryReuseExistingTypeNode(context, annotation, type, context.enclosingDeclaration);
if (result) {
return result;
}
@@ -8836,7 +8838,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
);
}
if (isNamedDeclaration(node) && node.name.kind === SyntaxKind.ComputedPropertyName && !isLateBindableName(node.name)) {
if (!(context.flags & NodeBuilderFlags.AllowUnresolvedNames && hasDynamicName(node) && isEntityNameExpression(node.name.expression) && checkComputedPropertyName(node.name).flags & TypeFlags.Any)) {
if (!hasDynamicName(node)) {
return visitEachChild(node, visitExistingNodeTreeSymbols);
}
if (!(context.flags & NodeBuilderFlags.AllowUnresolvedNames && isEntityNameExpression(node.name.expression) && checkComputedPropertyName(node.name).flags & TypeFlags.Any)) {
return undefined;
}
}
@@ -13416,7 +13421,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
links[resolutionKind] = resolved || emptySymbols;
}
return links[resolutionKind]!;
return links[resolutionKind];
}
/**
@@ -15958,7 +15963,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
function createSignatureTypeMapper(signature: Signature, typeArguments: readonly Type[] | undefined): TypeMapper {
return createTypeMapper(signature.typeParameters!, typeArguments);
return createTypeMapper(sameMap(signature.typeParameters!, tp => tp.mapper ? instantiateType(tp, tp.mapper) : tp), typeArguments);
}
function getErasedSignature(signature: Signature): Signature {
@@ -17835,10 +17840,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// Check that the given type has a match in every union. A given type is matched by
// an identical type, and a literal type is additionally matched by its corresponding
// primitive type.
// primitive type, and missingType is matched by undefinedType (and vice versa).
function eachUnionContains(unionTypes: UnionType[], type: Type) {
for (const u of unionTypes) {
if (!containsType(u.types, type)) {
if (type === missingType) {
return containsType(u.types, undefinedType);
}
if (type === undefinedType) {
return containsType(u.types, missingType);
}
const primitive = type.flags & TypeFlags.StringLiteral ? stringType :
type.flags & (TypeFlags.Enum | TypeFlags.NumberLiteral) ? numberType :
type.flags & TypeFlags.BigIntLiteral ? bigintType :
@@ -17918,6 +17929,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
for (const t of u.types) {
if (insertType(checked, t)) {
if (eachUnionContains(unionTypes, t)) {
// undefinedType/missingType should always come sorted first so we leverage that here
if (t === undefinedType && result.length && result[0] === missingType) {
continue;
}
if (t === missingType && result.length && result[0] === undefinedType) {
result[0] = missingType;
continue;
}
insertType(result, t);
}
}
@@ -18831,7 +18850,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
function getSimplifiedIndexedAccessType(type: IndexedAccessType, writing: boolean): Type {
const cache = writing ? "simplifiedForWriting" : "simplifiedForReading";
if (type[cache]) {
return type[cache] === circularConstraintType ? type : type[cache]!;
return type[cache] === circularConstraintType ? type : type[cache];
}
type[cache] = circularConstraintType;
// We recursively simplify the object type as it may in turn be an indexed access type. For example, with
@@ -24181,7 +24200,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
for (let i = 0; i < types.length; i++) {
if (include[i]) {
const targetType = getTypeOfPropertyOrIndexSignatureOfType(types[i], propertyName);
if (targetType && related(getDiscriminatingType(), targetType)) {
if (targetType && someType(getDiscriminatingType(), t => !!related(t, targetType))) {
matched = true;
}
else {
@@ -33199,7 +33218,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
? Diagnostics.Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_nodenext_or_to_add_aliases_to_the_paths_option
: Diagnostics.Cannot_find_module_0_or_its_corresponding_type_declarations;
const specifier = getJSXRuntimeImportSpecifier(file, runtimeImportSpecifier);
const mod = resolveExternalModule(specifier || location!, runtimeImportSpecifier, errorMessage, location!);
const mod = resolveExternalModule(specifier || location!, runtimeImportSpecifier, errorMessage, location);
const result = mod && mod !== unknownSymbol ? getMergedSymbol(resolveSymbol(mod)) : undefined;
if (links) {
links.jsxImplicitImportContainer = result || false;
@@ -51247,6 +51266,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// fallthrough
case ModuleKind.ES2022:
case ModuleKind.ESNext:
case ModuleKind.Preserve:
case ModuleKind.System:
if (languageVersion >= ScriptTarget.ES2017) {
break;
@@ -52064,13 +52084,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
const nodeArguments = node.arguments;
if (moduleKind !== ModuleKind.ESNext && moduleKind !== ModuleKind.NodeNext && moduleKind !== ModuleKind.Node16) {
if (moduleKind !== ModuleKind.ESNext && moduleKind !== ModuleKind.NodeNext && moduleKind !== ModuleKind.Node16 && moduleKind !== ModuleKind.Preserve) {
// We are allowed trailing comma after proposal-import-assertions.
checkGrammarForDisallowedTrailingComma(nodeArguments);
if (nodeArguments.length > 1) {
const importAttributesArgument = nodeArguments[1];
return grammarErrorOnNode(importAttributesArgument, Diagnostics.Dynamic_imports_only_support_a_second_argument_when_the_module_option_is_set_to_esnext_node16_or_nodenext);
return grammarErrorOnNode(importAttributesArgument, Diagnostics.Dynamic_imports_only_support_a_second_argument_when_the_module_option_is_set_to_esnext_node16_nodenext_or_preserve);
}
}
@@ -52280,8 +52300,7 @@ export function signatureHasRestParameter(s: Signature) {
return !!(s.flags & SignatureFlags.HasRestParameter);
}
/** @internal */
export function signatureHasLiteralTypes(s: Signature) {
function signatureHasLiteralTypes(s: Signature) {
return !!(s.flags & SignatureFlags.HasLiteralTypes);
}
+6 -10
View File
@@ -123,8 +123,7 @@ import {
WatchOptions,
} from "./_namespaces/ts.js";
/** @internal */
export const compileOnSaveCommandLineOption: CommandLineOption = {
const compileOnSaveCommandLineOption: CommandLineOption = {
name: "compileOnSave",
type: "boolean",
defaultValueDescription: false,
@@ -1626,12 +1625,11 @@ export const optionsAffectingProgramStructure: readonly CommandLineOption[] = op
/** @internal */
export const transpileOptionValueCompilerOptions: readonly CommandLineOption[] = optionDeclarations.filter(option => hasProperty(option, "transpileOptionValue"));
/** @internal */
export const configDirTemplateSubstitutionOptions: readonly CommandLineOption[] = optionDeclarations.filter(
const configDirTemplateSubstitutionOptions: readonly CommandLineOption[] = optionDeclarations.filter(
option => option.allowConfigDirTemplateSubstitution || (!option.isCommandLineOnly && option.isFilePath),
);
/** @internal */
export const configDirTemplateSubstitutionWatchOptions: readonly CommandLineOption[] = optionsForWatch.filter(
const configDirTemplateSubstitutionWatchOptions: readonly CommandLineOption[] = optionsForWatch.filter(
option => option.allowConfigDirTemplateSubstitution || (!option.isCommandLineOnly && option.isFilePath),
);
@@ -1745,8 +1743,7 @@ const compilerOptionsAlternateMode: AlternateModeDiagnostics = {
getOptionsNameMap: getBuildOptionsNameMap,
};
/** @internal */
export const defaultInitCompilerOptions: CompilerOptions = {
const defaultInitCompilerOptions: CompilerOptions = {
module: ModuleKind.CommonJS,
target: ScriptTarget.ES2016,
strict: true,
@@ -2903,8 +2900,7 @@ function directoryOfCombinedPath(fileName: string, basePath: string) {
return getDirectoryPath(getNormalizedAbsolutePath(fileName, basePath));
}
/** @internal */
export const defaultIncludeSpec = "**/*";
const defaultIncludeSpec = "**/*";
/**
* Parse the contents of a config file from json or json source file (tsconfig.json).
+2 -112
View File
@@ -17,8 +17,6 @@ import {
export const emptyArray: never[] = [] as never[];
/** @internal */
export const emptyMap: ReadonlyMap<never, never> = new Map<never, never>();
/** @internal */
export const emptySet: ReadonlySet<never> = new Set<never>();
/** @internal */
export function length(array: readonly any[] | undefined): number {
@@ -218,22 +216,6 @@ export function findLastIndex<T>(array: readonly T[] | undefined, predicate: (el
return -1;
}
/**
* Returns the first truthy result of `callback`, or else fails.
* This is like `forEach`, but never returns undefined.
*
* @internal
*/
export function findMap<T, U>(array: readonly T[], callback: (element: T, index: number) => U | undefined): U {
for (let i = 0; i < array.length; i++) {
const result = callback(array[i], i);
if (result) {
return result;
}
}
return Debug.fail();
}
/** @internal */
export function contains<T>(array: readonly T[] | undefined, value: T, equalityComparer: EqualityComparer<T> = equateValues): boolean {
if (array !== undefined) {
@@ -827,17 +809,6 @@ export function sortAndDeduplicate<T>(array: readonly T[], comparer?: Comparer<T
return deduplicateSorted(sort(array, comparer), equalityComparer ?? comparer ?? compareStringsCaseSensitive as any as Comparer<T>);
}
/** @internal */
export function arrayIsSorted<T>(array: readonly T[], comparer: Comparer<T>) {
if (array.length < 2) return true;
for (let i = 1, len = array.length; i < len; i++) {
if (comparer(array[i - 1], array[i]) === Comparison.GreaterThan) {
return false;
}
}
return true;
}
/** @internal */
export function arrayIsEqualTo<T>(array1: readonly T[] | undefined, array2: readonly T[] | undefined, equalityComparer: (a: T, b: T, index: number) => boolean = equateValues): boolean {
if (array1 === undefined || array2 === undefined) {
@@ -1875,10 +1846,8 @@ export function identity<T>(x: T) {
/**
* Returns lower case string
*
* @internal
*/
export function toLowerCase(x: string) {
function toLowerCase(x: string) {
return x.toLowerCase();
}
@@ -1963,82 +1932,6 @@ export function memoizeOne<A extends string | number | boolean | undefined, T>(c
};
}
/**
* A version of `memoize` that supports a single non-primitive argument, stored as keys of a WeakMap.
*
* @internal
*/
export function memoizeWeak<A extends object, T>(callback: (arg: A) => T): (arg: A) => T {
const map = new WeakMap<A, T>();
return (arg: A) => {
let value = map.get(arg);
if (value === undefined && !map.has(arg)) {
value = callback(arg);
map.set(arg, value);
}
return value!;
};
}
/** @internal */
export interface MemoizeCache<A extends any[], T> {
has(args: A): boolean;
get(args: A): T | undefined;
set(args: A, value: T): void;
}
/**
* A version of `memoize` that supports multiple arguments, backed by a provided cache.
*
* @internal
*/
export function memoizeCached<A extends any[], T>(callback: (...args: A) => T, cache: MemoizeCache<A, T>): (...args: A) => T {
return (...args: A) => {
let value = cache.get(args);
if (value === undefined && !cache.has(args)) {
value = callback(...args);
cache.set(args, value);
}
return value!;
};
}
/**
* High-order function, composes functions. Note that functions are composed inside-out;
* for example, `compose(a, b)` is the equivalent of `x => b(a(x))`.
*
* @param args The functions to compose.
*
* @internal
*/
export function compose<T>(...args: ((t: T) => T)[]): (t: T) => T;
/** @internal */
export function compose<T>(a: (t: T) => T, b: (t: T) => T, c: (t: T) => T, d: (t: T) => T, e: (t: T) => T): (t: T) => T {
if (!!e) {
const args: ((t: T) => T)[] = [];
for (let i = 0; i < arguments.length; i++) {
// eslint-disable-next-line prefer-rest-params
args[i] = arguments[i];
}
return t => reduceLeft(args, (u, f) => f(u), t);
}
else if (d) {
return t => d(c(b(a(t))));
}
else if (c) {
return t => c(b(a(t)));
}
else if (b) {
return t => b(a(t));
}
else if (a) {
return t => a(t);
}
else {
return t => t;
}
}
/** @internal */
export const enum AssertionLevel {
None = 0,
@@ -2054,8 +1947,6 @@ export const enum AssertionLevel {
* @internal
*/
export type AnyFunction = (...args: never[]) => void;
/** @internal */
export type AnyConstructor = new (...args: unknown[]) => unknown;
/** @internal */
export function equateValues<T>(a: T, b: T) {
@@ -2467,8 +2358,7 @@ export function orderedRemoveItemAt<T>(array: T[], index: number): void {
array.pop();
}
/** @internal */
export function unorderedRemoveItemAt<T>(array: T[], index: number): void {
function unorderedRemoveItemAt<T>(array: T[], index: number): void {
// Fill in the "hole" left at `index`.
array[index] = array[array.length - 1];
array.pop();
-10
View File
@@ -33,16 +33,6 @@ export interface ReadonlyCollection<K> {
keys(): IterableIterator<K>;
}
/**
* Common write methods for ES6 Map/Set.
*
* @internal
*/
export interface Collection<K> extends ReadonlyCollection<K> {
delete(key: K): boolean;
clear(): void;
}
/** @internal */
export type EqualityComparer<T> = (a: T, b: T) => boolean;
+1 -1
View File
@@ -1032,7 +1032,7 @@
"category": "Error",
"code": 1323
},
"Dynamic imports only support a second argument when the '--module' option is set to 'esnext', 'node16', or 'nodenext'.": {
"Dynamic imports only support a second argument when the '--module' option is set to 'esnext', 'node16', 'nodenext', or 'preserve'.": {
"category": "Error",
"code": 1324
},
+6 -7
View File
@@ -503,8 +503,7 @@ export function canEmitTsBuildInfo(options: CompilerOptions) {
return isIncrementalCompilation(options) || !!options.tscBuild;
}
/** @internal */
export function getOutputPathsForBundle(options: CompilerOptions, forceDtsPaths: boolean): EmitFileNames {
function getOutputPathsForBundle(options: CompilerOptions, forceDtsPaths: boolean): EmitFileNames {
const outPath = options.outFile!;
const jsFilePath = options.emitDeclarationOnly ? undefined : outPath;
const sourceMapFilePath = jsFilePath && getSourceMapFilePath(jsFilePath, options);
@@ -2089,7 +2088,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
// SyntaxKind.TemplateMiddle
// SyntaxKind.TemplateTail
function emitLiteral(node: LiteralLikeNode, jsxAttributeEscape: boolean) {
const text = getLiteralTextOfNode(node, printerOptions.neverAsciiEscape, jsxAttributeEscape);
const text = getLiteralTextOfNode(node, /*sourceFile*/ undefined, printerOptions.neverAsciiEscape, jsxAttributeEscape);
if (
(printerOptions.sourceMap || printerOptions.inlineSourceMap)
&& (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))
@@ -2642,7 +2641,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
expression = skipPartiallyEmittedExpressions(expression);
if (isNumericLiteral(expression)) {
// check if numeric literal is a decimal literal that was originally written with a dot
const text = getLiteralTextOfNode(expression as LiteralExpression, /*neverAsciiEscape*/ true, /*jsxAttributeEscape*/ false);
const text = getLiteralTextOfNode(expression as LiteralExpression, /*sourceFile*/ undefined, /*neverAsciiEscape*/ true, /*jsxAttributeEscape*/ false);
// If the number will be printed verbatim and it doesn't already contain a dot or an exponent indicator, add one
// if the expression doesn't have any comments that will be emitted.
return !(expression.numericLiteralFlags & TokenFlags.WithSpecifier)
@@ -5170,7 +5169,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
return getSourceTextOfNodeFromSourceFile(sourceFile, node, includeTrivia);
}
function getLiteralTextOfNode(node: LiteralLikeNode, neverAsciiEscape: boolean | undefined, jsxAttributeEscape: boolean): string {
function getLiteralTextOfNode(node: LiteralLikeNode, sourceFile = currentSourceFile, neverAsciiEscape: boolean | undefined, jsxAttributeEscape: boolean): string {
if (node.kind === SyntaxKind.StringLiteral && (node as StringLiteral).textSourceNode) {
const textSourceNode = (node as StringLiteral).textSourceNode!;
if (isIdentifier(textSourceNode) || isPrivateIdentifier(textSourceNode) || isNumericLiteral(textSourceNode) || isJsxNamespacedName(textSourceNode)) {
@@ -5180,7 +5179,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
`"${escapeNonAsciiString(text)}"`;
}
else {
return getLiteralTextOfNode(textSourceNode, neverAsciiEscape, jsxAttributeEscape);
return getLiteralTextOfNode(textSourceNode, getSourceFileOfNode(textSourceNode), neverAsciiEscape, jsxAttributeEscape);
}
}
@@ -5189,7 +5188,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
| (printerOptions.terminateUnterminatedLiterals ? GetLiteralTextFlags.TerminateUnterminatedLiterals : 0)
| (printerOptions.target && printerOptions.target >= ScriptTarget.ES2021 ? GetLiteralTextFlags.AllowNumericSeparator : 0);
return getLiteralText(node, currentSourceFile, flags);
return getLiteralText(node, sourceFile, flags);
}
/**
+43 -72
View File
@@ -696,10 +696,8 @@ export function compareEmitHelpers(x: EmitHelper, y: EmitHelper) {
/**
* @param input Template string input strings
* @param args Names which need to be made file-level unique
*
* @internal
*/
export function helperString(input: TemplateStringsArray, ...args: string[]) {
function helperString(input: TemplateStringsArray, ...args: string[]) {
return (uniqueName: EmitHelperUniqueNameCallback) => {
let result = "";
for (let i = 0; i < args.length; i++) {
@@ -713,8 +711,7 @@ export function helperString(input: TemplateStringsArray, ...args: string[]) {
// TypeScript Helpers
/** @internal */
export const decorateHelper: UnscopedEmitHelper = {
const decorateHelper: UnscopedEmitHelper = {
name: "typescript:decorate",
importName: "__decorate",
scoped: false,
@@ -728,8 +725,7 @@ export const decorateHelper: UnscopedEmitHelper = {
};`,
};
/** @internal */
export const metadataHelper: UnscopedEmitHelper = {
const metadataHelper: UnscopedEmitHelper = {
name: "typescript:metadata",
importName: "__metadata",
scoped: false,
@@ -740,8 +736,7 @@ export const metadataHelper: UnscopedEmitHelper = {
};`,
};
/** @internal */
export const paramHelper: UnscopedEmitHelper = {
const paramHelper: UnscopedEmitHelper = {
name: "typescript:param",
importName: "__param",
scoped: false,
@@ -753,8 +748,7 @@ export const paramHelper: UnscopedEmitHelper = {
};
// ES Decorators Helpers
/** @internal */
export const esDecorateHelper: UnscopedEmitHelper = {
const esDecorateHelper: UnscopedEmitHelper = {
name: "typescript:esDecorate",
importName: "__esDecorate",
scoped: false,
@@ -789,8 +783,7 @@ export const esDecorateHelper: UnscopedEmitHelper = {
};`,
};
/** @internal */
export const runInitializersHelper: UnscopedEmitHelper = {
const runInitializersHelper: UnscopedEmitHelper = {
name: "typescript:runInitializers",
importName: "__runInitializers",
scoped: false,
@@ -807,8 +800,7 @@ export const runInitializersHelper: UnscopedEmitHelper = {
// ES2018 Helpers
/** @internal */
export const assignHelper: UnscopedEmitHelper = {
const assignHelper: UnscopedEmitHelper = {
name: "typescript:assign",
importName: "__assign",
scoped: false,
@@ -827,8 +819,7 @@ export const assignHelper: UnscopedEmitHelper = {
};`,
};
/** @internal */
export const awaitHelper: UnscopedEmitHelper = {
const awaitHelper: UnscopedEmitHelper = {
name: "typescript:await",
importName: "__await",
scoped: false,
@@ -836,8 +827,7 @@ export const awaitHelper: UnscopedEmitHelper = {
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }`,
};
/** @internal */
export const asyncGeneratorHelper: UnscopedEmitHelper = {
const asyncGeneratorHelper: UnscopedEmitHelper = {
name: "typescript:asyncGenerator",
importName: "__asyncGenerator",
scoped: false,
@@ -857,8 +847,7 @@ export const asyncGeneratorHelper: UnscopedEmitHelper = {
};`,
};
/** @internal */
export const asyncDelegator: UnscopedEmitHelper = {
const asyncDelegator: UnscopedEmitHelper = {
name: "typescript:asyncDelegator",
importName: "__asyncDelegator",
scoped: false,
@@ -871,8 +860,7 @@ export const asyncDelegator: UnscopedEmitHelper = {
};`,
};
/** @internal */
export const asyncValues: UnscopedEmitHelper = {
const asyncValues: UnscopedEmitHelper = {
name: "typescript:asyncValues",
importName: "__asyncValues",
scoped: false,
@@ -888,8 +876,7 @@ export const asyncValues: UnscopedEmitHelper = {
// ES2018 Destructuring Helpers
/** @internal */
export const restHelper: UnscopedEmitHelper = {
const restHelper: UnscopedEmitHelper = {
name: "typescript:rest",
importName: "__rest",
scoped: false,
@@ -909,8 +896,7 @@ export const restHelper: UnscopedEmitHelper = {
// ES2017 Helpers
/** @internal */
export const awaiterHelper: UnscopedEmitHelper = {
const awaiterHelper: UnscopedEmitHelper = {
name: "typescript:awaiter",
importName: "__awaiter",
scoped: false,
@@ -929,8 +915,7 @@ export const awaiterHelper: UnscopedEmitHelper = {
// ES2015 Helpers
/** @internal */
export const extendsHelper: UnscopedEmitHelper = {
const extendsHelper: UnscopedEmitHelper = {
name: "typescript:extends",
importName: "__extends",
scoped: false,
@@ -954,8 +939,7 @@ export const extendsHelper: UnscopedEmitHelper = {
})();`,
};
/** @internal */
export const templateObjectHelper: UnscopedEmitHelper = {
const templateObjectHelper: UnscopedEmitHelper = {
name: "typescript:makeTemplateObject",
importName: "__makeTemplateObject",
scoped: false,
@@ -967,8 +951,7 @@ export const templateObjectHelper: UnscopedEmitHelper = {
};`,
};
/** @internal */
export const readHelper: UnscopedEmitHelper = {
const readHelper: UnscopedEmitHelper = {
name: "typescript:read",
importName: "__read",
scoped: false,
@@ -991,8 +974,7 @@ export const readHelper: UnscopedEmitHelper = {
};`,
};
/** @internal */
export const spreadArrayHelper: UnscopedEmitHelper = {
const spreadArrayHelper: UnscopedEmitHelper = {
name: "typescript:spreadArray",
importName: "__spreadArray",
scoped: false,
@@ -1008,8 +990,7 @@ export const spreadArrayHelper: UnscopedEmitHelper = {
};`,
};
/** @internal */
export const propKeyHelper: UnscopedEmitHelper = {
const propKeyHelper: UnscopedEmitHelper = {
name: "typescript:propKey",
importName: "__propKey",
scoped: false,
@@ -1020,8 +1001,7 @@ export const propKeyHelper: UnscopedEmitHelper = {
};
// https://tc39.es/ecma262/#sec-setfunctionname
/** @internal */
export const setFunctionNameHelper: UnscopedEmitHelper = {
const setFunctionNameHelper: UnscopedEmitHelper = {
name: "typescript:setFunctionName",
importName: "__setFunctionName",
scoped: false,
@@ -1034,8 +1014,7 @@ export const setFunctionNameHelper: UnscopedEmitHelper = {
// ES2015 Destructuring Helpers
/** @internal */
export const valuesHelper: UnscopedEmitHelper = {
const valuesHelper: UnscopedEmitHelper = {
name: "typescript:values",
importName: "__values",
scoped: false,
@@ -1116,8 +1095,7 @@ export const valuesHelper: UnscopedEmitHelper = {
// entering a finally block.
//
// For examples of how these are used, see the comments in ./transformers/generators.ts
/** @internal */
export const generatorHelper: UnscopedEmitHelper = {
const generatorHelper: UnscopedEmitHelper = {
name: "typescript:generator",
importName: "__generator",
scoped: false,
@@ -1154,8 +1132,7 @@ export const generatorHelper: UnscopedEmitHelper = {
// ES Module Helpers
/** @internal */
export const createBindingHelper: UnscopedEmitHelper = {
const createBindingHelper: UnscopedEmitHelper = {
name: "typescript:commonjscreatebinding",
importName: "__createBinding",
scoped: false,
@@ -1174,8 +1151,7 @@ export const createBindingHelper: UnscopedEmitHelper = {
}));`,
};
/** @internal */
export const setModuleDefaultHelper: UnscopedEmitHelper = {
const setModuleDefaultHelper: UnscopedEmitHelper = {
name: "typescript:commonjscreatevalue",
importName: "__setModuleDefault",
scoped: false,
@@ -1189,8 +1165,7 @@ export const setModuleDefaultHelper: UnscopedEmitHelper = {
};
// emit helper for `import * as Name from "foo"`
/** @internal */
export const importStarHelper: UnscopedEmitHelper = {
const importStarHelper: UnscopedEmitHelper = {
name: "typescript:commonjsimportstar",
importName: "__importStar",
scoped: false,
@@ -1207,8 +1182,7 @@ export const importStarHelper: UnscopedEmitHelper = {
};
// emit helper for `import Name from "foo"`
/** @internal */
export const importDefaultHelper: UnscopedEmitHelper = {
const importDefaultHelper: UnscopedEmitHelper = {
name: "typescript:commonjsimportdefault",
importName: "__importDefault",
scoped: false,
@@ -1218,8 +1192,7 @@ export const importDefaultHelper: UnscopedEmitHelper = {
};`,
};
/** @internal */
export const exportStarHelper: UnscopedEmitHelper = {
const exportStarHelper: UnscopedEmitHelper = {
name: "typescript:export-star",
importName: "__exportStar",
scoped: false,
@@ -1278,10 +1251,8 @@ export const exportStarHelper: UnscopedEmitHelper = {
*
* Reading from a private static method (TS 4.3+):
* __classPrivateFieldGet(<any>, <constructor>, "m", <function>)
*
* @internal
*/
export const classPrivateFieldGetHelper: UnscopedEmitHelper = {
const classPrivateFieldGetHelper: UnscopedEmitHelper = {
name: "typescript:classPrivateFieldGet",
importName: "__classPrivateFieldGet",
scoped: false,
@@ -1343,10 +1314,8 @@ export const classPrivateFieldGetHelper: UnscopedEmitHelper = {
* Writing to a private static method (TS 4.3+):
* __classPrivateFieldSet(<any>, <constructor>, <any>, "m", <function>)
* NOTE: This always results in a runtime error.
*
* @internal
*/
export const classPrivateFieldSetHelper: UnscopedEmitHelper = {
const classPrivateFieldSetHelper: UnscopedEmitHelper = {
name: "typescript:classPrivateFieldSet",
importName: "__classPrivateFieldSet",
scoped: false,
@@ -1370,10 +1339,8 @@ export const classPrivateFieldSetHelper: UnscopedEmitHelper = {
* Usage:
* This helper is used to transform `#field in expression` to
* `__classPrivateFieldIn(<weakMap/weakSet/constructor>, expression)`
*
* @internal
*/
export const classPrivateFieldInHelper: UnscopedEmitHelper = {
const classPrivateFieldInHelper: UnscopedEmitHelper = {
name: "typescript:classPrivateFieldIn",
importName: "__classPrivateFieldIn",
scoped: false,
@@ -1384,10 +1351,7 @@ export const classPrivateFieldInHelper: UnscopedEmitHelper = {
};`,
};
/**
* @internal
*/
export const addDisposableResourceHelper: UnscopedEmitHelper = {
const addDisposableResourceHelper: UnscopedEmitHelper = {
name: "typescript:addDisposableResource",
importName: "__addDisposableResource",
scoped: false,
@@ -1417,9 +1381,11 @@ export const addDisposableResourceHelper: UnscopedEmitHelper = {
};
/**
* @internal
* The `s` variable represents two boolean flags from the `DisposeResources` algorithm:
* - `needsAwait` (`1`) Indicates that an `await using` for a `null` or `undefined` resource was encountered.
* - `hasAwaited` (`2`) Indicates that the algorithm has performed an Await.
*/
export const disposeResourcesHelper: UnscopedEmitHelper = {
const disposeResourcesHelper: UnscopedEmitHelper = {
name: "typescript:disposeResources",
importName: "__disposeResources",
scoped: false,
@@ -1430,17 +1396,22 @@ export const disposeResourcesHelper: UnscopedEmitHelper = {
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
env.hasError = true;
}
var r, s = 0;
function next() {
while (env.stack.length) {
var rec = env.stack.pop();
while (r = env.stack.pop()) {
try {
var result = rec.dispose && rec.dispose.call(rec.value);
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
if (r.dispose) {
var result = r.dispose.call(r.value);
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
else s |= 1;
}
catch (e) {
fail(e);
}
}
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
if (env.hasError) throw env.error;
}
return next();
+1 -1
View File
@@ -364,7 +364,7 @@ export function setIdentifierAutoGenerate<T extends Identifier | PrivateIdentifi
return node;
}
/** @internal */
/** @internal @knipignore */
export function getIdentifierAutoGenerate(node: Identifier | PrivateIdentifier): AutoGenerateInfo | undefined {
return node.emitNode?.autoGenerate;
}
+44 -8
View File
@@ -1,25 +1,61 @@
import {
Debug,
emptyArray,
isNodeKind,
Node,
SourceFileLike,
SyntaxKind,
SyntaxList,
} from "../_namespaces/ts.js";
const nodeChildren = new WeakMap<Node, readonly Node[] | undefined>();
const sourceFileToNodeChildren = new WeakMap<SourceFileLike, WeakMap<Node, readonly Node[] | undefined>>();
/** @internal */
export function getNodeChildren(node: Node): readonly Node[] | undefined {
if (!isNodeKind(node.kind)) return emptyArray;
export function getNodeChildren(node: Node, sourceFile: SourceFileLike): readonly Node[] | undefined {
const kind = node.kind;
if (!isNodeKind(kind)) {
return emptyArray;
}
if (kind === SyntaxKind.SyntaxList) {
return (node as SyntaxList)._children;
}
return nodeChildren.get(node);
return sourceFileToNodeChildren.get(sourceFile)?.get(node);
}
/** @internal */
export function setNodeChildren(node: Node, children: readonly Node[]): readonly Node[] {
nodeChildren.set(node, children);
export function setNodeChildren(node: Node, sourceFile: SourceFileLike, children: readonly Node[]): readonly Node[] {
if (node.kind === SyntaxKind.SyntaxList) {
// SyntaxList children are always eagerly created in the process of
// creating their parent's `children` list. We shouldn't need to set them here.
Debug.fail("Should not need to re-set the children of a SyntaxList.");
}
let map = sourceFileToNodeChildren.get(sourceFile);
if (map === undefined) {
map = new WeakMap();
sourceFileToNodeChildren.set(sourceFile, map);
}
map.set(node, children);
return children;
}
/** @internal */
export function unsetNodeChildren(node: Node) {
nodeChildren.delete(node);
export function unsetNodeChildren(node: Node, origSourceFile: SourceFileLike) {
if (node.kind === SyntaxKind.SyntaxList) {
// Syntax lists are synthesized and we store their children directly on them.
// They are a special case where we expect incremental parsing to toss them away entirely
// if a change intersects with their containing parents.
Debug.fail("Did not expect to unset the children of a SyntaxList.");
}
sourceFileToNodeChildren.get(origSourceFile)?.delete(node);
}
/** @internal */
export function transferSourceFileChildren(sourceFile: SourceFileLike, targetSourceFile: SourceFileLike) {
const map = sourceFileToNodeChildren.get(sourceFile);
if (map !== undefined) {
sourceFileToNodeChildren.delete(sourceFile);
sourceFileToNodeChildren.set(targetSourceFile, map);
}
}
+3 -6
View File
@@ -389,7 +389,6 @@ import {
setEmitFlags,
setIdentifierAutoGenerate,
setIdentifierTypeArguments,
setNodeChildren,
setParent,
setTextRange,
ShorthandPropertyAssignment,
@@ -477,7 +476,7 @@ export const enum NodeFactoryFlags {
const nodeFactoryPatchers: ((factory: NodeFactory) => void)[] = [];
/** @internal */
/** @internal @knipignore */
export function addNodeFactoryPatcher(fn: (factory: NodeFactory) => void) {
nodeFactoryPatchers.push(fn);
}
@@ -6221,7 +6220,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
// @api
function createSyntaxList(children: readonly Node[]) {
const node = createBaseNode<SyntaxList>(SyntaxKind.SyntaxList);
setNodeChildren(node, children);
node._children = children;
return node;
}
@@ -7304,10 +7303,8 @@ function aggregateChildrenFlags(children: MutableNodeArray<Node>) {
/**
* Gets the transform flags to exclude when unioning the transform flags of a subtree.
*
* @internal
*/
export function getTransformFlagsSubtreeExclusions(kind: SyntaxKind) {
function getTransformFlagsSubtreeExclusions(kind: SyntaxKind) {
if (kind >= SyntaxKind.FirstTypeNode && kind <= SyntaxKind.LastTypeNode) {
return TransformFlags.TypeExcludes;
}
+2 -44
View File
@@ -17,8 +17,6 @@ import {
BindingOrAssignmentPattern,
BitwiseOperator,
BitwiseOperatorOrHigher,
Block,
BooleanLiteral,
CharacterCodes,
CommaListExpression,
compareStringsCaseSensitive,
@@ -78,7 +76,6 @@ import {
isAssignmentExpression,
isAssignmentOperator,
isAssignmentPattern,
isBlock,
isCommaListExpression,
isComputedPropertyName,
isDeclarationBindingElement,
@@ -91,10 +88,8 @@ import {
isGeneratedPrivateIdentifier,
isIdentifier,
isInJSFile,
isLiteralExpression,
isMemberName,
isMinusToken,
isModifierKind,
isObjectLiteralElementLike,
isParenthesizedExpression,
isPlusToken,
@@ -139,7 +134,6 @@ import {
NodeArray,
NodeFactory,
nodeIsSynthesized,
NullLiteral,
NumericLiteral,
ObjectLiteralElementLike,
ObjectLiteralExpression,
@@ -333,16 +327,6 @@ export function createForOfBindingStatement(factory: NodeFactory, node: ForIniti
}
}
/** @internal */
export function insertLeadingStatement(factory: NodeFactory, dest: Statement, source: Statement): Block {
if (isBlock(dest)) {
return factory.updateBlock(dest, setTextRange(factory.createNodeArray([source, ...dest.statements]), dest.statements));
}
else {
return factory.createBlock(factory.createNodeArray([dest, source]), /*multiLine*/ true);
}
}
/** @internal */
export function createExpressionFromEntityName(factory: NodeFactory, node: EntityName | Expression): Expression {
if (isQualifiedName(node)) {
@@ -679,15 +663,6 @@ export function walkUpOuterExpressions(node: Expression, kinds = OuterExpression
return parent;
}
/** @internal */
export function skipAssertions(node: Expression): Expression;
/** @internal */
export function skipAssertions(node: Node): Node;
/** @internal */
export function skipAssertions(node: Node): Node {
return skipOuterExpressions(node, OuterExpressionKinds.Assertions);
}
/** @internal */
export function startOnNewLine<T extends Node>(node: T): T {
return setStartsOnNewLine(node, /*newLine*/ true);
@@ -761,8 +736,7 @@ export function createExternalHelpersImportDeclarationIfNeeded(nodeFactory: Node
}
}
/** @internal */
export function getOrCreateExternalHelpersModuleNameIfNeeded(factory: NodeFactory, node: SourceFile, compilerOptions: CompilerOptions, hasExportStarsToExportValues?: boolean, hasImportStarOrImportDefault?: boolean) {
function getOrCreateExternalHelpersModuleNameIfNeeded(factory: NodeFactory, node: SourceFile, compilerOptions: CompilerOptions, hasExportStarsToExportValues?: boolean, hasImportStarOrImportDefault?: boolean) {
if (compilerOptions.importHelpers && isEffectiveExternalModule(node, compilerOptions)) {
const externalHelpersModuleName = getExternalHelpersModuleName(node);
if (externalHelpersModuleName) {
@@ -1116,7 +1090,7 @@ export function getJSDocTypeAliasName(fullName: JSDocNamespaceBody | undefined)
}
}
/** @internal */
/** @internal @knipignore */
export function canHaveIllegalType(node: Node): node is HasIllegalType {
const kind = node.kind;
return kind === SyntaxKind.Constructor
@@ -1183,16 +1157,6 @@ export function isModuleName(node: Node): node is ModuleName {
return isIdentifier(node) || isStringLiteral(node);
}
/** @internal */
export function isLiteralTypeLikeExpression(node: Node): node is NullLiteral | BooleanLiteral | LiteralExpression | PrefixUnaryExpression {
const kind = node.kind;
return kind === SyntaxKind.NullKeyword
|| kind === SyntaxKind.TrueKeyword
|| kind === SyntaxKind.FalseKeyword
|| isLiteralExpression(node)
|| isPrefixUnaryExpression(node);
}
function isExponentiationOperator(kind: SyntaxKind): kind is ExponentiationOperator {
return kind === SyntaxKind.AsteriskAsteriskToken;
}
@@ -1521,12 +1485,6 @@ export function isExportOrDefaultModifier(node: Node): node is ExportKeyword | D
return isExportOrDefaultKeywordKind(kind);
}
/** @internal */
export function isNonExportDefaultModifier(node: Node): node is Exclude<Modifier, ExportKeyword | DefaultKeyword> {
const kind = node.kind;
return isModifierKind(kind) && !isExportOrDefaultKeywordKind(kind);
}
/**
* If `nodes` is not undefined, creates an empty `NodeArray` that preserves the `pos` and `end` of `nodes`.
* @internal
+5 -5
View File
@@ -967,8 +967,7 @@ export interface CacheWithRedirects<K, V> {
/** @internal */
export type RedirectsCacheKey = string & { __compilerOptionsKey: any; };
/** @internal */
export function createCacheWithRedirects<K, V>(ownOptions: CompilerOptions | undefined, optionsToRedirectsKey: Map<CompilerOptions, RedirectsCacheKey>): CacheWithRedirects<K, V> {
function createCacheWithRedirects<K, V>(ownOptions: CompilerOptions | undefined, optionsToRedirectsKey: Map<CompilerOptions, RedirectsCacheKey>): CacheWithRedirects<K, V> {
const redirectsMap = new Map<CompilerOptions, Map<K, V>>();
const redirectsKeyToMap = new Map<RedirectsCacheKey, Map<K, V>>();
let ownMap = new Map<K, V>();
@@ -1752,8 +1751,10 @@ function tryResolveJSModuleWorker(moduleName: string, initialDir: string, host:
/*conditions*/ undefined,
);
}
// knip applies the internal marker to _all_ declarations, not just the one overload.
export function bundlerModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations;
/** @internal */
/** @internal @knipignore */
export function bundlerModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, conditions?: string[]): ResolvedModuleWithFailedLookupLocations; // eslint-disable-line @typescript-eslint/unified-signatures
export function bundlerModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, conditions?: string[]): ResolvedModuleWithFailedLookupLocations {
const containingDirectory = getDirectoryPath(containingFile);
@@ -2432,8 +2433,7 @@ function readPackageJsonPeerDependencies(packageJsonInfo: PackageJsonInfo, state
return result;
}
/** @internal */
export function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PackageJsonInfo | undefined {
function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PackageJsonInfo | undefined {
const { host, traceEnabled } = state;
const packageJsonPath = combinePaths(packageDirectory, "package.json");
if (onlyRecordFailures) {
+10 -7
View File
@@ -369,6 +369,7 @@ import {
tokenIsIdentifierOrKeywordOrGreaterThan,
tokenToString,
tracing,
transferSourceFileChildren,
TransformFlags,
TryStatement,
TupleTypeNode,
@@ -424,6 +425,7 @@ let SourceFileConstructor: new (kind: SyntaxKind.SourceFile, pos: number, end: n
* NOTE: You should not use this, it is only exported to support `createNode` in `~/src/deprecatedCompat/deprecations.ts`.
*
* @internal
* @knipignore
*/
export const parseBaseNodeFactory: BaseNodeFactory = {
createBaseSourceFileNode: kind => new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, -1, -1),
@@ -9972,6 +9974,7 @@ namespace IncrementalParser {
aggressiveChecks,
);
result.impliedNodeFormat = sourceFile.impliedNodeFormat;
transferSourceFileChildren(sourceFile, result);
return result;
}
@@ -10024,9 +10027,9 @@ namespace IncrementalParser {
}
}
function moveElementEntirelyPastChangeRange(element: Node, isArray: false, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;
function moveElementEntirelyPastChangeRange(element: NodeArray<Node>, isArray: true, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;
function moveElementEntirelyPastChangeRange(element: Node | NodeArray<Node>, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) {
function moveElementEntirelyPastChangeRange(element: Node, origSourceFile: SourceFile, isArray: false, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;
function moveElementEntirelyPastChangeRange(element: NodeArray<Node>, origSourceFile: SourceFile, isArray: true, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void;
function moveElementEntirelyPastChangeRange(element: Node | NodeArray<Node>, origSourceFile: SourceFile, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) {
if (isArray) {
visitArray(element as NodeArray<Node>);
}
@@ -10043,7 +10046,7 @@ namespace IncrementalParser {
// Ditch any existing LS children we may have created. This way we can avoid
// moving them forward.
unsetNodeChildren(node);
unsetNodeChildren(node, origSourceFile);
setTextRangePosEnd(node, node.pos + delta, node.end + delta);
@@ -10190,7 +10193,7 @@ namespace IncrementalParser {
if (child.pos > changeRangeOldEnd) {
// Node is entirely past the change range. We need to move both its pos and
// end, forward or backward appropriately.
moveElementEntirelyPastChangeRange(child, /*isArray*/ false, delta, oldText, newText, aggressiveChecks);
moveElementEntirelyPastChangeRange(child, sourceFile, /*isArray*/ false, delta, oldText, newText, aggressiveChecks);
return;
}
@@ -10200,7 +10203,7 @@ namespace IncrementalParser {
const fullEnd = child.end;
if (fullEnd >= changeStart) {
markAsIntersectingIncrementalChange(child);
unsetNodeChildren(child);
unsetNodeChildren(child, sourceFile);
// Adjust the pos or end (or both) of the intersecting element accordingly.
adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);
@@ -10223,7 +10226,7 @@ namespace IncrementalParser {
if (array.pos > changeRangeOldEnd) {
// Array is entirely after the change range. We need to move it, and move any of
// its children.
moveElementEntirelyPastChangeRange(array, /*isArray*/ true, delta, oldText, newText, aggressiveChecks);
moveElementEntirelyPastChangeRange(array, sourceFile, /*isArray*/ true, delta, oldText, newText, aggressiveChecks);
return;
}
+1 -2
View File
@@ -907,8 +907,7 @@ export function startsWithDirectory(fileName: string, directoryName: string, get
//// Relative Paths
/** @internal */
export function getPathComponentsRelativeTo(from: string, to: string, stringEqualityComparer: (a: string, b: string) => boolean, getCanonicalFileName: GetCanonicalFileName) {
function getPathComponentsRelativeTo(from: string, to: string, stringEqualityComparer: (a: string, b: string) => boolean, getCanonicalFileName: GetCanonicalFileName) {
const fromComponents = reducePathComponents(getPathComponents(from));
const toComponents = reducePathComponents(getPathComponents(to));
+214 -241
View File
@@ -140,6 +140,8 @@ import {
getPathFromPathComponents,
getPositionOfLineAndCharacter,
getPropertyArrayElementValue,
getResolvedModuleFromResolution,
getResolvedTypeReferenceDirectiveFromResolution,
getResolveJsonModule,
getRootLength,
getSetExternalModuleIndicator,
@@ -902,7 +904,7 @@ export function getModeForUsageLocation(file: { impliedNodeFormat?: ResolutionMo
}
function getModeForUsageLocationWorker(file: { impliedNodeFormat?: ResolutionMode; }, usage: StringLiteralLike, compilerOptions?: CompilerOptions) {
if ((isImportDeclaration(usage.parent) || isExportDeclaration(usage.parent))) {
if (isImportDeclaration(usage.parent) || isExportDeclaration(usage.parent) || isJSDocImportTag(usage.parent)) {
const isTypeOnly = isExclusivelyTypeOnlyImportOrExport(usage.parent);
if (isTypeOnly) {
const override = getResolutionModeOverride(usage.parent.attributes);
@@ -969,6 +971,12 @@ const emptyResolution: ResolvedModuleWithFailedLookupLocations & ResolvedTypeRef
resolvedTypeReferenceDirective: undefined,
};
/** @internal */
export interface ResolutionWithResolvedFileName {
resolvedFileName: string | undefined;
packageId?: PackageId;
}
/** @internal */
export interface ResolutionNameAndModeGetter<Entry, SourceFile> {
getName(entry: Entry): string;
@@ -1157,11 +1165,6 @@ function getLibFileNameFromLibReference(libReference: FileReference) {
return libMap.get(libName);
}
interface DiagnosticCache<T extends Diagnostic> {
perFile?: Map<Path, readonly T[]>;
allDiagnostics?: readonly T[];
}
/** @internal */
export function isReferencedFile(reason: FileIncludeReason | undefined): reason is ReferencedFile {
switch (reason?.kind) {
@@ -1366,8 +1369,7 @@ export function getImpliedNodeFormatForFileWorker(
}
}
/** @internal */
export const plainJSErrors = new Set<number>([
const plainJSErrors = new Set<number>([
// binder errors
Diagnostics.Cannot_redeclare_block_scoped_variable_0.code,
Diagnostics.A_module_cannot_have_multiple_default_exports.code,
@@ -1548,8 +1550,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
let filesWithReferencesProcessed: Set<Path> | undefined;
let fileReasonsToChain: Map<Path, FileReasonToChainCache> | undefined;
let reasonToRelatedInfo: Map<FileIncludeReason, DiagnosticWithLocation | false> | undefined;
const cachedBindAndCheckDiagnosticsForFile: DiagnosticCache<Diagnostic> = {};
const cachedDeclarationDiagnosticsForFile: DiagnosticCache<DiagnosticWithLocation> = {};
let cachedBindAndCheckDiagnosticsForFile: Map<Path, readonly Diagnostic[]> | undefined;
let cachedDeclarationDiagnosticsForFile: Map<Path, readonly DiagnosticWithLocation[]> | undefined;
let fileProcessingDiagnostics: FilePreprocessingDiagnostics[] | undefined;
let automaticTypeDirectiveNames: string[] | undefined;
@@ -1858,13 +1860,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
// old file wasn't redirect but new file is
(oldSourceFile.resolvedPath === oldSourceFile.path && newFile.resolvedPath !== oldSourceFile.path)
) {
host.onReleaseOldSourceFile(oldSourceFile, oldProgram.getCompilerOptions(), !!getSourceFileByPath(oldSourceFile.path));
host.onReleaseOldSourceFile(oldSourceFile, oldProgram.getCompilerOptions(), !!getSourceFileByPath(oldSourceFile.path), newFile);
}
}
if (!host.getParsedCommandLine) {
oldProgram.forEachResolvedProjectReference(resolvedProjectReference => {
if (!getResolvedProjectReferenceByPath(resolvedProjectReference.sourceFile.path)) {
host.onReleaseOldSourceFile!(resolvedProjectReference.sourceFile, oldProgram!.getCompilerOptions(), /*hasSourceFileByPath*/ false);
host.onReleaseOldSourceFile!(resolvedProjectReference.sourceFile, oldProgram!.getCompilerOptions(), /*hasSourceFileByPath*/ false, /*newSourceFileByResolvedPath*/ undefined);
}
});
}
@@ -2111,27 +2113,47 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
if (fromCache) addResolutionDiagnostics(fromCache);
}
function resolveModuleNamesWorker(moduleNames: readonly StringLiteralLike[], containingFile: SourceFile, reusedNames: readonly StringLiteralLike[] | undefined): readonly ResolvedModuleWithFailedLookupLocations[] {
if (!moduleNames.length) return emptyArray;
function resolveModuleNamesWorker(
moduleNames: readonly StringLiteralLike[],
containingFile: SourceFile,
reusedNames: readonly StringLiteralLike[] | undefined,
): readonly ResolvedModuleWithFailedLookupLocations[] {
const containingFileName = getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory);
const redirectedReference = getRedirectReferenceForResolution(containingFile);
tracing?.push(tracing.Phase.Program, "resolveModuleNamesWorker", { containingFileName });
performance.mark("beforeResolveModule");
const result = actualResolveModuleNamesWorker(moduleNames, containingFileName, redirectedReference, options, containingFile, reusedNames);
const result = actualResolveModuleNamesWorker(
moduleNames,
containingFileName,
redirectedReference,
options,
containingFile,
reusedNames,
);
performance.mark("afterResolveModule");
performance.measure("ResolveModule", "beforeResolveModule", "afterResolveModule");
tracing?.pop();
return result;
}
function resolveTypeReferenceDirectiveNamesWorker<T extends FileReference | string>(typeDirectiveNames: readonly T[], containingFile: string | SourceFile, reusedNames: readonly T[] | undefined): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] {
if (!typeDirectiveNames.length) return [];
function resolveTypeReferenceDirectiveNamesWorker<T extends FileReference | string>(
typeDirectiveNames: readonly T[],
containingFile: string | SourceFile,
reusedNames: readonly T[] | undefined,
): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] {
const containingSourceFile = !isString(containingFile) ? containingFile : undefined;
const containingFileName = !isString(containingFile) ? getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory) : containingFile;
const redirectedReference = containingSourceFile && getRedirectReferenceForResolution(containingSourceFile);
tracing?.push(tracing.Phase.Program, "resolveTypeReferenceDirectiveNamesWorker", { containingFileName });
performance.mark("beforeResolveTypeReference");
const result = actualResolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames, containingFileName, redirectedReference, options, containingSourceFile, reusedNames);
const result = actualResolveTypeReferenceDirectiveNamesWorker(
typeDirectiveNames,
containingFileName,
redirectedReference,
options,
containingSourceFile,
reusedNames,
);
performance.mark("afterResolveTypeReference");
performance.measure("ResolveTypeReference", "beforeResolveTypeReference", "afterResolveTypeReference");
tracing?.pop();
@@ -2215,201 +2237,177 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
return classifiableNames;
}
function resolveModuleNamesReusingOldState(moduleNames: readonly StringLiteralLike[], file: SourceFile): readonly ResolvedModuleWithFailedLookupLocations[] {
if (structureIsReused === StructureIsReused.Not && !file.ambientModuleNames.length) {
// If the old program state does not permit reusing resolutions and `file` does not contain locally defined ambient modules,
// the best we can do is fallback to the default logic.
return resolveModuleNamesWorker(moduleNames, file, /*reusedNames*/ undefined);
}
// At this point, we know at least one of the following hold:
// - file has local declarations for ambient modules
// - old program state is available
// With this information, we can infer some module resolutions without performing resolution.
/** An ordered list of module names for which we cannot recover the resolution. */
let unknownModuleNames: StringLiteralLike[] | undefined;
/**
* The indexing of elements in this list matches that of `moduleNames`.
*
* Before combining results, result[i] is in one of the following states:
* * undefined: needs to be recomputed,
* * predictedToResolveToAmbientModuleMarker: known to be an ambient module.
* Needs to be reset to undefined before returning,
* * ResolvedModuleFull instance: can be reused.
*/
let result: ResolvedModuleWithFailedLookupLocations[] | undefined;
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(file.path)) {
const oldResolution = oldProgram?.getResolvedModule(file, moduleName.text, getModeForUsageLocation(file, moduleName));
if (oldResolution?.resolvedModule) {
if (isTraceEnabled(options, host)) {
trace(
host,
oldResolution.resolvedModule.packageId ?
Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2_with_Package_ID_3 :
Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2,
moduleName.text,
getNormalizedAbsolutePath(file.originalFileName, currentDirectory),
oldResolution.resolvedModule.resolvedFileName,
oldResolution.resolvedModule.packageId && packageIdToString(oldResolution.resolvedModule.packageId),
);
}
(result ??= new Array(moduleNames.length))[i] = oldResolution;
(reusedNames ??= []).push(moduleName);
continue;
}
}
// We know moduleName resolves to an ambient module provided that moduleName:
// - is in the list of ambient modules locally declared in the current source file.
// - resolved to an ambient module in the old program whose declaration is in an unmodified file
// (so the same module declaration will land in the new program)
let resolvesToAmbientModuleInNonModifiedFile = false;
if (contains(file.ambientModuleNames, moduleName.text)) {
resolvesToAmbientModuleInNonModifiedFile = true;
if (isTraceEnabled(options, host)) {
trace(host, Diagnostics.Module_0_was_resolved_as_locally_declared_ambient_module_in_file_1, moduleName.text, getNormalizedAbsolutePath(file.originalFileName, currentDirectory));
}
}
else {
resolvesToAmbientModuleInNonModifiedFile = moduleNameResolvesToAmbientModuleInNonModifiedFile(moduleName);
}
if (resolvesToAmbientModuleInNonModifiedFile) {
(result || (result = new Array(moduleNames.length)))[i] = predictedToResolveToAmbientModuleMarker;
}
else {
// Resolution failed in the old program, or resolved to an ambient module for which we can't reuse the result.
(unknownModuleNames ??= []).push(moduleName);
}
}
const resolutions = unknownModuleNames && unknownModuleNames.length
? resolveModuleNamesWorker(unknownModuleNames, file, reusedNames)
: emptyArray;
// Combine results of resolutions and predicted results
if (!result) {
// There were no unresolved/ambient resolutions.
Debug.assert(resolutions.length === moduleNames.length);
return resolutions;
}
let j = 0;
for (let i = 0; i < result.length; i++) {
if (!result[i]) {
result[i] = resolutions[j];
j++;
}
}
Debug.assert(j === resolutions.length);
return result;
// 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 = 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
// place as we expected to find an actual module file.
// We actually need to return 'false' here even though this seems like a 'true' case
// because the normal module resolution algorithm will find this anyway.
return false;
}
// at least one of declarations should come from non-modified source file
const unmodifiedFile = ambientModuleNameToUnmodifiedFileName.get(moduleName.text);
if (!unmodifiedFile) {
return false;
}
function resolveModuleNamesReusingOldState(moduleNames: readonly StringLiteralLike[], containingFile: SourceFile): readonly ResolvedModuleWithFailedLookupLocations[] {
return resolveNamesReusingOldState({
entries: moduleNames,
containingFile,
containingSourceFile: containingFile,
redirectedReference: getRedirectReferenceForResolution(containingFile),
nameAndModeGetter: moduleResolutionNameAndModeGetter,
resolutionWorker: resolveModuleNamesWorker,
getResolutionFromOldProgram: (name, mode) => oldProgram?.getResolvedModule(containingFile, name, mode),
getResolved: getResolvedModuleFromResolution,
canReuseResolutionsInFile: () =>
containingFile === oldProgram?.getSourceFile(containingFile.fileName) &&
!hasInvalidatedResolutions(containingFile.path),
isEntryResolvingToAmbientModule: moduleNameResolvesToAmbientModule,
});
}
function moduleNameResolvesToAmbientModule(moduleName: StringLiteralLike, file: SourceFile) {
// We know moduleName resolves to an ambient module provided that moduleName:
// - is in the list of ambient modules locally declared in the current source file.
// - resolved to an ambient module in the old program whose declaration is in an unmodified file
// (so the same module declaration will land in the new program)
if (contains(file.ambientModuleNames, moduleName.text)) {
if (isTraceEnabled(options, host)) {
trace(host, Diagnostics.Module_0_was_resolved_as_ambient_module_declared_in_1_since_this_file_was_not_modified, moduleName.text, unmodifiedFile);
trace(host, Diagnostics.Module_0_was_resolved_as_locally_declared_ambient_module_in_file_1, moduleName.text, getNormalizedAbsolutePath(file.originalFileName, currentDirectory));
}
return true;
}
else {
return moduleNameResolvesToAmbientModuleInNonModifiedFile(moduleName, file);
}
}
// If we change our policy of rechecking failed lookups on each program create,
// we should adjust the value returned here.
function moduleNameResolvesToAmbientModuleInNonModifiedFile(moduleName: StringLiteralLike, file: SourceFile): boolean {
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
// place as we expected to find an actual module file.
// We actually need to return 'false' here even though this seems like a 'true' case
// because the normal module resolution algorithm will find this anyway.
return false;
}
// at least one of declarations should come from non-modified source file
const unmodifiedFile = ambientModuleNameToUnmodifiedFileName.get(moduleName.text);
if (!unmodifiedFile) {
return false;
}
if (isTraceEnabled(options, host)) {
trace(host, Diagnostics.Module_0_was_resolved_as_ambient_module_declared_in_1_since_this_file_was_not_modified, moduleName.text, unmodifiedFile);
}
return true;
}
function resolveTypeReferenceDirectiveNamesReusingOldState(typeDirectiveNames: readonly FileReference[], containingFile: SourceFile): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[];
function resolveTypeReferenceDirectiveNamesReusingOldState(typeDirectiveNames: string[], containingFile: string): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[];
function resolveTypeReferenceDirectiveNamesReusingOldState(typeDirectiveNames: readonly string[], containingFile: string): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[];
function resolveTypeReferenceDirectiveNamesReusingOldState<T extends string | FileReference>(typeDirectiveNames: readonly T[], containingFile: string | SourceFile): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] {
if (structureIsReused === StructureIsReused.Not) {
const containingSourceFile = !isString(containingFile) ? containingFile : undefined;
return resolveNamesReusingOldState({
entries: typeDirectiveNames,
containingFile,
containingSourceFile,
redirectedReference: containingSourceFile && getRedirectReferenceForResolution(containingSourceFile),
nameAndModeGetter: typeReferenceResolutionNameAndModeGetter,
resolutionWorker: resolveTypeReferenceDirectiveNamesWorker,
getResolutionFromOldProgram: (name, mode) =>
containingSourceFile ?
oldProgram?.getResolvedTypeReferenceDirective(containingSourceFile, name, mode) :
oldProgram?.getAutomaticTypeDirectiveResolutions()?.get(name, mode),
getResolved: getResolvedTypeReferenceDirectiveFromResolution,
canReuseResolutionsInFile: () =>
containingSourceFile ?
containingSourceFile === oldProgram?.getSourceFile(containingSourceFile.fileName) && !hasInvalidatedResolutions(containingSourceFile.path) :
!hasInvalidatedResolutions(toPath(containingFile as string)),
});
}
interface ResolveNamesReusingOldStateInput<Entry, SourceFileOrString, SourceFileOrUndefined extends SourceFile | undefined, Resolution> {
entries: readonly Entry[];
containingFile: SourceFileOrString;
containingSourceFile: SourceFileOrUndefined;
redirectedReference: ResolvedProjectReference | undefined;
nameAndModeGetter: ResolutionNameAndModeGetter<Entry, SourceFileOrUndefined>;
resolutionWorker: (
entries: readonly Entry[],
containingFile: SourceFileOrString,
reusedNames: readonly Entry[] | undefined,
) => readonly Resolution[];
getResolutionFromOldProgram: (name: string, mode: ResolutionMode) => Resolution | undefined;
getResolved: (oldResolution: Resolution) => ResolutionWithResolvedFileName | undefined;
canReuseResolutionsInFile: () => boolean;
isEntryResolvingToAmbientModule?: (entry: Entry, containingFile: SourceFileOrString) => boolean;
}
function resolveNamesReusingOldState<Entry, SourceFileOrString, SourceFileOrUndefined extends SourceFile | undefined, Resolution>({
entries,
containingFile,
containingSourceFile,
redirectedReference,
nameAndModeGetter,
resolutionWorker,
getResolutionFromOldProgram,
getResolved,
canReuseResolutionsInFile,
isEntryResolvingToAmbientModule,
}: ResolveNamesReusingOldStateInput<Entry, SourceFileOrString, SourceFileOrUndefined, Resolution>): readonly Resolution[] {
if (!entries.length) return emptyArray;
if (structureIsReused === StructureIsReused.Not && (!isEntryResolvingToAmbientModule || !containingSourceFile!.ambientModuleNames.length)) {
// If the old program state does not permit reusing resolutions and `file` does not contain locally defined ambient modules,
// the best we can do is fallback to the default logic.
return resolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames, containingFile, /*reusedNames*/ undefined);
return resolutionWorker(
entries,
containingFile,
/*reusedNames*/ undefined,
);
}
/** 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(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) ?
oldProgram?.getResolvedTypeReferenceDirective(containingFile, typeDirectiveName, mode) :
oldProgram?.getAutomaticTypeDirectiveResolutions()?.get(typeDirectiveName, mode);
if (oldResolution?.resolvedTypeReferenceDirective) {
let unknownEntries: Entry[] | undefined;
let unknownEntryIndices: number[] | undefined;
let result: Resolution[] | undefined;
let reusedNames: Entry[] | undefined;
const reuseResolutions = canReuseResolutionsInFile();
for (let i = 0; i < entries.length; i++) {
const entry = entries[i];
if (reuseResolutions) {
const name = nameAndModeGetter.getName(entry);
const mode = nameAndModeGetter.getMode(entry, containingSourceFile, redirectedReference?.commandLine.options ?? options);
const oldResolution = getResolutionFromOldProgram(name, mode);
const oldResolved = oldResolution && getResolved(oldResolution);
if (oldResolved) {
if (isTraceEnabled(options, host)) {
trace(
host,
oldResolution.resolvedTypeReferenceDirective.packageId ?
resolutionWorker === resolveModuleNamesWorker as unknown ?
oldResolved.packageId ?
Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2_with_Package_ID_3 :
Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_successfully_resolved_to_2 :
oldResolved.packageId ?
Diagnostics.Reusing_resolution_of_type_reference_directive_0_from_1_of_old_program_it_was_successfully_resolved_to_2_with_Package_ID_3 :
Diagnostics.Reusing_resolution_of_type_reference_directive_0_from_1_of_old_program_it_was_successfully_resolved_to_2,
typeDirectiveName,
!isString(containingFile) ? getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory) : containingFile,
oldResolution.resolvedTypeReferenceDirective.resolvedFileName,
oldResolution.resolvedTypeReferenceDirective.packageId && packageIdToString(oldResolution.resolvedTypeReferenceDirective.packageId),
name,
containingSourceFile ? getNormalizedAbsolutePath(containingSourceFile.originalFileName, currentDirectory) : containingFile,
oldResolved.resolvedFileName,
oldResolved.packageId && packageIdToString(oldResolved.packageId),
);
}
(result ??= new Array(typeDirectiveNames.length))[i] = oldResolution;
(result ??= new Array(entries.length))[i] = oldResolution;
(reusedNames ??= []).push(entry);
continue;
}
}
// Resolution failed in the old program, or resolved to an ambient module for which we can't reuse the result.
(unknownTypeReferenceDirectiveNames ??= []).push(entry);
}
if (!unknownTypeReferenceDirectiveNames) return result || emptyArray;
const resolutions = resolveTypeReferenceDirectiveNamesWorker(
unknownTypeReferenceDirectiveNames,
containingFile,
reusedNames,
);
// Combine results of resolutions
if (!result) {
// There were no unresolved resolutions.
Debug.assert(resolutions.length === typeDirectiveNames.length);
return resolutions;
}
let j = 0;
for (let i = 0; i < result.length; i++) {
if (!result[i]) {
result[i] = resolutions[j];
j++;
if (isEntryResolvingToAmbientModule?.(entry, containingFile)) {
(result ??= new Array(entries.length))[i] = emptyResolution;
}
else {
// Resolution failed in the old program, or resolved to an ambient module for which we can't reuse the result.
(unknownEntries ??= []).push(entry);
(unknownEntryIndices ??= []).push(i);
}
}
Debug.assert(j === resolutions.length);
if (!unknownEntries) return result!;
const resolutions = resolutionWorker(unknownEntries, containingFile, reusedNames);
if (!result) return resolutions;
resolutions.forEach((resolution, index) => result[unknownEntryIndices![index]] = resolution);
return result;
}
@@ -2777,7 +2775,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
return true;
}
if (!options.noLib) {
if (options.noLib) {
return false;
}
@@ -2788,7 +2786,11 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
return equalityComparer(file.fileName, getDefaultLibraryFileName());
}
else {
return some(options.lib, libFileName => equalityComparer(file.fileName, resolvedLibReferences!.get(libFileName)!.actual));
return some(options.lib, libFileName => {
// We might not have resolved lib if one of the root file included contained no-default-lib = true
const resolvedLib = resolvedLibReferences!.get(libFileName);
return !!resolvedLib && equalityComparer(file.fileName, resolvedLib.actual);
});
}
}
@@ -2914,10 +2916,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
);
}
function getCachedSemanticDiagnostics(sourceFile?: SourceFile): readonly Diagnostic[] | undefined {
return sourceFile
? cachedBindAndCheckDiagnosticsForFile.perFile?.get(sourceFile.path)
: cachedBindAndCheckDiagnosticsForFile.allDiagnostics;
function getCachedSemanticDiagnostics(sourceFile: SourceFile): readonly Diagnostic[] | undefined {
return cachedBindAndCheckDiagnosticsForFile?.get(sourceFile.path);
}
function getBindAndCheckDiagnostics(sourceFile: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] {
@@ -2938,14 +2938,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
}
function getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[] {
const options = program.getCompilerOptions();
// collect diagnostics from the program only once if either no source file was specified or out/outFile is set (bundled emit)
if (!sourceFile || options.outFile) {
return getDeclarationDiagnosticsWorker(sourceFile, cancellationToken);
}
else {
return getDiagnosticsHelper(sourceFile, getDeclarationDiagnosticsForFile, cancellationToken);
}
return getDiagnosticsHelper(sourceFile, getDeclarationDiagnosticsForFile, cancellationToken);
}
function getSyntacticDiagnosticsForFile(sourceFile: SourceFile): readonly DiagnosticWithLocation[] {
@@ -2994,7 +2987,14 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
if (nodesToCheck) {
return getBindAndCheckDiagnosticsForFileNoCache(sourceFile, cancellationToken, nodesToCheck);
}
return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedBindAndCheckDiagnosticsForFile, getBindAndCheckDiagnosticsForFileNoCache);
let result = cachedBindAndCheckDiagnosticsForFile?.get(sourceFile.path);
if (!result) {
(cachedBindAndCheckDiagnosticsForFile ??= new Map()).set(
sourceFile.path,
result = getBindAndCheckDiagnosticsForFileNoCache(sourceFile, cancellationToken),
);
}
return result;
}
function getBindAndCheckDiagnosticsForFileNoCache(
@@ -3355,11 +3355,18 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
});
}
function getDeclarationDiagnosticsWorker(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken | undefined): readonly DiagnosticWithLocation[] {
return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedDeclarationDiagnosticsForFile, getDeclarationDiagnosticsForFileNoCache);
function getDeclarationDiagnosticsWorker(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined): readonly DiagnosticWithLocation[] {
let result = cachedDeclarationDiagnosticsForFile?.get(sourceFile.path);
if (!result) {
(cachedDeclarationDiagnosticsForFile ??= new Map()).set(
sourceFile.path,
result = getDeclarationDiagnosticsForFileNoCache(sourceFile, cancellationToken),
);
}
return result;
}
function getDeclarationDiagnosticsForFileNoCache(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken | undefined): readonly DiagnosticWithLocation[] {
function getDeclarationDiagnosticsForFileNoCache(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined): readonly DiagnosticWithLocation[] {
return runWithCancellationToken(() => {
const resolver = getTypeChecker().getEmitResolver(sourceFile, cancellationToken);
// Don't actually write any files since we're just getting diagnostics.
@@ -3367,31 +3374,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
});
}
function getAndCacheDiagnostics<T extends SourceFile | undefined, U extends Diagnostic>(
sourceFile: T,
cancellationToken: CancellationToken | undefined,
cache: DiagnosticCache<U>,
getDiagnostics: (sourceFile: T, cancellationToken: CancellationToken | undefined) => readonly U[],
): readonly U[] {
const cachedResult = sourceFile
? cache.perFile?.get(sourceFile.path)
: cache.allDiagnostics;
if (cachedResult) {
return cachedResult;
}
const result = getDiagnostics(sourceFile, cancellationToken);
if (sourceFile) {
(cache.perFile || (cache.perFile = new Map())).set(sourceFile.path, result);
}
else {
cache.allDiagnostics = result;
}
return result;
}
function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined): readonly DiagnosticWithLocation[] {
return sourceFile.isDeclarationFile ? [] : getDeclarationDiagnosticsWorker(sourceFile, cancellationToken);
return sourceFile.isDeclarationFile ? emptyArray : getDeclarationDiagnosticsWorker(sourceFile, cancellationToken);
}
function getOptionsDiagnostics(): SortedReadonlyArray<Diagnostic> {
@@ -4435,7 +4419,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
options.outDir || // there is --outDir specified
options.rootDir || // there is --rootDir specified
options.sourceRoot || // there is --sourceRoot specified
options.mapRoot // there is --mapRoot specified
options.mapRoot || // there is --mapRoot specified
(getEmitDeclarations(options) && options.declarationDir) // there is --declarationDir specified
) {
// Precalculate and cache the common source directory
const dir = getCommonSourceDirectory();
@@ -4454,16 +4439,6 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
if (!getEmitDeclarations(options)) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "emitDeclarationOnly", "declaration", "composite");
}
if (options.noEmit) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "emitDeclarationOnly", "noEmit");
}
}
if (options.noCheck) {
if (options.noEmit) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noCheck", "noEmit");
}
}
if (
@@ -5354,8 +5329,6 @@ export function handleNoEmitOptions<T extends BuilderProgram>(
): EmitResult | undefined {
const options = program.getCompilerOptions();
if (options.noEmit) {
// Cache the semantic diagnostics
program.getSemanticDiagnostics(sourceFile, cancellationToken);
return sourceFile ?
emitSkippedWithNoDiagnostics :
program.emitBuildInfo(writeFile, cancellationToken);
+54 -76
View File
@@ -30,9 +30,10 @@ import {
getOptionsForLibraryResolution,
getPathComponents,
getPathFromPathComponents,
getResolvedModuleFromResolution,
getResolvedTypeReferenceDirectiveFromResolution,
HasInvalidatedLibResolutions,
HasInvalidatedResolutions,
hasTrailingDirectorySeparator,
ignoredPaths,
inferredTypesContainingFile,
isDiskPathRoot,
@@ -51,7 +52,6 @@ import {
mutateMap,
noopFileWatcher,
normalizePath,
PackageId,
packageIdToString,
PackageJsonInfoCacheEntry,
parseNodeModuleFromPath,
@@ -63,6 +63,7 @@ import {
resolutionExtensionIsTSOrJson,
ResolutionLoader,
ResolutionMode,
ResolutionWithResolvedFileName,
ResolvedModuleWithFailedLookupLocations,
ResolvedProjectReference,
ResolvedTypeReferenceDirectiveWithFailedLookupLocations,
@@ -140,7 +141,7 @@ export interface ResolutionCache {
invalidateResolutionsOfFailedLookupLocations(): boolean;
invalidateResolutionOfFile(filePath: Path): void;
removeResolutionsOfFile(filePath: Path, syncDirWatcherRemove?: boolean): void;
removeResolutionsOfFile(filePath: Path): void;
removeResolutionsFromProjectReferenceRedirects(filePath: Path): void;
setFilesWithInvalidatedNonRelativeUnresolvedImports(filesWithUnresolvedImports: Map<Path, readonly string[]>): void;
createHasInvalidatedResolutions(
@@ -167,18 +168,11 @@ export interface ResolutionWithFailedLookupLocations {
failedLookupLocations?: string[];
affectingLocations?: string[];
isInvalidated?: boolean;
refCount?: number;
// Files that have this resolution using
files?: Set<Path>;
alternateResult?: string;
}
/** @internal */
export interface ResolutionWithResolvedFileName {
resolvedFileName: string | undefined;
packageId?: PackageId;
}
/** @internal */
export interface CachedResolvedModuleWithFailedLookupLocations extends ResolvedModuleWithFailedLookupLocations, ResolutionWithFailedLookupLocations {
}
@@ -192,6 +186,7 @@ export interface ResolutionCacheHost extends MinimalResolutionCacheHost {
toPath(fileName: string): Path;
getCanonicalFileName: GetCanonicalFileName;
getCompilationSettings(): CompilerOptions;
preferNonRecursiveWatch: boolean | undefined;
watchDirectoryOfFailedLookupLocation(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags): FileWatcher;
watchAffectingFileLocation(file: string, cb: FileWatcherCallback): FileWatcher;
onInvalidatedResolution(): void;
@@ -351,6 +346,7 @@ export function getDirectoryToWatchFailedLookupLocation(
rootPath: Path,
rootPathComponents: Readonly<PathPathComponents>,
getCurrentDirectory: () => string | undefined,
preferNonRecursiveWatch: boolean | undefined,
): DirectoryOfFailedLookupWatch | undefined {
const failedLookupPathComponents: Readonly<PathPathComponents> = getPathComponents(failedLookupLocationPath);
// Ensure failed look up is normalized path
@@ -390,6 +386,7 @@ export function getDirectoryToWatchFailedLookupLocation(
nodeModulesIndex,
rootPathComponents,
lastNodeModulesIndex,
preferNonRecursiveWatch,
);
}
@@ -401,6 +398,7 @@ function getDirectoryToWatchFromFailedLookupLocationDirectory(
nodeModulesIndex: number,
rootPathComponents: Readonly<PathPathComponents>,
lastNodeModulesIndex: number,
preferNonRecursiveWatch: boolean | undefined,
): DirectoryOfFailedLookupWatch | undefined {
// If directory path contains node module, get the most parent node_modules directory for watching
if (nodeModulesIndex !== -1) {
@@ -412,14 +410,17 @@ function getDirectoryToWatchFromFailedLookupLocationDirectory(
lastNodeModulesIndex,
);
}
// Use some ancestor of the root directory
let nonRecursive = true;
let length = dirPathComponentsLength;
for (let i = 0; i < dirPathComponentsLength; i++) {
if (dirPathComponents[i] !== rootPathComponents[i]) {
nonRecursive = false;
length = Math.max(i + 1, perceivedOsRootLength + 1);
break;
if (!preferNonRecursiveWatch) {
for (let i = 0; i < dirPathComponentsLength; i++) {
if (dirPathComponents[i] !== rootPathComponents[i]) {
nonRecursive = false;
length = Math.max(i + 1, perceivedOsRootLength + 1);
break;
}
}
}
return getDirectoryOfFailedLookupWatch(
@@ -463,6 +464,7 @@ export function getDirectoryToWatchFailedLookupLocationFromTypeRoot(
rootPath: Path,
rootPathComponents: Readonly<PathPathComponents>,
getCurrentDirectory: () => string | undefined,
preferNonRecursiveWatch: boolean | undefined,
filterCustomPath: (path: Path) => boolean, // Return true if this path can be used
): Path | undefined {
const typeRootPathComponents = getPathComponents(typeRootPath);
@@ -479,6 +481,7 @@ export function getDirectoryToWatchFailedLookupLocationFromTypeRoot(
typeRootPathComponents.indexOf("node_modules" as Path),
rootPathComponents,
typeRootPathComponents.lastIndexOf("node_modules" as Path),
preferNonRecursiveWatch,
);
return toWatch && filterCustomPath(toWatch.dirPath) ? toWatch.dirPath : undefined;
}
@@ -491,11 +494,6 @@ export function getRootDirectoryOfResolutionCache(rootDirForResolution: string,
normalized;
}
/** @internal */
export function getRootPathSplitLength(rootPath: Path) {
return rootPath.split(directorySeparator).length - (hasTrailingDirectorySeparator(rootPath) ? 1 : 0);
}
function getModuleResolutionHost(resolutionHost: ResolutionCacheHost) {
return resolutionHost.getCompilerHost?.() || resolutionHost;
}
@@ -670,14 +668,6 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
onChangesAffectModuleResolution,
};
function getResolvedModule(resolution: CachedResolvedModuleWithFailedLookupLocations) {
return resolution.resolvedModule;
}
function getResolvedTypeReferenceDirective(resolution: CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations) {
return resolution.resolvedTypeReferenceDirective;
}
function clear() {
clearMap(directoryWatchesOfFailedLookups, closeFileWatcherOf);
clearMap(fileWatchesOfAffectingLocations, closeFileWatcherOf);
@@ -776,7 +766,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
stopWatchFailedLookupLocationOfResolution(
resolution,
resolutionHost.toPath(getInferredLibraryNameResolveFrom(resolutionHost.getCompilationSettings(), getCurrentDirectory(), libFileName)),
getResolvedModule,
getResolvedModuleFromResolution,
);
resolvedLibraries.delete(libFileName);
}
@@ -1003,7 +993,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
getModuleResolutionHost(resolutionHost),
typeReferenceDirectiveResolutionCache,
),
getResolutionWithResolvedFileName: getResolvedTypeReferenceDirective,
getResolutionWithResolvedFileName: getResolvedTypeReferenceDirectiveFromResolution,
shouldRetryResolution: resolution => resolution.resolvedTypeReferenceDirective === undefined,
deferWatchingNonRelativeResolution: false,
});
@@ -1032,7 +1022,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
resolutionHost,
moduleResolutionCache,
),
getResolutionWithResolvedFileName: getResolvedModule,
getResolutionWithResolvedFileName: getResolvedModuleFromResolution,
shouldRetryResolution: resolution => !resolution.resolvedModule || !resolutionExtensionIsTSOrJson(resolution.resolvedModule.extension),
logChanges: logChangesWhenResolvingModule,
deferWatchingNonRelativeResolution: true, // Defer non relative resolution watch because we could be using ambient modules
@@ -1051,15 +1041,15 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
const existingResolution = resolution;
resolution = ts_resolveLibrary(libraryName, resolveFrom, options, host, libraryResolutionCache);
const path = resolutionHost.toPath(resolveFrom);
watchFailedLookupLocationsOfExternalModuleResolutions(libraryName, resolution, path, getResolvedModule, /*deferWatchingNonRelativeResolution*/ false);
watchFailedLookupLocationsOfExternalModuleResolutions(libraryName, resolution, path, getResolvedModuleFromResolution, /*deferWatchingNonRelativeResolution*/ false);
resolvedLibraries.set(libFileName, resolution);
if (existingResolution) {
stopWatchFailedLookupLocationOfResolution(existingResolution, path, getResolvedModule);
stopWatchFailedLookupLocationOfResolution(existingResolution, path, getResolvedModuleFromResolution);
}
}
else {
if (isTraceEnabled(options, host)) {
const resolved = getResolvedModule(resolution);
const resolved = getResolvedModuleFromResolution(resolution);
trace(
host,
resolved?.resolvedFileName ?
@@ -1107,28 +1097,21 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>,
deferWatchingNonRelativeResolution: boolean,
) {
if (resolution.refCount) {
resolution.refCount++;
Debug.assertIsDefined(resolution.files);
(resolution.files ??= new Set()).add(filePath);
if (resolution.files.size !== 1) return;
if (!deferWatchingNonRelativeResolution || isExternalModuleNameRelative(name)) {
watchFailedLookupLocationOfResolution(resolution);
}
else {
resolution.refCount = 1;
Debug.assert(!resolution.files?.size); // This resolution shouldnt be referenced by any file yet
if (!deferWatchingNonRelativeResolution || isExternalModuleNameRelative(name)) {
watchFailedLookupLocationOfResolution(resolution);
}
else {
nonRelativeExternalModuleResolutions.add(name, resolution);
}
const resolved = getResolutionWithResolvedFileName(resolution);
if (resolved && resolved.resolvedFileName) {
const key = resolutionHost.toPath(resolved.resolvedFileName);
let resolutions = resolvedFileToResolution.get(key);
if (!resolutions) resolvedFileToResolution.set(key, resolutions = new Set());
resolutions.add(resolution);
}
nonRelativeExternalModuleResolutions.add(name, resolution);
}
const resolved = getResolutionWithResolvedFileName(resolution);
if (resolved && resolved.resolvedFileName) {
const key = resolutionHost.toPath(resolved.resolvedFileName);
let resolutions = resolvedFileToResolution.get(key);
if (!resolutions) resolvedFileToResolution.set(key, resolutions = new Set());
resolutions.add(resolution);
}
(resolution.files ??= new Set()).add(filePath);
}
function watchFailedLookupLocation(failedLookupLocation: string, setAtRoot: boolean) {
@@ -1140,6 +1123,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
rootPath,
rootPathComponents,
getCurrentDirectory,
resolutionHost.preferNonRecursiveWatch,
);
if (toWatch) {
const { dir, dirPath, nonRecursive, packageDir, packageDirPath } = toWatch;
@@ -1156,7 +1140,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
}
function watchFailedLookupLocationOfResolution(resolution: ResolutionWithFailedLookupLocations) {
Debug.assert(!!resolution.refCount);
Debug.assert(!!resolution.files?.size);
const { failedLookupLocations, affectingLocations, alternateResult } = resolution;
if (!failedLookupLocations?.length && !affectingLocations?.length && !alternateResult) return;
@@ -1177,7 +1161,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
}
function watchAffectingLocationsOfResolution(resolution: ResolutionWithFailedLookupLocations, addToResolutionsWithOnlyAffectingLocations: boolean) {
Debug.assert(!!resolution.refCount);
Debug.assert(!!resolution.files?.size);
const { affectingLocations } = resolution;
if (!affectingLocations?.length) return;
if (addToResolutionsWithOnlyAffectingLocations) resolutionsWithOnlyAffectingLocations.add(resolution);
@@ -1289,7 +1273,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
else if (packageDirWatcher.isSymlink !== isSymlink) {
// Handle the change
packageDirWatcher.dirPathToWatcher.forEach(watcher => {
removeDirectoryWatcher(packageDirWatcher!.isSymlink ? packageDirPath : dirPath, /*syncDirWatcherRemove*/ false);
removeDirectoryWatcher(packageDirWatcher!.isSymlink ? packageDirPath : dirPath);
watcher.watcher = createDirPathToWatcher();
});
packageDirWatcher.isSymlink = isSymlink;
@@ -1345,7 +1329,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
return dirWatcher;
}
function stopWatchFailedLookupLocation(failedLookupLocation: string, removeAtRoot: boolean, syncDirWatcherRemove: boolean | undefined) {
function stopWatchFailedLookupLocation(failedLookupLocation: string, removeAtRoot: boolean) {
const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation);
const toWatch = getDirectoryToWatchFailedLookupLocation(
failedLookupLocation,
@@ -1354,6 +1338,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
rootPath,
rootPathComponents,
getCurrentDirectory,
resolutionHost.preferNonRecursiveWatch,
);
if (toWatch) {
const { dirPath, packageDirPath } = toWatch;
@@ -1365,7 +1350,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
const forDirPath = packageDirWatcher.dirPathToWatcher.get(dirPath)!;
forDirPath.refCount--;
if (forDirPath.refCount === 0) {
removeDirectoryWatcher(packageDirWatcher.isSymlink ? packageDirPath : dirPath, syncDirWatcherRemove);
removeDirectoryWatcher(packageDirWatcher.isSymlink ? packageDirPath : dirPath);
packageDirWatcher.dirPathToWatcher.delete(dirPath);
if (packageDirWatcher.isSymlink) {
const refCount = dirPathToSymlinkPackageRefCount.get(dirPath)! - 1;
@@ -1376,11 +1361,10 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
dirPathToSymlinkPackageRefCount.set(dirPath, refCount);
}
}
if (syncDirWatcherRemove) closePackageDirWatcher(packageDirWatcher, packageDirPath);
}
}
else {
removeDirectoryWatcher(dirPath, syncDirWatcherRemove);
removeDirectoryWatcher(dirPath);
}
}
return removeAtRoot;
@@ -1390,13 +1374,10 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
resolution: T,
filePath: Path,
getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName<T, R>,
syncDirWatcherRemove?: boolean,
) {
Debug.checkDefined(resolution.files).delete(filePath);
resolution.refCount!--;
if (resolution.refCount) {
return;
}
if (resolution.files!.size) return;
resolution.files = undefined;
const resolved = getResolutionWithResolvedFileName(resolution);
if (resolved && resolved.resolvedFileName) {
const key = resolutionHost.toPath(resolved.resolvedFileName);
@@ -1409,11 +1390,11 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
let removeAtRoot = false;
if (failedLookupLocations) {
for (const failedLookupLocation of failedLookupLocations) {
removeAtRoot = stopWatchFailedLookupLocation(failedLookupLocation, removeAtRoot, syncDirWatcherRemove);
removeAtRoot = stopWatchFailedLookupLocation(failedLookupLocation, removeAtRoot);
}
}
if (alternateResult) removeAtRoot = stopWatchFailedLookupLocation(alternateResult, removeAtRoot, syncDirWatcherRemove);
if (removeAtRoot) removeDirectoryWatcher(rootPath, syncDirWatcherRemove);
if (alternateResult) removeAtRoot = stopWatchFailedLookupLocation(alternateResult, removeAtRoot);
if (removeAtRoot) removeDirectoryWatcher(rootPath);
}
else if (affectingLocations?.length) {
resolutionsWithOnlyAffectingLocations.delete(resolution);
@@ -1423,16 +1404,14 @@ 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: Path, syncDirWatcherRemove: boolean | undefined) {
function removeDirectoryWatcher(dirPath: Path) {
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) {
@@ -1451,7 +1430,6 @@ 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);
@@ -1461,7 +1439,6 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
resolution,
filePath,
getResolutionWithResolvedFileName,
syncDirWatcherRemove,
)
);
cache.delete(filePath);
@@ -1482,9 +1459,9 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
resolvedProjectReference.commandLine.fileNames.forEach(f => removeResolutionsOfFile(resolutionHost.toPath(f)));
}
function removeResolutionsOfFile(filePath: Path, syncDirWatcherRemove?: boolean) {
removeResolutionsOfFileFromCache(resolvedModuleNames, filePath, getResolvedModule, syncDirWatcherRemove);
removeResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath, getResolvedTypeReferenceDirective, syncDirWatcherRemove);
function removeResolutionsOfFile(filePath: Path) {
removeResolutionsOfFileFromCache(resolvedModuleNames, filePath, getResolvedModuleFromResolution);
removeResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath, getResolvedTypeReferenceDirectiveFromResolution);
}
function invalidateResolutions(resolutions: Set<ResolutionWithFailedLookupLocations> | Map<string, ResolutionWithFailedLookupLocations> | undefined, canInvalidate: (resolution: ResolutionWithFailedLookupLocations) => boolean | undefined) {
@@ -1662,6 +1639,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
rootPath,
rootPathComponents,
getCurrentDirectory,
resolutionHost.preferNonRecursiveWatch,
dirPath => directoryWatchesOfFailedLookups.has(dirPath) || dirPathToSymlinkPackageRefCount.has(dirPath),
);
if (dirPath) {
+5 -8
View File
@@ -419,12 +419,12 @@ export function stringToToken(s: string): SyntaxKind | undefined {
const regExpFlagCharCodes = makeReverseMap(charCodeToRegExpFlag);
/** @internal */
/** @internal @knipignore */
export function regularExpressionFlagToCharacterCode(f: RegularExpressionFlags): CharacterCodes | undefined {
return regExpFlagCharCodes[f];
}
/** @internal */
/** @internal @knipignore */
export function characterCodeToRegularExpressionFlag(ch: CharacterCodes): RegularExpressionFlags | undefined {
return charCodeToRegExpFlag.get(ch);
}
@@ -603,8 +603,7 @@ function isWordCharacter(ch: number): boolean {
return isASCIILetter(ch) || isDigit(ch) || ch === CharacterCodes._;
}
/** @internal */
export function isOctalDigit(ch: number): boolean {
function isOctalDigit(ch: number): boolean {
return ch >= CharacterCodes._0 && ch <= CharacterCodes._7;
}
@@ -789,15 +788,13 @@ function scanConflictMarkerTrivia(text: string, pos: number, error?: (diag: Diag
const shebangTriviaRegex = /^#!.*/;
/** @internal */
export function isShebangTrivia(text: string, pos: number) {
function isShebangTrivia(text: string, pos: number) {
// Shebangs check must only be done at the start of the file
Debug.assert(pos === 0);
return shebangTriviaRegex.test(text);
}
/** @internal */
export function scanShebangTrivia(text: string, pos: number) {
function scanShebangTrivia(text: string, pos: number) {
const shebang = shebangTriviaRegex.exec(text)![0];
pos = pos + shebang.length;
return pos;
+1 -2
View File
@@ -405,8 +405,7 @@ function isStringOrNull(x: any) {
return typeof x === "string" || x === null;
}
/** @internal */
export function isRawSourceMap(x: any): x is RawSourceMap {
function isRawSourceMap(x: any): x is RawSourceMap {
return x !== null
&& typeof x === "object"
&& x.version === 3
+3 -1
View File
@@ -1409,6 +1409,7 @@ export interface System {
*/
watchFile?(path: string, callback: FileWatcherCallback, pollingInterval?: number, options?: WatchOptions): FileWatcher;
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean, options?: WatchOptions): FileWatcher;
/**@internal */ preferNonRecursiveWatch?: boolean;
resolvePath(path: string): string;
fileExists(path: string): boolean;
directoryExists(path: string): boolean;
@@ -1534,6 +1535,7 @@ export let sys: System = (() => {
writeFile,
watchFile,
watchDirectory,
preferNonRecursiveWatch: !fsSupportsRecursiveFsWatch,
resolvePath: path => _path.resolve(path),
fileExists,
directoryExists,
@@ -1994,7 +1996,7 @@ export let sys: System = (() => {
return sys!;
})();
/** @internal */
/** @internal @knipignore */
export function setSys(s: System) {
sys = s;
}
-2
View File
@@ -464,8 +464,6 @@ export function transformClassFields(context: TransformationContext): (x: Source
}
switch (node.kind) {
case SyntaxKind.AccessorKeyword:
return Debug.fail("Use `modifierVisitor` instead.");
case SyntaxKind.ClassDeclaration:
return visitClassDeclaration(node as ClassDeclaration);
case SyntaxKind.ClassExpression:
+1 -2
View File
@@ -29,9 +29,8 @@ import {
* @param classThis The identifier to use for the captured static `this` reference, usually with the name `_classThis`.
* @param thisExpression Overrides the expression to use for the actual `this` reference. This can be used to provide an
* expression that has already had its `EmitFlags` set or may have been tracked to prevent substitution.
* @internal
*/
export function createClassThisAssignmentBlock(factory: NodeFactory, classThis: Identifier, thisExpression = factory.createThis()): ClassThisAssignmentBlock {
function createClassThisAssignmentBlock(factory: NodeFactory, classThis: Identifier, thisExpression = factory.createThis()): ClassThisAssignmentBlock {
// produces:
//
// static { _classThis = this; }
+17 -11
View File
@@ -214,19 +214,24 @@ import {
} from "../_namespaces/ts.js";
/** @internal */
export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, file: SourceFile | undefined): DiagnosticWithLocation[] | undefined {
export function getDeclarationDiagnostics(
host: EmitHost,
resolver: EmitResolver,
file: SourceFile,
): DiagnosticWithLocation[] | undefined {
const compilerOptions = host.getCompilerOptions();
const files = filter(getSourceFilesToEmit(host, file), isSourceFileNotJson);
const result = transformNodes(
resolver,
host,
factory,
compilerOptions,
file ? contains(files, file) ? [file] : emptyArray : files,
[transformDeclarations],
/*allowDtsFiles*/ false,
);
return result.diagnostics;
return contains(files, file) ?
transformNodes(
resolver,
host,
factory,
compilerOptions,
[file],
[transformDeclarations],
/*allowDtsFiles*/ false,
).diagnostics :
undefined;
}
const declarationEmitNodeBuilderFlags = NodeBuilderFlags.MultilineObjectLiterals |
@@ -303,6 +308,7 @@ export function transformDeclarations(context: TransformationContext) {
}
function reportInferenceFallback(node: Node) {
if (!isolatedDeclarations || isSourceFileJS(currentSourceFile)) return;
if (getSourceFileOfNode(node) !== currentSourceFile) return; // Nested error on a declaration in another file - ignore, will be reemitted if file is in the output file set
if (isVariableDeclaration(node) && resolver.isExpandoFunctionDeclaration(node)) {
reportExpandoFunctionErrors(node);
}
+2 -4
View File
@@ -52,9 +52,8 @@ import {
/**
* Gets a string literal to use as the assigned name of an anonymous class or function declaration.
* @internal
*/
export function getAssignedNameOfIdentifier(factory: NodeFactory, name: Identifier, expression: WrappedExpression<AnonymousFunctionDefinition>): StringLiteral {
function getAssignedNameOfIdentifier(factory: NodeFactory, name: Identifier, expression: WrappedExpression<AnonymousFunctionDefinition>): StringLiteral {
const original = getOriginalNode(skipOuterExpressions(expression));
if (
(isClassDeclaration(original) || isFunctionDeclaration(original)) &&
@@ -98,9 +97,8 @@ function getAssignedNameOfPropertyName(context: TransformationContext, name: Pro
* side effects.
* @param thisExpression Overrides the expression to use for the actual `this` reference. This can be used to provide an
* expression that has already had its `EmitFlags` set or may have been tracked to prevent substitution.
* @internal
*/
export function createClassNamedEvaluationHelperBlock(context: TransformationContext, assignedName: Expression, thisExpression: Expression = context.factory.createThis()): ClassNamedEvaluationHelperBlock {
function createClassNamedEvaluationHelperBlock(context: TransformationContext, assignedName: Expression, thisExpression: Expression = context.factory.createThis()): ClassNamedEvaluationHelperBlock {
// produces:
//
// static { __setFunctionName(this, "C"); }
+3 -6
View File
@@ -429,8 +429,7 @@ export class IdentifierNameMap<V> {
}
}
/** @internal */
export class IdentifierNameMultiMap<V> extends IdentifierNameMap<V[]> {
class IdentifierNameMultiMap<V> extends IdentifierNameMap<V[]> {
add(key: Identifier, value: V): V[] {
let values = this.get(key);
if (values) {
@@ -801,8 +800,7 @@ export interface LexicalEnvironment<in out TEnvData, TPrivateEnvData, TPrivateEn
readonly previous: LexicalEnvironment<TEnvData, TPrivateEnvData, TPrivateEntry> | undefined;
}
/** @internal */
export function walkUpLexicalEnvironments<TEnvData, TPrivateEnvData, TPrivateEntry, U>(
function walkUpLexicalEnvironments<TEnvData, TPrivateEnvData, TPrivateEntry, U>(
env: LexicalEnvironment<TEnvData, TPrivateEnvData, TPrivateEntry> | undefined,
cb: (env: LexicalEnvironment<TEnvData, TPrivateEnvData, TPrivateEntry>) => U,
): U | undefined {
@@ -856,8 +854,7 @@ export function accessPrivateIdentifier<
return walkUpLexicalEnvironments(env, env => getPrivateIdentifier(env.privateEnv, name));
}
/** @internal */
export function isSimpleParameter(node: ParameterDeclaration) {
function isSimpleParameter(node: ParameterDeclaration) {
return !node.initializer && isIdentifier(node.name);
}
+27 -9
View File
@@ -66,7 +66,7 @@ import {
getNonIncrementalBuildInfoRoots,
getNormalizedAbsolutePath,
getParsedCommandLineOfConfigFile,
getPendingEmitKind,
getPendingEmitKindWithSeen,
getSourceFileVersionAsHashFromText,
getTsBuildInfoEmitOutputFilePath,
getWatchErrorSummaryDiagnosticMessage,
@@ -198,10 +198,8 @@ function getOrCreateValueMapFromConfigFileMap<K extends string, V>(configFileMap
/**
* Helper to use now method instead of current date for testing purposes to get consistent baselines
*
* @internal
*/
export function getCurrentTime(host: { now?(): Date; }) {
function getCurrentTime(host: { now?(): Date; }) {
return host.now ? host.now() : new Date();
}
@@ -1513,8 +1511,14 @@ function getUpToDateStatusWorker<T extends BuilderProgram>(state: SolutionBuilde
// If there are errors, we need to build project again to report it
if (
!project.options.noCheck &&
(incrementalBuildInfo.semanticDiagnosticsPerFile?.length ||
(!project.options.noEmit && getEmitDeclarations(project.options) && incrementalBuildInfo.emitDiagnosticsPerFile?.length))
(
incrementalBuildInfo.changeFileSet?.length ||
incrementalBuildInfo.semanticDiagnosticsPerFile?.length ||
(
getEmitDeclarations(project.options) &&
incrementalBuildInfo.emitDiagnosticsPerFile?.length
)
)
) {
return {
type: UpToDateStatusType.OutOfDateBuildInfoWithErrors,
@@ -1525,8 +1529,11 @@ function getUpToDateStatusWorker<T extends BuilderProgram>(state: SolutionBuilde
// If there are pending changes that are not emitted, project is out of date
if (
!project.options.noEmit &&
((incrementalBuildInfo as IncrementalMultiFileEmitBuildInfo).affectedFilesPendingEmit?.length ||
(incrementalBuildInfo as IncrementalBundleEmitBuildInfo).pendingEmit !== undefined)
(
incrementalBuildInfo.changeFileSet?.length ||
(incrementalBuildInfo as IncrementalMultiFileEmitBuildInfo).affectedFilesPendingEmit?.length ||
(incrementalBuildInfo as IncrementalBundleEmitBuildInfo).pendingEmit !== undefined
)
) {
return {
type: UpToDateStatusType.OutOfDateBuildInfoWithPendingEmit,
@@ -1535,7 +1542,18 @@ function getUpToDateStatusWorker<T extends BuilderProgram>(state: SolutionBuilde
}
// Has not emitted some of the files, project is out of date
if (!project.options.noEmit && getPendingEmitKind(project.options, incrementalBuildInfo.options || {})) {
if (
(
!project.options.noEmit ||
(project.options.noEmit && getEmitDeclarations(project.options))
) &&
getPendingEmitKindWithSeen(
project.options,
incrementalBuildInfo.options || {},
/*emitOnlyDtsFiles*/ undefined,
!!project.options.noEmit,
)
) {
return {
type: UpToDateStatusType.OutOfDateOptions,
buildInfoFile: buildInfoPath,
+12 -21
View File
@@ -1308,7 +1308,7 @@ export type HasExpressionInitializer =
| PropertyAssignment
| EnumMember;
/** @internal */
/** @internal @knipignore */
export type HasIllegalExpressionInitializer = PropertySignature;
// NOTE: Changing the following list requires changes to:
@@ -2316,7 +2316,7 @@ export interface TypeOperatorNode extends TypeNode {
readonly type: TypeNode;
}
/** @internal */
/** @internal @knipignore */
export interface UniqueTypeOperatorNode extends TypeOperatorNode {
readonly operator: SyntaxKind.UniqueKeyword;
}
@@ -2668,7 +2668,7 @@ export type ObjectBindingOrAssignmentElement =
| SpreadAssignment // AssignmentRestProperty
;
/** @internal */
/** @internal @knipignore */
export type ObjectAssignmentElement = Exclude<ObjectBindingOrAssignmentElement, BindingElement>;
export type ArrayBindingOrAssignmentElement =
@@ -2699,7 +2699,7 @@ export type BindingOrAssignmentElementTarget =
| ElementAccessExpression
| OmittedExpression;
/** @internal */
/** @internal @knipignore */
export type AssignmentElementTarget = Exclude<BindingOrAssignmentElementTarget, BindingPattern>;
export type ObjectBindingOrAssignmentPattern =
@@ -4746,7 +4746,7 @@ export interface Program extends ScriptReferenceHost {
/** @internal */ getCommonSourceDirectory(): string;
/** @internal */ getCachedSemanticDiagnostics(sourceFile?: SourceFile): readonly Diagnostic[] | undefined;
/** @internal */ getCachedSemanticDiagnostics(sourceFile: SourceFile): readonly Diagnostic[] | undefined;
/** @internal */ getClassifiableNames(): Set<__String>;
@@ -5506,12 +5506,6 @@ export const enum SymbolAccessibility {
NotResolved,
}
/** @internal */
export const enum SyntheticSymbolKind {
UnionOrIntersection,
Spread,
}
export const enum TypePredicateKind {
This,
Identifier,
@@ -7982,7 +7976,7 @@ export interface CompilerHost extends ModuleResolutionHost {
*/
hasInvalidatedLibResolutions?(libFileName: string): boolean;
getEnvironmentVariable?(name: string): string | undefined;
/** @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean): void;
/** @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean, newSourceFileByResolvedPath: SourceFile | undefined): void;
/** @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void;
/** If provided along with custom resolveModuleNames or resolveTypeReferenceDirectives, used to determine if unchanged file path needs to re-resolve modules/type reference directives */
hasInvalidatedResolutions?(filePath: Path): boolean;
@@ -8007,12 +8001,6 @@ export interface CompilerHost extends ModuleResolutionHost {
*/
export type SourceOfProjectReferenceRedirect = string | true;
/** @internal */
export interface ResolvedProjectReferenceCallbacks {
getSourceOfProjectReferenceRedirect(fileName: string): SourceOfProjectReferenceRedirect | undefined;
forEachResolvedProjectReference<T>(cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined): T | undefined;
}
/** @internal */
export const enum TransformFlags {
None = 0,
@@ -8230,9 +8218,6 @@ export interface UnscopedEmitHelper extends EmitHelperBase {
export type EmitHelper = ScopedEmitHelper | UnscopedEmitHelper;
/** @internal */
export type UniqueNameHandler = (baseName: string, checkFn?: (name: string) => boolean, optimistic?: boolean) => string;
export type EmitHelperUniqueNameCallback = (name: string) => string;
/**
@@ -9846,6 +9831,12 @@ export interface DiagnosticCollection {
// SyntaxKind.SyntaxList
export interface SyntaxList extends Node {
kind: SyntaxKind.SyntaxList;
// Unlike other nodes which may or may not have their child nodes calculated,
// the entire purpose of a SyntaxList is to hold child nodes.
// Instead of using the WeakMap machinery in `nodeChildren.ts`,
// we just store the children directly on the SyntaxList.
/** @internal */ _children: readonly Node[];
}
// dprint-ignore
+99 -200
View File
@@ -11,7 +11,7 @@ import {
AmpersandAmpersandEqualsToken,
AnyImportOrBareOrAccessedRequire,
AnyImportOrReExport,
AnyImportOrRequireStatement,
type AnyImportOrRequireStatement,
AnyImportSyntax,
AnyValidImportOrReExport,
append,
@@ -150,7 +150,6 @@ import {
flatMapToMutable,
flatten,
forEach,
forEachAncestorDirectory,
forEachChild,
forEachChildRecursively,
ForInOrOfStatement,
@@ -524,7 +523,6 @@ import {
StringLiteralType,
stringToToken,
SuperCall,
SuperExpression,
SuperProperty,
SwitchStatement,
Symbol,
@@ -690,8 +688,7 @@ export function changesAffectModuleResolution(oldOptions: CompilerOptions, newOp
optionsHaveModuleResolutionChanges(oldOptions, newOptions);
}
/** @internal */
export function optionsHaveModuleResolutionChanges(oldOptions: CompilerOptions, newOptions: CompilerOptions) {
function optionsHaveModuleResolutionChanges(oldOptions: CompilerOptions, newOptions: CompilerOptions) {
return optionsHaveChanges(oldOptions, newOptions, moduleResolutionOptionDeclarations);
}
@@ -799,6 +796,16 @@ export function moduleResolutionIsEqualTo(oldResolution: ResolvedModuleWithFaile
oldResolution.alternateResult === newResolution.alternateResult;
}
/** @internal */
export function getResolvedModuleFromResolution(resolution: ResolvedModuleWithFailedLookupLocations) {
return resolution.resolvedModule;
}
/** @internal */
export function getResolvedTypeReferenceDirectiveFromResolution(resolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations) {
return resolution.resolvedTypeReferenceDirective;
}
/** @internal */
export function createModuleNotFoundChain(sourceFile: SourceFile, host: TypeCheckerHost, moduleReference: string, mode: ResolutionMode, packageName: string) {
const alternateResult = host.getResolvedModule(sourceFile, moduleReference, mode)?.alternateResult;
@@ -955,7 +962,7 @@ export function getStartPositionOfLine(line: number, sourceFile: SourceFileLike)
}
// This is a useful function for debugging purposes.
/** @internal */
/** @internal @knipignore */
export function nodePosToString(node: Node): string {
const file = getSourceFileOfNode(node);
const loc = getLineAndCharacterOfPosition(file, node.pos);
@@ -1098,6 +1105,7 @@ export function insertStatementsAfterCustomPrologue<T extends Statement>(to: T[]
* Prepends statements to an array while taking care of prologue directives.
*
* @internal
* @knipignore
*/
export function insertStatementAfterStandardPrologue<T extends Statement>(to: T[], statement: T | undefined): T[] {
return insertStatementAfterPrologue(to, statement, isPrologueDirective);
@@ -1180,7 +1188,7 @@ export function getTokenPosOfNode(node: Node, sourceFile?: SourceFileLike, inclu
if (isJSDocNode(node) || node.kind === SyntaxKind.JsxText) {
// JsxText cannot actually contain comments, even though the scanner will think it sees comments
return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos, /*stopAfterLineBreak*/ false, /*stopAtComments*/ true);
return skipTrivia((sourceFile ?? getSourceFileOfNode(node)).text, node.pos, /*stopAfterLineBreak*/ false, /*stopAtComments*/ true);
}
if (includeJsDoc && hasJSDocNodes(node)) {
@@ -1192,14 +1200,15 @@ export function getTokenPosOfNode(node: Node, sourceFile?: SourceFileLike, inclu
// trivia for the list, we may have skipped the JSDocComment as well. So we should process its
// first child to determine the actual position of its first token.
if (node.kind === SyntaxKind.SyntaxList) {
const first = firstOrUndefined(getNodeChildren(node));
sourceFile ??= getSourceFileOfNode(node);
const first = firstOrUndefined(getNodeChildren(node, sourceFile));
if (first) {
return getTokenPosOfNode(first, sourceFile, includeJsDoc);
}
}
return skipTrivia(
(sourceFile || getSourceFileOfNode(node)).text,
(sourceFile ?? getSourceFileOfNode(node)).text,
node.pos,
/*stopAfterLineBreak*/ false,
/*stopAtComments*/ false,
@@ -1337,6 +1346,10 @@ export const getScriptTargetFeatures = /* @__PURE__ */ memoize((): ScriptTargetF
es2023: [
"findLastIndex",
"findLast",
"toReversed",
"toSorted",
"toSpliced",
"with",
],
})),
Iterator: new Map(Object.entries({
@@ -1614,6 +1627,10 @@ export const getScriptTargetFeatures = /* @__PURE__ */ memoize((): ScriptTargetF
es2023: [
"findLastIndex",
"findLast",
"toReversed",
"toSorted",
"toSpliced",
"with",
],
})),
Uint8Array: new Map(Object.entries({
@@ -1623,6 +1640,10 @@ export const getScriptTargetFeatures = /* @__PURE__ */ memoize((): ScriptTargetF
es2023: [
"findLastIndex",
"findLast",
"toReversed",
"toSorted",
"toSpliced",
"with",
],
})),
Uint8ClampedArray: new Map(Object.entries({
@@ -1632,6 +1653,10 @@ export const getScriptTargetFeatures = /* @__PURE__ */ memoize((): ScriptTargetF
es2023: [
"findLastIndex",
"findLast",
"toReversed",
"toSorted",
"toSpliced",
"with",
],
})),
Int16Array: new Map(Object.entries({
@@ -1641,6 +1666,10 @@ export const getScriptTargetFeatures = /* @__PURE__ */ memoize((): ScriptTargetF
es2023: [
"findLastIndex",
"findLast",
"toReversed",
"toSorted",
"toSpliced",
"with",
],
})),
Uint16Array: new Map(Object.entries({
@@ -1650,6 +1679,10 @@ export const getScriptTargetFeatures = /* @__PURE__ */ memoize((): ScriptTargetF
es2023: [
"findLastIndex",
"findLast",
"toReversed",
"toSorted",
"toSpliced",
"with",
],
})),
Int32Array: new Map(Object.entries({
@@ -1659,6 +1692,10 @@ export const getScriptTargetFeatures = /* @__PURE__ */ memoize((): ScriptTargetF
es2023: [
"findLastIndex",
"findLast",
"toReversed",
"toSorted",
"toSpliced",
"with",
],
})),
Uint32Array: new Map(Object.entries({
@@ -1668,6 +1705,10 @@ export const getScriptTargetFeatures = /* @__PURE__ */ memoize((): ScriptTargetF
es2023: [
"findLastIndex",
"findLast",
"toReversed",
"toSorted",
"toSpliced",
"with",
],
})),
Float32Array: new Map(Object.entries({
@@ -1677,6 +1718,10 @@ export const getScriptTargetFeatures = /* @__PURE__ */ memoize((): ScriptTargetF
es2023: [
"findLastIndex",
"findLast",
"toReversed",
"toSorted",
"toSpliced",
"with",
],
})),
Float64Array: new Map(Object.entries({
@@ -1686,6 +1731,10 @@ export const getScriptTargetFeatures = /* @__PURE__ */ memoize((): ScriptTargetF
es2023: [
"findLastIndex",
"findLast",
"toReversed",
"toSorted",
"toSpliced",
"with",
],
})),
BigInt64Array: new Map(Object.entries({
@@ -1696,6 +1745,10 @@ export const getScriptTargetFeatures = /* @__PURE__ */ memoize((): ScriptTargetF
es2023: [
"findLastIndex",
"findLast",
"toReversed",
"toSorted",
"toSpliced",
"with",
],
})),
BigUint64Array: new Map(Object.entries({
@@ -1706,6 +1759,10 @@ export const getScriptTargetFeatures = /* @__PURE__ */ memoize((): ScriptTargetF
es2023: [
"findLastIndex",
"findLast",
"toReversed",
"toSorted",
"toSpliced",
"with",
],
})),
Error: new Map(Object.entries({
@@ -1843,10 +1900,8 @@ export function isNonGlobalAmbientModule(node: Node): node is ModuleDeclaration
* 1. An actual declaration: namespace X { ... }
* 2. A Javascript declaration, which is:
* An identifier in a nested property access expression: Y in `X.Y.Z = { ... }`
*
* @internal
*/
export function isEffectiveModuleDeclaration(node: Node) {
function isEffectiveModuleDeclaration(node: Node) {
return isModuleDeclaration(node) || isIdentifier(node);
}
@@ -2522,12 +2577,10 @@ export function getJSDocCommentRanges(node: Node, text: string) {
text.charCodeAt(comment.pos + 3) !== CharacterCodes.slash);
}
/** @internal */
export const fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*<reference\s+path\s*=\s*)(('[^']*')|("[^"]*")).*?\/>/;
const fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*<reference\s+path\s*=\s*)(('[^']*')|("[^"]*")).*?\/>/;
const fullTripleSlashReferenceTypeReferenceDirectiveRegEx = /^(\/\/\/\s*<reference\s+types\s*=\s*)(('[^']*')|("[^"]*")).*?\/>/;
const fullTripleSlashLibReferenceRegEx = /^(\/\/\/\s*<reference\s+lib\s*=\s*)(('[^']*')|("[^"]*")).*?\/>/;
/** @internal */
export const fullTripleSlashAMDReferencePathRegEx = /^(\/\/\/\s*<amd-dependency\s+path\s*=\s*)(('[^']*')|("[^"]*")).*?\/>/;
const fullTripleSlashAMDReferencePathRegEx = /^(\/\/\/\s*<amd-dependency\s+path\s*=\s*)(('[^']*')|("[^"]*")).*?\/>/;
const fullTripleSlashAMDModuleRegEx = /^\/\/\/\s*<amd-module\s+.*?\/>/;
const defaultLibReferenceRegEx = /^(\/\/\/\s*<reference\s+no-default-lib\s*=\s*)(('[^']*')|("[^"]*"))\s*\/>/;
@@ -2633,17 +2686,6 @@ function isPartOfTypeExpressionWithTypeArguments(node: Node) {
|| isHeritageClause(node.parent) && !isExpressionWithTypeArgumentsInClassExtendsClause(node);
}
/** @internal */
export function isChildOfNodeWithKind(node: Node, kind: SyntaxKind): boolean {
while (node) {
if (node.kind === kind) {
return true;
}
node = node.parent;
}
return false;
}
// Warning: This has the same semantics as the forEach family of functions,
// in that traversal terminates in the event that 'visitor' supplies a truthy value.
/** @internal */
@@ -3160,12 +3202,6 @@ export function getImmediatelyInvokedFunctionExpression(func: Node): CallExpress
}
}
/** @internal */
export function isSuperOrSuperProperty(node: Node): node is SuperExpression | SuperProperty {
return node.kind === SyntaxKind.SuperKeyword
|| isSuperProperty(node);
}
/**
* Determines whether a node is a property or element access expression for `super`.
*
@@ -3567,11 +3603,6 @@ export function isSourceFileJS(file: SourceFile): boolean {
return isInJSFile(file);
}
/** @internal */
export function isSourceFileNotJS(file: SourceFile): boolean {
return !isInJSFile(file);
}
/** @internal */
export function isInJSFile(node: Node | undefined): boolean {
return !!node && !!(node.flags & NodeFlags.JavaScriptFile);
@@ -3886,19 +3917,15 @@ export function isBindableObjectDefinePropertyCall(expr: CallExpression): expr i
/**
* x.y OR x[0]
*
* @internal
*/
export function isLiteralLikeAccess(node: Node): node is LiteralLikeElementAccessExpression | PropertyAccessExpression {
function isLiteralLikeAccess(node: Node): node is LiteralLikeElementAccessExpression | PropertyAccessExpression {
return isPropertyAccessExpression(node) || isLiteralLikeElementAccess(node);
}
/**
* x[0] OR x['a'] OR x[Symbol.y]
*
* @internal
*/
export function isLiteralLikeElementAccess(node: Node): node is LiteralLikeElementAccessExpression {
function isLiteralLikeElementAccess(node: Node): node is LiteralLikeElementAccessExpression {
return isElementAccessExpression(node) && isStringOrNumericLiteralLike(node.argumentExpression);
}
@@ -4245,8 +4272,7 @@ function getSourceOfDefaultedAssignment(node: Node): Node | undefined {
: undefined;
}
/** @internal */
export function getSingleInitializerOfVariableStatementOrPropertyDeclaration(node: Node): Expression | undefined {
function getSingleInitializerOfVariableStatementOrPropertyDeclaration(node: Node): Expression | undefined {
switch (node.kind) {
case SyntaxKind.VariableStatement:
const v = getSingleVariableOfVariableStatement(node);
@@ -4573,7 +4599,7 @@ export function getTypeParameterFromJsDoc(node: TypeParameterDeclaration & { par
return typeParameters && find(typeParameters, p => p.name.escapedText === name);
}
/** @internal */
/** @internal @knipignore */
export function hasTypeArguments(node: Node): node is HasTypeArguments {
return !!(node as HasTypeArguments).typeArguments;
}
@@ -4889,46 +4915,6 @@ export function isIdentifierName(node: Identifier): boolean {
return false;
}
// An alias symbol is created by one of the following declarations:
// import <symbol> = ...
// import <symbol> from ...
// import * as <symbol> from ...
// import { x as <symbol> } from ...
// export { x as <symbol> } from ...
// export * as ns <symbol> from ...
// export = <EntityNameExpression>
// export default <EntityNameExpression>
// module.exports = <EntityNameExpression>
// module.exports.x = <EntityNameExpression>
// const x = require("...")
// const { x } = require("...")
// const x = require("...").y
// const { x } = require("...").y
/** @internal */
export function isAliasSymbolDeclaration(node: Node): boolean {
if (
node.kind === SyntaxKind.ImportEqualsDeclaration ||
node.kind === SyntaxKind.NamespaceExportDeclaration ||
node.kind === SyntaxKind.ImportClause && !!(node as ImportClause).name ||
node.kind === SyntaxKind.NamespaceImport ||
node.kind === SyntaxKind.NamespaceExport ||
node.kind === SyntaxKind.ImportSpecifier ||
node.kind === SyntaxKind.ExportSpecifier ||
node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node as ExportAssignment)
) {
return true;
}
return isInJSFile(node) && (
isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports && exportAssignmentIsAlias(node) ||
isPropertyAccessExpression(node)
&& isBinaryExpression(node.parent)
&& node.parent.left === node
&& node.parent.operatorToken.kind === SyntaxKind.EqualsToken
&& isAliasableExpression(node.parent.right)
);
}
/** @internal */
export function getAliasDeclarationFromName(node: EntityName): Declaration | undefined {
switch (node.parent.kind) {
@@ -5067,23 +5053,12 @@ export function isNonContextualKeyword(token: SyntaxKind): boolean {
return isKeyword(token) && !isContextualKeyword(token);
}
/** @internal */
export function isFutureReservedKeyword(token: SyntaxKind): boolean {
return SyntaxKind.FirstFutureReservedWord <= token && token <= SyntaxKind.LastFutureReservedWord;
}
/** @internal */
export function isStringANonContextualKeyword(name: string) {
const token = stringToToken(name);
return token !== undefined && isNonContextualKeyword(token);
}
/** @internal */
export function isStringAKeyword(name: string) {
const token = stringToToken(name);
return token !== undefined && isKeyword(token);
}
/** @internal */
export function isIdentifierANonContextualKeyword(node: Identifier): boolean {
const originalKeywordKind = identifierToKeywordKind(node);
@@ -5235,11 +5210,6 @@ export function getEscapedTextOfIdentifierOrLiteral(node: PropertyNameLiteral):
return isMemberName(node) ? node.escapedText : isJsxNamespacedName(node) ? getEscapedTextOfJsxNamespacedName(node) : escapeLeadingUnderscores(node.text);
}
/** @internal */
export function getPropertyNameForUniqueESSymbol(symbol: Symbol): __String {
return `__@${getSymbolId(symbol)}@${symbol.escapedName}` as __String;
}
/** @internal */
export function getSymbolNameForPrivateIdentifier(containingClassSymbol: Symbol, description: __String): __String {
return `__#${getSymbolId(containingClassSymbol)}@${description}` as __String;
@@ -5255,24 +5225,13 @@ export function isPrivateIdentifierSymbol(symbol: Symbol): boolean {
return startsWith(symbol.escapedName as string, "__#");
}
/**
* Includes the word "Symbol" with unicode escapes
*
* @internal
*/
export function isESSymbolIdentifier(node: Node): boolean {
return node.kind === SyntaxKind.Identifier && (node as Identifier).escapedText === "Symbol";
}
/**
* Indicates whether a property name is the special `__proto__` property.
* Per the ECMA-262 spec, this only matters for property assignments whose name is
* the Identifier `__proto__`, or the string literal `"__proto__"`, but not for
* computed property names.
*
* @internal
*/
export function isProtoSetter(node: PropertyName) {
function isProtoSetter(node: PropertyName) {
return isIdentifier(node) ? idText(node) === "__proto__" :
isStringLiteral(node) && node.text === "__proto__";
}
@@ -5287,9 +5246,8 @@ export type AnonymousFunctionDefinition =
* Indicates whether an expression is an anonymous function definition.
*
* @see https://tc39.es/ecma262/#sec-isanonymousfunctiondefinition
* @internal
*/
export function isAnonymousFunctionDefinition(node: Expression, cb?: (node: AnonymousFunctionDefinition) => boolean): node is WrappedExpression<AnonymousFunctionDefinition> {
function isAnonymousFunctionDefinition(node: Expression, cb?: (node: AnonymousFunctionDefinition) => boolean): node is WrappedExpression<AnonymousFunctionDefinition> {
node = skipOuterExpressions(node);
switch (node.kind) {
case SyntaxKind.ClassExpression:
@@ -5434,11 +5392,6 @@ export function nodeIsSynthesized(range: TextRange): boolean {
|| positionIsSynthesized(range.end);
}
/** @internal */
export function getOriginalSourceFile(sourceFile: SourceFile) {
return getParseTreeNode(sourceFile, isSourceFile) || sourceFile;
}
/** @internal */
export const enum Associativity {
Left,
@@ -5499,8 +5452,7 @@ export function getExpressionPrecedence(expression: Expression) {
return getOperatorPrecedence(expression.kind, operator, hasArguments);
}
/** @internal */
export function getOperator(expression: Expression): SyntaxKind {
function getOperator(expression: Expression): SyntaxKind {
if (expression.kind === SyntaxKind.BinaryExpression) {
return (expression as BinaryExpression).operatorToken.kind;
}
@@ -6103,8 +6055,7 @@ export function getIndentString(level: number) {
return indentStrings[level];
}
/** @internal */
export function getIndentSize() {
function getIndentSize() {
return indentStrings[1].length;
}
@@ -6366,15 +6317,15 @@ export function getOwnEmitOutputFilePath(fileName: string, host: EmitHost, exten
/** @internal */
export function getDeclarationEmitOutputFilePath(fileName: string, host: EmitHost) {
return getDeclarationEmitOutputFilePathWorker(fileName, host.getCompilerOptions(), host.getCurrentDirectory(), host.getCommonSourceDirectory(), f => host.getCanonicalFileName(f));
return getDeclarationEmitOutputFilePathWorker(fileName, host.getCompilerOptions(), host);
}
/** @internal */
export function getDeclarationEmitOutputFilePathWorker(fileName: string, options: CompilerOptions, currentDirectory: string, commonSourceDirectory: string, getCanonicalFileName: GetCanonicalFileName): string {
export function getDeclarationEmitOutputFilePathWorker(fileName: string, options: CompilerOptions, host: Pick<EmitHost, "getCommonSourceDirectory" | "getCurrentDirectory" | "getCanonicalFileName">): string {
const outputDir = options.declarationDir || options.outDir; // Prefer declaration folder if specified
const path = outputDir
? getSourceFilePathInNewDirWorker(fileName, outputDir, currentDirectory, commonSourceDirectory, getCanonicalFileName)
? getSourceFilePathInNewDirWorker(fileName, outputDir, host.getCurrentDirectory(), host.getCommonSourceDirectory(), f => host.getCanonicalFileName(f))
: fileName;
const declarationExtension = getDeclarationEmitExtensionForPath(path);
return removeFileExtension(path) + declarationExtension;
@@ -6491,8 +6442,7 @@ export function getSourceFilePathInNewDir(fileName: string, host: EmitHost, newD
return getSourceFilePathInNewDirWorker(fileName, newDirPath, host.getCurrentDirectory(), host.getCommonSourceDirectory(), f => host.getCanonicalFileName(f));
}
/** @internal */
export function getSourceFilePathInNewDirWorker(fileName: string, newDirPath: string, currentDirectory: string, commonSourceDirectory: string, getCanonicalFileName: GetCanonicalFileName): string {
function getSourceFilePathInNewDirWorker(fileName: string, newDirPath: string, currentDirectory: string, commonSourceDirectory: string, getCanonicalFileName: GetCanonicalFileName): string {
let sourceFilePath = getNormalizedAbsolutePath(fileName, currentDirectory);
const isSourceFileInCommonSourceDirectory = getCanonicalFileName(sourceFilePath).indexOf(getCanonicalFileName(commonSourceDirectory)) === 0;
sourceFilePath = isSourceFileInCommonSourceDirectory ? sourceFilePath.substring(commonSourceDirectory.length) : sourceFilePath;
@@ -6551,8 +6501,7 @@ export function getLineOfLocalPosition(sourceFile: SourceFile, pos: number) {
return computeLineOfPosition(lineStarts, pos);
}
/** @internal */
export function getLineOfLocalPositionFromLineMap(lineMap: readonly number[], pos: number) {
function getLineOfLocalPositionFromLineMap(lineMap: readonly number[], pos: number) {
return computeLineOfPosition(lineMap, pos);
}
@@ -6736,13 +6685,11 @@ export function getEffectiveSetAccessorTypeAnnotationNode(node: SetAccessorDecla
return parameter && getEffectiveTypeAnnotationNode(parameter);
}
/** @internal */
export function emitNewLineBeforeLeadingComments(lineMap: readonly number[], writer: EmitTextWriter, node: TextRange, leadingComments: readonly CommentRange[] | undefined) {
function emitNewLineBeforeLeadingComments(lineMap: readonly number[], writer: EmitTextWriter, node: TextRange, leadingComments: readonly CommentRange[] | undefined) {
emitNewLineBeforeLeadingCommentsOfPosition(lineMap, writer, node.pos, leadingComments);
}
/** @internal */
export function emitNewLineBeforeLeadingCommentsOfPosition(lineMap: readonly number[], writer: EmitTextWriter, pos: number, leadingComments: readonly CommentRange[] | undefined) {
function emitNewLineBeforeLeadingCommentsOfPosition(lineMap: readonly number[], writer: EmitTextWriter, pos: number, leadingComments: readonly CommentRange[] | undefined) {
// If the leading comments start on different line than the start of node, write new line
if (
leadingComments && leadingComments.length && pos !== leadingComments[0].pos &&
@@ -6763,8 +6710,7 @@ export function emitNewLineBeforeLeadingCommentOfPosition(lineMap: readonly numb
}
}
/** @internal */
export function emitComments(
function emitComments(
text: string,
lineMap: readonly number[],
writer: EmitTextWriter,
@@ -7032,7 +6978,7 @@ export function getSelectedEffectiveModifierFlags(node: Node, flags: ModifierFla
return getEffectiveModifierFlags(node) & flags;
}
/** @internal */
/** @internal @knipignore */
export function getSelectedSyntacticModifierFlags(node: Node, flags: ModifierFlags): ModifierFlags {
return getSyntacticModifierFlags(node) & flags;
}
@@ -7132,6 +7078,7 @@ export function getEffectiveModifierFlagsNoCache(node: Node): ModifierFlags {
* NOTE: This function does not use `parent` pointers and will not include modifiers from JSDoc.
*
* @internal
* @knipignore
*/
export function getSyntacticModifierFlagsNoCache(node: Node): ModifierFlags {
let flags = canHaveModifiers(node) ? modifiersToFlags(node.modifiers) : ModifierFlags.None;
@@ -7273,10 +7220,6 @@ export function isAssignmentExpression(node: Node, excludeCompoundAssignment?: b
&& isLeftHandSideExpression(node.left);
}
/** @internal */
export function isLeftHandSideOfAssignment(node: Node) {
return isAssignmentExpression(node.parent) && node.parent.left === node;
}
/** @internal */
export function isDestructuringAssignment(node: Node): node is DestructuringAssignment {
if (isAssignmentExpression(node, /*excludeCompoundAssignment*/ true)) {
@@ -7687,17 +7630,6 @@ export function moveRangePastModifiers(node: Node): TextRange {
: moveRangePastDecorators(node);
}
/**
* Determines whether a TextRange has the same start and end positions.
*
* @param range A TextRange.
*
* @internal
*/
export function isCollapsedRange(range: TextRange) {
return range.pos === range.end;
}
/**
* Creates a new TextRange for a token at the provides start position.
*
@@ -7729,7 +7661,7 @@ export function rangeEndPositionsAreOnSameLine(range1: TextRange, range2: TextRa
return positionsAreOnSameLine(range1.end, range2.end, sourceFile);
}
/** @internal */
/** @internal @knipignore */
export function rangeStartIsOnSameLineAsRangeEnd(range1: TextRange, range2: TextRange, sourceFile: SourceFile) {
return positionsAreOnSameLine(getStartPositionOfRange(range1, sourceFile, /*includeComments*/ false), range2.end, sourceFile);
}
@@ -7745,7 +7677,7 @@ export function getLinesBetweenRangeEndAndRangeStart(range1: TextRange, range2:
return getLinesBetweenPositions(sourceFile, range1.end, range2Start);
}
/** @internal */
/** @internal @knipignore */
export function getLinesBetweenRangeEndPositions(range1: TextRange, range2: TextRange, sourceFile: SourceFile) {
return getLinesBetweenPositions(sourceFile, range1.end, range2.end);
}
@@ -7760,7 +7692,7 @@ export function positionsAreOnSameLine(pos1: number, pos2: number, sourceFile: S
return getLinesBetweenPositions(sourceFile, pos1, pos2) === 0;
}
/** @internal */
/** @internal @knipignore */
export function getStartPositionOfRange(range: TextRange, sourceFile: SourceFile, includeComments: boolean) {
return positionIsSynthesized(range.pos) ? -1 : skipTrivia(sourceFile.text, range.pos, /*stopAfterLineBreak*/ false, includeComments);
}
@@ -8067,11 +7999,6 @@ export function getObjectFlags(type: Type): ObjectFlags {
return type.flags & TypeFlags.ObjectFlagsType ? (type as ObjectFlagsType).objectFlags : 0;
}
/** @internal */
export function forSomeAncestorDirectory(directory: string, callback: (directory: string) => boolean): boolean {
return !!forEachAncestorDirectory(directory, d => callback(d) ? true : undefined);
}
/** @internal */
export function isUMDExportSymbol(symbol: Symbol | undefined): boolean {
return !!symbol && !!symbol.declarations && !!symbol.declarations[0] && isNamespaceExportDeclaration(symbol.declarations[0]);
@@ -8361,6 +8288,7 @@ const objectAllocatorPatchers: ((objectAllocator: ObjectAllocator) => void)[] =
/**
* Used by `deprecatedCompat` to patch the object allocator to apply deprecations.
* @internal
* @knipignore
*/
export function addObjectAllocatorPatcher(fn: (objectAllocator: ObjectAllocator) => void) {
objectAllocatorPatchers.push(fn);
@@ -8578,8 +8506,7 @@ export function compareDiagnostics(d1: Diagnostic, d2: Diagnostic): Comparison {
Comparison.EqualTo;
}
/** @internal */
export function compareDiagnosticsSkipRelatedInformation(d1: Diagnostic, d2: Diagnostic): Comparison {
function compareDiagnosticsSkipRelatedInformation(d1: Diagnostic, d2: Diagnostic): Comparison {
const code1 = getDiagnosticCode(d1);
const code2 = getDiagnosticCode(d2);
return compareStringsCaseSensitive(getDiagnosticFilePath(d1), getDiagnosticFilePath(d2)) ||
@@ -9040,7 +8967,7 @@ export const getEmitScriptTarget = computedOptions.target.computeValue;
export const getEmitModuleKind = computedOptions.module.computeValue;
/** @internal */
export const getEmitModuleResolutionKind = computedOptions.moduleResolution.computeValue;
/** @internal */
/** @internal @knipignore */
export const getEmitModuleDetectionKind = computedOptions.moduleDetection.computeValue;
/** @internal */
export const getIsolatedModules = computedOptions.isolatedModules.computeValue;
@@ -9343,8 +9270,7 @@ function escapeRegExpCharacter(match: string) {
const wildcardCharCodes = [CharacterCodes.asterisk, CharacterCodes.question];
/** @internal */
export const commonPackageFolders: readonly string[] = ["node_modules", "bower_components", "jspm_packages"];
const commonPackageFolders: readonly string[] = ["node_modules", "bower_components", "jspm_packages"];
const implicitExcludePathRegexPattern = `(?!(${commonPackageFolders.join("|")})(/|$))`;
@@ -9706,17 +9632,14 @@ export function getScriptKindFromFileName(fileName: string): ScriptKind {
/**
* Groups of supported extensions in order of file resolution precedence. (eg, TS > TSX > DTS and seperately, CTS > DCTS)
*
* @internal
*/
export const supportedTSExtensions: readonly Extension[][] = [[Extension.Ts, Extension.Tsx, Extension.Dts], [Extension.Cts, Extension.Dcts], [Extension.Mts, Extension.Dmts]];
const supportedTSExtensions: readonly Extension[][] = [[Extension.Ts, Extension.Tsx, Extension.Dts], [Extension.Cts, Extension.Dcts], [Extension.Mts, Extension.Dmts]];
/** @internal */
export const supportedTSExtensionsFlat: readonly Extension[] = flatten(supportedTSExtensions);
const supportedTSExtensionsWithJson: readonly Extension[][] = [...supportedTSExtensions, [Extension.Json]];
/** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */
const supportedTSExtensionsForExtractExtension: readonly Extension[] = [Extension.Dts, Extension.Dcts, Extension.Dmts, Extension.Cts, Extension.Mts, Extension.Ts, Extension.Tsx];
/** @internal */
export const supportedJSExtensions: readonly Extension[][] = [[Extension.Js, Extension.Jsx], [Extension.Mjs], [Extension.Cjs]];
const supportedJSExtensions: readonly Extension[][] = [[Extension.Js, Extension.Jsx], [Extension.Mjs], [Extension.Cjs]];
/** @internal */
export const supportedJSExtensionsFlat: readonly Extension[] = flatten(supportedJSExtensions);
const allSupportedExtensions: readonly Extension[][] = [[Extension.Ts, Extension.Tsx, Extension.Dts, Extension.Js, Extension.Jsx], [Extension.Cts, Extension.Dcts, Extension.Cjs], [Extension.Mts, Extension.Dmts, Extension.Mjs]];
@@ -9787,8 +9710,7 @@ export const enum ModuleSpecifierEnding {
TsExtension,
}
/** @internal */
export function usesExtensionsOnImports({ imports }: SourceFile, hasExtension: (text: string) => boolean = or(hasJSFileExtension, hasTSFileExtension)): boolean {
function usesExtensionsOnImports({ imports }: SourceFile, hasExtension: (text: string) => boolean = or(hasJSFileExtension, hasTSFileExtension)): boolean {
return firstDefined(imports, ({ text }) =>
pathIsRelative(text) && !fileExtensionIsOneOf(text, extensionsNotSupportingExtensionlessResolution)
? hasExtension(text)
@@ -9917,7 +9839,7 @@ export function removeFileExtension(path: string): string {
return path;
}
/** @internal */
/** @internal @knipignore */
export function tryRemoveExtension(path: string, extension: string): string | undefined {
return fileExtensionIs(path, extension) ? removeExtension(path, extension) : undefined;
}
@@ -10402,24 +10324,6 @@ export function setParent<T extends Node>(child: T | undefined, parent: T["paren
return child;
}
/**
* Bypasses immutability and directly sets the `parent` property of each `Node` in an array of nodes, if is not already set.
*
* @internal
*/
export function setEachParent<T extends readonly Node[]>(children: T, parent: T[number]["parent"]): T;
/** @internal */
export function setEachParent<T extends readonly Node[]>(children: T | undefined, parent: T[number]["parent"]): T | undefined;
/** @internal */
export function setEachParent<T extends readonly Node[]>(children: T | undefined, parent: T[number]["parent"]): T | undefined {
if (children) {
for (const child of children) {
setParent(child, parent);
}
}
return children;
}
/**
* Bypasses immutability and directly sets the `parent` property of each `Node` recursively.
* @param rootNode The root node from which to start the recursion.
@@ -10734,11 +10638,6 @@ export function getNodeModulePathParts(fullPath: string): NodeModulePathParts |
return state > States.NodeModules ? { topLevelNodeModulesIndex, topLevelPackageNameIndex, packageRootIndex, fileNameIndex } : undefined;
}
/** @internal */
export function getParameterTypeNode(parameter: ParameterDeclaration | JSDocParameterTag) {
return parameter.kind === SyntaxKind.JSDocParameterTag ? parameter.typeExpression?.type : parameter.type;
}
/** @internal */
export function isTypeDeclaration(node: Node): node is TypeParameterDeclaration | ClassDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag | EnumDeclaration | ImportClause | ImportSpecifier | ExportSpecifier {
switch (node.kind) {
@@ -10900,7 +10799,7 @@ export function isExpandoPropertyDeclaration(declaration: Declaration | undefine
}
/** @internal */
export function hasResolutionModeOverride(node: ImportTypeNode | ImportDeclaration | ExportDeclaration | undefined) {
export function hasResolutionModeOverride(node: ImportTypeNode | ImportDeclaration | ExportDeclaration | JSDocImportTag | undefined) {
if (node === undefined) {
return false;
}
+3 -37
View File
@@ -160,10 +160,8 @@ import {
isKeyword,
isModuleBlock,
isNonNullExpression,
isNotEmittedStatement,
isOmittedExpression,
isParameter,
isPartiallyEmittedExpression,
isPrivateIdentifier,
isPropertyAccessExpression,
isPropertyAssignment,
@@ -241,7 +239,6 @@ import {
NodeFlags,
NonNullChain,
normalizePath,
NotEmittedStatement,
NullLiteral,
ObjectBindingOrAssignmentElement,
ObjectBindingOrAssignmentPattern,
@@ -251,7 +248,6 @@ import {
OptionalChainRoot,
OuterExpressionKinds,
ParameterDeclaration,
PartiallyEmittedExpression,
pathIsRelative,
PostfixUnaryExpression,
PrefixUnaryExpression,
@@ -260,7 +256,6 @@ import {
PrivateIdentifierPropertyAccessExpression,
PropertyAccessChain,
PropertyAccessExpression,
PropertyDeclaration,
PropertyName,
QualifiedName,
ScriptTarget,
@@ -1277,11 +1272,6 @@ export function getJSDocTags(node: Node): readonly JSDocTag[] {
return getJSDocTagsWorker(node, /*noCache*/ false);
}
/** @internal */
export function getJSDocTagsNoCache(node: Node): readonly JSDocTag[] {
return getJSDocTagsWorker(node, /*noCache*/ true);
}
/** Get the first JSDoc tag of a specified kind, or undefined if not present. */
function getFirstJSDocTag<T extends JSDocTag>(node: Node, predicate: (tag: JSDocTag) => tag is T, noCache?: boolean): T | undefined {
return find(getJSDocTagsWorker(node, noCache), predicate);
@@ -1464,10 +1454,6 @@ export function isJSDocPropertyLikeTag(node: Node): node is JSDocPropertyLikeTag
//
// All node tests in the following list should *not* reference parent pointers so that
// they may be used with transformations.
/** @internal */
export function isNode(node: Node) {
return isNodeKind(node.kind);
}
/** @internal */
export function isNodeKind(kind: SyntaxKind) {
@@ -1780,19 +1766,6 @@ export function isMethodOrAccessor(node: Node): node is MethodDeclaration | Acce
}
}
/** @internal */
export function isNamedClassElement(node: Node): node is MethodDeclaration | AccessorDeclaration | PropertyDeclaration {
switch (node.kind) {
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.PropertyDeclaration:
return true;
default:
return false;
}
}
// Type members
export function isModifierLike(node: Node): node is ModifierLike {
@@ -2127,12 +2100,6 @@ export function isAssertionExpression(node: Node): node is AssertionExpression {
|| kind === SyntaxKind.AsExpression;
}
/** @internal */
export function isNotEmittedOrPartiallyEmittedNode(node: Node): node is NotEmittedStatement | PartiallyEmittedExpression {
return isNotEmittedStatement(node)
|| isPartiallyEmittedExpression(node);
}
// Statement
export function isIterationStatement(node: Node, lookInLabeledStatements: false): node is IterationStatement;
@@ -2152,8 +2119,7 @@ export function isIterationStatement(node: Node, lookInLabeledStatements: boolea
return false;
}
/** @internal */
export function isScopeMarker(node: Node) {
function isScopeMarker(node: Node) {
return isExportAssignment(node) || isExportDeclaration(node);
}
@@ -2202,14 +2168,14 @@ export function isModuleBody(node: Node): node is ModuleBody {
|| kind === SyntaxKind.Identifier;
}
/** @internal */
/** @internal @knipignore */
export function isNamespaceBody(node: Node): node is NamespaceBody {
const kind = node.kind;
return kind === SyntaxKind.ModuleBlock
|| kind === SyntaxKind.ModuleDeclaration;
}
/** @internal */
/** @internal @knipignore */
export function isJSDocNamespaceBody(node: Node): node is JSDocNamespaceBody {
const kind = node.kind;
return kind === SyntaxKind.Identifier
+17 -8
View File
@@ -55,6 +55,7 @@ import {
generateDjb2Hash,
getDefaultLibFileName,
getDirectoryPath,
getEmitDeclarations,
getEmitScriptTarget,
getLineAndCharacterOfPosition,
getNameOfScriptTarget,
@@ -155,8 +156,7 @@ function clearScreenIfNotWatchingForFileChanges(system: System, diagnostic: Diag
return false;
}
/** @internal */
export const screenStartingMessageCodes: number[] = [
const screenStartingMessageCodes: number[] = [
Diagnostics.Starting_compilation_in_watch_mode.code,
Diagnostics.File_change_detected_Starting_incremental_compilation.code,
];
@@ -279,18 +279,18 @@ export function getErrorSummaryText(
) {
if (errorCount === 0) return "";
const nonNilFiles = filesInError.filter(fileInError => fileInError !== undefined);
const distinctFileNamesWithLines = nonNilFiles.map(fileInError => `${fileInError!.fileName}:${fileInError!.line}`)
const distinctFileNamesWithLines = nonNilFiles.map(fileInError => `${fileInError.fileName}:${fileInError.line}`)
.filter((value, index, self) => self.indexOf(value) === index);
const firstFileReference = nonNilFiles[0] && prettyPathForFileError(nonNilFiles[0], host.getCurrentDirectory());
let messageAndArgs: DiagnosticAndArguments;
if (errorCount === 1) {
messageAndArgs = filesInError[0] !== undefined ? [Diagnostics.Found_1_error_in_0, firstFileReference!] : [Diagnostics.Found_1_error];
messageAndArgs = filesInError[0] !== undefined ? [Diagnostics.Found_1_error_in_0, firstFileReference] : [Diagnostics.Found_1_error];
}
else {
messageAndArgs = distinctFileNamesWithLines.length === 0 ? [Diagnostics.Found_0_errors, errorCount] :
distinctFileNamesWithLines.length === 1 ? [Diagnostics.Found_0_errors_in_the_same_file_starting_at_Colon_1, errorCount, firstFileReference!] :
distinctFileNamesWithLines.length === 1 ? [Diagnostics.Found_0_errors_in_the_same_file_starting_at_Colon_1, errorCount, firstFileReference] :
[Diagnostics.Found_0_errors_in_1_files, errorCount, distinctFileNamesWithLines.length];
}
@@ -571,7 +571,7 @@ export function emitFilesAndReportErrors<T extends BuilderProgram>(
emitResult: EmitResult;
diagnostics: SortedReadonlyArray<Diagnostic>;
} {
const isListFilesOnly = !!program.getCompilerOptions().listFilesOnly;
const options = program.getCompilerOptions();
// First get and report any syntactic errors.
const allDiagnostics = program.getConfigFileParsingDiagnostics().slice();
@@ -583,17 +583,25 @@ export function emitFilesAndReportErrors<T extends BuilderProgram>(
if (allDiagnostics.length === configFileParsingDiagnosticsLength) {
addRange(allDiagnostics, program.getOptionsDiagnostics(cancellationToken));
if (!isListFilesOnly) {
if (!options.listFilesOnly) {
addRange(allDiagnostics, program.getGlobalDiagnostics(cancellationToken));
if (allDiagnostics.length === configFileParsingDiagnosticsLength) {
addRange(allDiagnostics, program.getSemanticDiagnostics(/*sourceFile*/ undefined, cancellationToken));
}
if (
options.noEmit &&
getEmitDeclarations(options) &&
allDiagnostics.length === configFileParsingDiagnosticsLength
) {
addRange(allDiagnostics, program.getDeclarationDiagnostics(/*sourceFile*/ undefined, cancellationToken));
}
}
}
// Emit and report any errors we ran into.
const emitResult = isListFilesOnly
const emitResult = options.listFilesOnly
? { emitSkipped: true, diagnostics: emptyArray }
: program.emit(/*targetSourceFile*/ undefined, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers);
addRange(allDiagnostics, emitResult.diagnostics);
@@ -667,6 +675,7 @@ export function createWatchHost(system = sys, reportWatchStatus?: WatchStatusRep
watchDirectory: maybeBind(system, system.watchDirectory) || returnNoopFileWatcher,
setTimeout: maybeBind(system, system.setTimeout) || noop,
clearTimeout: maybeBind(system, system.clearTimeout) || noop,
preferNonRecursiveWatch: system.preferNonRecursiveWatch,
};
}
+2
View File
@@ -169,6 +169,7 @@ export interface WatchHost {
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
/** If provided, will be used to reset existing delayed compilation */
clearTimeout?(timeoutId: any): void;
preferNonRecursiveWatch?: boolean;
}
export interface ProgramHost<T extends BuilderProgram> {
/**
@@ -498,6 +499,7 @@ export function createWatchProgram<T extends BuilderProgram>(host: WatchCompiler
compilerHost.toPath = toPath;
compilerHost.getCompilationSettings = () => compilerOptions!;
compilerHost.useSourceOfProjectReferenceRedirect = maybeBind(host, host.useSourceOfProjectReferenceRedirect);
compilerHost.preferNonRecursiveWatch = host.preferNonRecursiveWatch;
compilerHost.watchDirectoryOfFailedLookupLocation = (dir, cb, flags) => watchDirectory(dir, cb, flags, watchOptions, WatchType.FailedLookupLocations);
compilerHost.watchAffectingFileLocation = (file, cb) => watchFile(file, cb, PollingInterval.High, watchOptions, WatchType.AffectingFileLocation);
compilerHost.watchTypeRootsDirectory = (dir, cb, flags) => watchDirectory(dir, cb, flags, watchOptions, WatchType.TypeRoots);
+2 -2
View File
@@ -77,7 +77,7 @@ export type OverloadBinders<T extends OverloadDefinitions> = { [P in OverloadKey
*/
export type OverloadDeprecations<T extends OverloadDefinitions> = { [P in OverloadKeys<T>]?: DeprecationOptions; };
/** @internal */
/** @internal @knipignore */
export function createOverload<T extends OverloadDefinitions>(name: string, overloads: T, binder: OverloadBinders<T>, deprecations?: OverloadDeprecations<T>) {
Object.defineProperty(call, "name", { ...Object.getOwnPropertyDescriptor(call, "name"), value: name });
@@ -137,7 +137,7 @@ export interface BoundOverloadBuilder<T extends OverloadDefinitions> extends Fin
// NOTE: We only use this "builder" because we don't infer correctly when calling `createOverload` directly in < TS 4.7,
// but lib is currently at TS 4.4. We can switch to directly calling `createOverload` when we update LKG in main.
/** @internal */
/** @internal @knipignore */
export function buildOverload(name: string): OverloadBuilder {
return {
overload: overloads => ({
+8 -6
View File
@@ -94,8 +94,7 @@ interface RenameEntry {
readonly locations: RenameLocation[];
}
/** @internal */
export function extractMessage(message: string): string {
function extractMessage(message: string): string {
// Read the content length
const contentLengthPrefix = "Content-Length: ";
const lines = message.split(/\r?\n/);
@@ -227,12 +226,14 @@ export class SessionClient implements LanguageService {
openFile(file: string, fileContent?: string, scriptKindName?: "TS" | "JS" | "TSX" | "JSX"): void {
const args: protocol.OpenRequestArgs = { file, fileContent, scriptKindName };
this.processRequest(protocol.CommandTypes.Open, args);
const request = this.processRequest(protocol.CommandTypes.Open, args);
this.processResponse(request, /*expectEmptyBody*/ true);
}
closeFile(file: string): void {
const args: protocol.FileRequestArgs = { file };
this.processRequest(protocol.CommandTypes.Close, args);
const request = this.processRequest(protocol.CommandTypes.Close, args);
this.processResponse(request, /*expectEmptyBody*/ true);
}
createChangeFileRequestArgs(fileName: string, start: number, end: number, insertString: string): protocol.ChangeRequestArgs {
@@ -242,7 +243,8 @@ export class SessionClient implements LanguageService {
changeFile(fileName: string, args: protocol.ChangeRequestArgs): void {
// clear the line map after an edit
this.lineMaps.set(fileName, undefined!); // TODO: GH#18217
this.processRequest(protocol.CommandTypes.Change, args);
const request = this.processRequest(protocol.CommandTypes.Change, args);
this.processResponse(request, /*expectEmptyBody*/ true);
}
toLineColumnOffset(fileName: string, position: number) {
@@ -1027,7 +1029,7 @@ export class SessionClient implements LanguageService {
};
const request = this.processRequest<protocol.GetPasteEditsRequest>(protocol.CommandTypes.GetPasteEdits, args);
const response = this.processResponse<protocol.GetPasteEditsResponse>(request);
if (!response.body) {
if (response.body.edits.length === 0) {
return { edits: [] };
}
const edits: FileTextChanges[] = this.convertCodeEditsToTextChanges(response.body.edits);
+3 -15
View File
@@ -1,3 +1,4 @@
import sourceMapSupport from "source-map-support";
import * as fakes from "./_namespaces/fakes.js";
import * as FourSlashInterface from "./_namespaces/FourSlashInterface.js";
import * as Harness from "./_namespaces/Harness.js";
@@ -4659,22 +4660,9 @@ function runCode(code: string, state: TestState, fileName: string): void {
const generatedFile = ts.changeExtension(fileName, ".js");
const wrappedCode = `(function(ts, test, goTo, config, verify, edit, debug, format, cancellation, classification, completion, verifyOperationIsCancelled, ignoreInterpolations) {${code}\n//# sourceURL=${ts.getBaseFileName(generatedFile)}\n})`;
type SourceMapSupportModule = typeof import("source-map-support") & {
// TODO(rbuckton): This is missing from the DT definitions and needs to be added.
resetRetrieveHandlers(): void;
};
// Provide the content of the current test to 'source-map-support' so that it can give us the correct source positions
// for test failures.
let sourceMapSupportModule: SourceMapSupportModule | undefined;
try {
sourceMapSupportModule = require("source-map-support");
}
catch {
// do nothing
}
sourceMapSupportModule?.install({
sourceMapSupport.install({
retrieveFile: path => {
return path === generatedFile ? wrappedCode :
undefined!;
@@ -4700,7 +4688,7 @@ function runCode(code: string, state: TestState, fileName: string): void {
throw err;
}
finally {
sourceMapSupportModule?.resetRetrieveHandlers();
sourceMapSupport.resetRetrieveHandlers();
}
}
+5 -12
View File
@@ -1,3 +1,6 @@
import * as Diff from "diff";
import fs from "fs";
import pathModule from "path";
import * as compiler from "./_namespaces/compiler.js";
import * as documents from "./_namespaces/documents.js";
import * as fakes from "./_namespaces/fakes.js";
@@ -54,14 +57,6 @@ export const virtualFileSystemRoot = "/";
function createNodeIO(): IO {
const workspaceRoot = Utils.findUpRoot();
let fs: any, pathModule: any;
if (require) {
fs = require("fs");
pathModule = require("path");
}
else {
fs = pathModule = {};
}
function deleteFile(path: string) {
try {
@@ -458,7 +453,7 @@ export namespace Compiler {
): DeclarationCompilationContext | undefined {
if (options.declaration && result.diagnostics.length === 0) {
if (options.emitDeclarationOnly) {
if (result.js.size > 0 || result.dts.size === 0) {
if (result.js.size > 0 || (result.dts.size === 0 && !options.noEmit)) {
throw new Error("Only declaration files should be generated when emitDeclarationOnly:true");
}
}
@@ -1022,7 +1017,6 @@ export namespace Compiler {
}
else if (original.text !== doc.text) {
jsCode += `\r\n\r\n!!!! File ${Utils.removeTestPathPrefixes(doc.file)} differs from original emit in noCheck emit\r\n`;
const Diff = require("diff");
const expected = original.text;
const actual = doc.text;
const patch = Diff.createTwoFilesPatch("Expected", "Actual", expected, actual, "The full check baseline", "with noCheck set");
@@ -1518,8 +1512,7 @@ export namespace Baseline {
IO.writeFile(actualFileName, encodedActual);
}
const errorMessage = getBaselineFileChangedErrorMessage(relativeFileName);
if (!!require && opts && opts.PrintDiff) {
const Diff = require("diff");
if (opts && opts.PrintDiff) {
const patch = Diff.createTwoFilesPatch("Expected", "Actual", expected, actual, "The current baseline", "The new version");
throw new Error(`${errorMessage}${ts.ForegroundColorEscapeSequences.Grey}\n\n${patch}`);
}
+1 -1
View File
@@ -1,3 +1,4 @@
import vm from "vm";
import * as Harness from "./_namespaces/Harness.js";
import * as ts from "./_namespaces/ts.js";
@@ -6,7 +7,6 @@ export function encodeString(s: string): string {
}
export function evalFile(fileContents: string, fileName: string, nodeContext?: any) {
const vm = require("vm");
if (nodeContext) {
vm.runInNewContext(fileContents, nodeContext, fileName);
}
+7 -11
View File
@@ -254,15 +254,11 @@ export function verifyResolutionCache(
// 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}`,
resolution.files?.size === info.length,
`${projectName}:: Expected Resolution ref count ${info.length} but got ${resolution.files?.size}`,
() =>
`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}`,
`Actual from: ${resolution.files?.size}`,
);
verifySet(resolutionToExpected.get(resolution)!.files, resolution.files, `${projectName}:: Resolution files`);
});
@@ -280,10 +276,9 @@ export function verifyResolutionCache(
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`);
});
resolutionToExpected.forEach(
expected => 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`);
@@ -516,6 +511,7 @@ function verifyProgram(service: ts.server.ProjectService, project: ts.server.Pro
fileIsOpen: project.fileIsOpen.bind(project),
getCurrentProgram: () => project.getCurrentProgram(),
preferNonRecursiveWatch: project.preferNonRecursiveWatch,
watchDirectoryOfFailedLookupLocation: ts.returnNoopFileWatcher,
watchAffectingFileLocation: ts.returnNoopFileWatcher,
onInvalidatedResolution: ts.noop,
+4 -1
View File
@@ -127,7 +127,10 @@ export function sanitizeLog(s: string): string {
s = s.replace(/"exportMapKey":\s*"\d+ \d+ /g, match => match.replace(/ \d+ /, ` * `));
s = s.replace(/getIndentationAtPosition: getCurrentSourceFile: \d+(?:\.\d+)?/, `getIndentationAtPosition: getCurrentSourceFile: *`);
s = s.replace(/getIndentationAtPosition: computeIndentation\s*: \d+(?:\.\d+)?/, `getIndentationAtPosition: computeIndentation: *`);
s = s.replace(/"duration":\s*\d+(?:.\d+)?/g, `"duration": *`);
s = s.replace(/"syntaxDiag":\s*\d+(?:.\d+)?/g, `"syntaxDiag": *`);
s = s.replace(/"semanticDiag":\s*\d+(?:.\d+)?/g, `"semanticDiag": *`);
s = s.replace(/"suggestionDiag":\s*\d+(?:.\d+)?/g, `"suggestionDiag": *`);
s = s.replace(/"regionSemanticDiag":\s*\d+(?:.\d+)?/g, `"regionSemanticDiag": *`);
s = replaceAll(s, `@ts${ts.versionMajorMinor}`, `@tsFakeMajor.Minor`);
s = sanitizeHarnessLSException(s);
return s;
+1 -2
View File
@@ -111,8 +111,7 @@ const unprefixedNodeCoreModuleList = [
"zlib",
];
/** @internal */
export const prefixedNodeCoreModuleList = unprefixedNodeCoreModuleList.map(name => `node:${name}`);
const prefixedNodeCoreModuleList = unprefixedNodeCoreModuleList.map(name => `node:${name}`);
/** @internal */
export const nodeCoreModuleList: readonly string[] = [...unprefixedNodeCoreModuleList, ...prefixedNodeCoreModuleList];
+4 -4
View File
@@ -1,24 +1,24 @@
interface ObjectConstructor {
/**
* Returns an array of values of the enumerable properties of an object
* Returns an array of values of the enumerable own properties of an object
* @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
*/
values<T>(o: { [s: string]: T; } | ArrayLike<T>): T[];
/**
* Returns an array of values of the enumerable properties of an object
* Returns an array of values of the enumerable own properties of an object
* @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
*/
values(o: {}): any[];
/**
* Returns an array of key/values of the enumerable properties of an object
* Returns an array of key/values of the enumerable own properties of an object
* @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
*/
entries<T>(o: { [s: string]: T; } | ArrayLike<T>): [string, T][];
/**
* Returns an array of key/values of the enumerable properties of an object
* Returns an array of key/values of the enumerable own properties of an object
* @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
*/
entries(o: {}): [string, any][];
-1
View File
@@ -8,7 +8,6 @@ export * from "../utilities.js";
import * as protocol from "./ts.server.protocol.js";
export { protocol };
export * from "../scriptInfo.js";
export * from "../typingsCache.js";
export * from "../project.js";
export * from "../editorServices.js";
export * from "../moduleSpecifierCache.js";
+27 -13
View File
@@ -83,6 +83,7 @@ import {
noop,
normalizePath,
normalizeSlashes,
notImplemented,
optionDeclarations,
optionsForWatch,
orderedRemoveItem,
@@ -170,7 +171,6 @@ import {
Msg,
NormalizedPath,
normalizedPathToPath,
nullTypingsInstaller,
PackageInstalledResponse,
PackageJsonCache,
Project,
@@ -183,7 +183,6 @@ import {
SetTypings,
ThrottledOperations,
toNormalizedPath,
TypingsCache,
WatchTypingLocations,
} from "./_namespaces/ts.server.js";
import * as protocol from "./protocol.js";
@@ -569,6 +568,16 @@ function findProjectByName<T extends Project>(projectName: string, projects: T[]
}
}
export const nullTypingsInstaller: ITypingsInstaller = {
isKnownTypesPackageName: returnFalse,
// Should never be called because we never provide a types registry.
installPackage: notImplemented,
enqueueInstallTypingsRequest: noop,
attach: noop,
onProjectClosed: noop,
globalTypingsCacheLocation: undefined!, // TODO: GH#18217
};
const noopConfigFileWatcher: FileWatcher = { close: noop };
/** @internal */
@@ -787,9 +796,8 @@ function forEachAncestorProject<T>(
* Goes through project's resolved project references and finds, creates or reloads project per kind
* If project for this resolved reference exists its used immediately otherwise,
* follows all references in order, deciding if references of the visited project can be loaded or not
* @internal
*/
export function forEachResolvedProjectReferenceProject<T>(
function forEachResolvedProjectReferenceProject<T>(
project: ConfiguredProject,
fileName: string | undefined,
cb: (child: ConfiguredProject, sentConfigFileDiag: boolean) => T | undefined,
@@ -1074,13 +1082,17 @@ function getHostWatcherMap<T>(): HostWatcherMap<T> {
return { idToCallbacks: new Map(), pathToId: new Map() };
}
function getCanUseWatchEvents(service: ProjectService, canUseWatchEvents: boolean | undefined) {
return !!canUseWatchEvents && !!service.eventHandler && !!service.session;
}
function createWatchFactoryHostUsingWatchEvents(service: ProjectService, canUseWatchEvents: boolean | undefined): WatchFactoryHost | undefined {
if (!canUseWatchEvents || !service.eventHandler || !service.session) return undefined;
if (!getCanUseWatchEvents(service, canUseWatchEvents)) return undefined;
const watchedFiles = getHostWatcherMap<FileWatcherCallback>();
const watchedDirectories = getHostWatcherMap<DirectoryWatcherCallback>();
const watchedDirectoriesRecursive = getHostWatcherMap<DirectoryWatcherCallback>();
let ids = 1;
service.session.addProtocolHandler(protocol.CommandTypes.WatchChange, req => {
service.session!.addProtocolHandler(protocol.CommandTypes.WatchChange, req => {
onWatchChange((req as protocol.WatchChangeRequest).arguments);
return { responseRequired: false };
});
@@ -1173,9 +1185,6 @@ function createWatchFactoryHostUsingWatchEvents(service: ProjectService, canUseW
}
export class ProjectService {
/** @internal */
readonly typingsCache: TypingsCache;
/** @internal */
readonly documentRegistry: DocumentRegistry;
@@ -1321,6 +1330,7 @@ export class ProjectService {
/** @internal */ verifyDocumentRegistry = noop;
/** @internal */ verifyProgram: (project: Project) => void = noop;
/** @internal */ onProjectCreation: (project: Project) => void = noop;
/** @internal */ canUseWatchEvents: boolean;
readonly jsDocParsingMode: JSDocParsingMode | undefined;
@@ -1367,8 +1377,6 @@ export class ProjectService {
this.typingsInstaller.attach(this);
this.typingsCache = new TypingsCache(this.typingsInstaller);
this.hostConfiguration = {
formatCodeOptions: getDefaultFormatCodeSettings(this.host.newLine),
preferences: emptyOptions,
@@ -1392,6 +1400,7 @@ export class ProjectService {
log,
getDetailWatchInfo,
);
this.canUseWatchEvents = getCanUseWatchEvents(this, opts.canUseWatchEvents);
opts.incrementalVerifier?.(this);
}
@@ -1481,11 +1490,16 @@ export class ProjectService {
switch (response.kind) {
case ActionSet:
// Update the typing files and update the project
project.updateTypingFiles(this.typingsCache.updateTypingsForProject(response.projectName, response.compilerOptions, response.typeAcquisition, response.unresolvedImports, response.typings));
project.updateTypingFiles(
response.compilerOptions,
response.typeAcquisition,
response.unresolvedImports,
response.typings,
);
return;
case ActionInvalidate:
// Do not clear resolution cache, there was changes detected in typings, so enque typing request and let it get us correct results
this.typingsCache.enqueueInstallTypingsForProject(project, project.lastCachedUnresolvedImportsList, /*forceRefresh*/ true);
project.enqueueInstallTypingsForProject(/*forceRefresh*/ true);
return;
}
}
+120 -29
View File
@@ -4,6 +4,7 @@ import {
append,
ApplyCodeActionCommandResult,
arrayFrom,
arrayIsEqualTo,
arrayToMap,
BuilderState,
CachedDirectoryStructureHost,
@@ -143,6 +144,7 @@ import {
ModuleImportResult,
Msg,
NormalizedPath,
nullTypingsInstaller,
PackageJsonWatcher,
ProjectOptions,
ProjectService,
@@ -150,7 +152,6 @@ import {
ServerHost,
Session,
toNormalizedPath,
TypingsCache,
updateProjectIfDirty,
} from "./_namespaces/ts.server.js";
import * as protocol from "./protocol.js";
@@ -306,6 +307,59 @@ const enum TypingWatcherType {
type TypingWatchers = Map<Path, FileWatcher> & { isInvoked?: boolean; };
interface TypingsCacheEntry {
readonly typeAcquisition: TypeAcquisition;
readonly compilerOptions: CompilerOptions;
readonly unresolvedImports: SortedReadonlyArray<string> | undefined;
}
function setIsEqualTo(arr1: string[] | undefined, arr2: string[] | undefined): boolean {
if (arr1 === arr2) {
return true;
}
if ((arr1 || emptyArray).length === 0 && (arr2 || emptyArray).length === 0) {
return true;
}
const set = new Map<string, boolean>();
let unique = 0;
for (const v of arr1!) {
if (set.get(v) !== true) {
set.set(v, true);
unique++;
}
}
for (const v of arr2!) {
const isSet = set.get(v);
if (isSet === undefined) {
return false;
}
if (isSet === true) {
set.set(v, false);
unique--;
}
}
return unique === 0;
}
function typeAcquisitionChanged(opt1: TypeAcquisition, opt2: TypeAcquisition): boolean {
return opt1.enable !== opt2.enable ||
!setIsEqualTo(opt1.include, opt2.include) ||
!setIsEqualTo(opt1.exclude, opt2.exclude);
}
function compilerOptionsChanged(opt1: CompilerOptions, opt2: CompilerOptions): boolean {
// TODO: add more relevant properties
return getAllowJSCompilerOption(opt1) !== getAllowJSCompilerOption(opt2);
}
function unresolvedImportsChanged(imports1: SortedReadonlyArray<string> | undefined, imports2: SortedReadonlyArray<string> | undefined): boolean {
if (imports1 === imports2) {
return false;
}
return !arrayIsEqualTo(imports1, imports2);
}
export abstract class Project implements LanguageServiceHost, ModuleResolutionHost {
private rootFilesMap = new Map<Path, ProjectRootFile>();
private program: Program | undefined;
@@ -388,6 +442,8 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
/** @internal */
typingFiles: SortedReadonlyArray<string> = emptyArray;
private typingsCache: TypingsCacheEntry | undefined;
private typingWatchers: TypingWatchers | undefined;
/** @internal */
@@ -499,6 +555,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
protected typeAcquisition: TypeAcquisition | undefined;
/** @internal */
createHash = maybeBind(this.projectService.host, this.projectService.host.createHash);
/** @internal*/ preferNonRecursiveWatch: boolean | undefined;
readonly jsDocParsingMode: JSDocParsingMode | undefined;
@@ -559,6 +616,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
this.trace = s => host.trace!(s);
}
this.realpath = maybeBind(host, host.realpath);
this.preferNonRecursiveWatch = this.projectService.canUseWatchEvents || host.preferNonRecursiveWatch;
// Use the current directory as resolution root only if the project created using current directory string
this.resolutionCache = createResolutionCache(
@@ -578,10 +636,10 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
}
isKnownTypesPackageName(name: string): boolean {
return this.typingsCache.isKnownTypesPackageName(name);
return this.projectService.typingsInstaller.isKnownTypesPackageName(name);
}
installPackage(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult> {
return this.typingsCache.installPackage({ ...options, projectName: this.projectName, projectRootPath: this.toPath(this.currentDirectory) });
return this.projectService.typingsInstaller.installPackage({ ...options, projectName: this.projectName, projectRootPath: this.toPath(this.currentDirectory) });
}
/** @internal */
@@ -589,10 +647,6 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
return this.getGlobalCache();
}
private get typingsCache(): TypingsCache {
return this.projectService.typingsCache;
}
/** @internal */
getSymlinkCache(): SymlinkCache {
if (!this.symlinks) {
@@ -1059,7 +1113,8 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
}
close() {
this.projectService.typingsCache.onProjectClosed(this);
if (this.typingsCache) this.projectService.typingsInstaller.onProjectClosed(this);
this.typingsCache = undefined;
this.closeWatchingTypingLocations();
// if we have a program - release all files that are enlisted in program but arent root
// The releasing of the roots happens later
@@ -1338,6 +1393,24 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
this.hasAddedOrRemovedSymlinks = true;
}
/** @internal */
onReleaseOldSourceFile(
oldSourceFile: SourceFile,
_oldOptions: CompilerOptions,
hasSourceFileByPath: boolean,
newSourceFileByResolvedPath: SourceFile | undefined,
) {
if (
!newSourceFileByResolvedPath ||
(oldSourceFile.resolvedPath === oldSourceFile.path && newSourceFileByResolvedPath.resolvedPath !== oldSourceFile.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(oldSourceFile.fileName, hasSourceFileByPath);
}
}
/** @internal */
updateFromProjectInProgress = false;
@@ -1379,7 +1452,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
this.lastCachedUnresolvedImportsList = getUnresolvedImports(this.program!, this.cachedUnresolvedImportsPerFile);
}
this.projectService.typingsCache.enqueueInstallTypingsForProject(this, this.lastCachedUnresolvedImportsList, hasAddedorRemovedFiles);
this.enqueueInstallTypingsForProject(hasAddedorRemovedFiles);
}
else {
this.lastCachedUnresolvedImportsList = undefined;
@@ -1401,7 +1474,41 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
}
/** @internal */
updateTypingFiles(typingFiles: SortedReadonlyArray<string>) {
enqueueInstallTypingsForProject(forceRefresh: boolean) {
const typeAcquisition = this.getTypeAcquisition();
if (!typeAcquisition || !typeAcquisition.enable || this.projectService.typingsInstaller === nullTypingsInstaller) {
return;
}
const entry = this.typingsCache;
if (
forceRefresh ||
!entry ||
typeAcquisitionChanged(typeAcquisition, entry.typeAcquisition) ||
compilerOptionsChanged(this.getCompilationSettings(), entry.compilerOptions) ||
unresolvedImportsChanged(this.lastCachedUnresolvedImportsList, entry.unresolvedImports)
) {
// Note: entry is now poisoned since it does not really contain typings for a given combination of compiler options\typings options.
// instead it acts as a placeholder to prevent issuing multiple requests
this.typingsCache = {
compilerOptions: this.getCompilationSettings(),
typeAcquisition,
unresolvedImports: this.lastCachedUnresolvedImportsList,
};
// something has been changed, issue a request to update typings
this.projectService.typingsInstaller.enqueueInstallTypingsRequest(this, typeAcquisition, this.lastCachedUnresolvedImportsList);
}
}
/** @internal */
updateTypingFiles(compilerOptions: CompilerOptions, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray<string>, newTypings: string[]) {
this.typingsCache = {
compilerOptions,
typeAcquisition,
unresolvedImports,
};
const typingFiles = !typeAcquisition || !typeAcquisition.enable ? emptyArray : sort(newTypings);
if (enumerateInsertsAndDeletes<string, string>(typingFiles, this.typingFiles, getStringComparer(!this.useCaseSensitiveFileNames()), /*inserted*/ noop, removed => this.detachScriptInfoFromProject(removed))) {
// If typing files changed, then only schedule project update
this.typingFiles = typingFiles;
@@ -1550,22 +1657,6 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
let hasNewProgram = false;
if (this.program && (!oldProgram || (this.program !== oldProgram && this.program.structureIsReused !== StructureIsReused.Completely))) {
hasNewProgram = true;
if (oldProgram) {
for (const f of oldProgram.getSourceFiles()) {
const newFile = this.program.getSourceFileByPath(f.resolvedPath);
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), /*syncDirWatcherRemove*/ true);
}
}
oldProgram.forEachResolvedProjectReference(resolvedProjectReference => {
if (!this.program!.getResolvedProjectReferenceByPath(resolvedProjectReference.sourceFile.path)) {
this.detachScriptInfoFromProject(resolvedProjectReference.sourceFile.fileName, /*noRemoveResolution*/ undefined, /*syncDirWatcherRemove*/ true);
}
});
}
// Update roots
this.rootFilesMap.forEach((value, path) => {
@@ -1610,7 +1701,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
!sourceFile ||
sourceFile.resolvedPath !== source ||
!this.isValidGeneratedFileWatcher(
getDeclarationEmitOutputFilePathWorker(sourceFile.fileName, this.compilerOptions, this.currentDirectory, this.program!.getCommonSourceDirectory(), this.getCanonicalFileName),
getDeclarationEmitOutputFilePathWorker(sourceFile.fileName, this.compilerOptions, this.program!),
watcher,
)
) {
@@ -1702,12 +1793,12 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
this.projectService.sendPerformanceEvent(kind, durationMs);
}
private detachScriptInfoFromProject(uncheckedFileName: string, noRemoveResolution?: boolean, syncDirWatcherRemove?: boolean) {
private detachScriptInfoFromProject(uncheckedFileName: string, noRemoveResolution?: boolean) {
const scriptInfoToDetach = this.projectService.getScriptInfo(uncheckedFileName);
if (scriptInfoToDetach) {
scriptInfoToDetach.detachFromProject(this);
if (!noRemoveResolution) {
this.resolutionCache.removeResolutionsOfFile(scriptInfoToDetach.path, syncDirWatcherRemove);
this.resolutionCache.removeResolutionsOfFile(scriptInfoToDetach.path);
}
}
}
+20 -8
View File
@@ -311,6 +311,22 @@ export interface PerformanceData {
* The time spent creating or updating the auto-import program, in milliseconds.
*/
createAutoImportProviderProgramDurationMs?: number;
/**
* The time spent computing diagnostics, in milliseconds.
*/
diagnosticsDuration?: FileDiagnosticPerformanceData[];
}
/**
* Time spent computing each kind of diagnostics, in milliseconds.
*/
export type DiagnosticPerformanceData = { [Kind in DiagnosticEventKind]?: number; };
export interface FileDiagnosticPerformanceData extends DiagnosticPerformanceData {
/**
* The file for which the performance data is reported.
*/
file: string;
}
/**
@@ -428,7 +444,7 @@ export interface OutliningSpansRequestFull extends FileRequest {
/**
* Response to OutliningSpansRequest request.
*
* @internal
* @internal @knipignore
*/
export interface OutliningSpansResponseFull extends Response {
body?: ts.OutliningSpan[];
@@ -1257,7 +1273,7 @@ export interface RenameFullRequest extends FileLocationRequest {
readonly arguments: RenameRequestArgs;
}
/** @internal */
/** @internal @knipignore */
export interface RenameFullResponse extends Response {
readonly body: readonly RenameLocation[];
}
@@ -2497,6 +2513,7 @@ export interface RequestCompletedEvent extends Event {
export interface RequestCompletedEventBody {
request_seq: number;
performanceData?: PerformanceData;
}
/**
@@ -2587,11 +2604,6 @@ export interface DiagnosticEventBody {
* Spans where the region diagnostic was requested, if this is a region semantic diagnostic event.
*/
spans?: TextSpan[];
/**
* Time spent computing the diagnostics, in milliseconds.
*/
duration?: number;
}
export type DiagnosticEventKind = "semanticDiag" | "syntaxDiag" | "suggestionDiag" | "regionSemanticDiag";
@@ -2756,7 +2768,7 @@ export interface CloseFileWatcherEventBody {
readonly id: number;
}
/** @internal */
/** @internal @knipignore */
export type AnyEvent =
| RequestCompletedEvent
| DiagnosticEvent
+113 -52
View File
@@ -130,6 +130,7 @@ import {
TextRange,
TextSpan,
textSpanEnd,
timestamp,
toArray,
toFileNameLowerCase,
tracing,
@@ -337,15 +338,21 @@ interface NextStep {
delay(actionType: string, ms: number, action: () => void): void;
}
/** @internal */
export type PerformanceData =
& Omit<protocol.PerformanceData, "diagnosticsDuration">
& { diagnosticsDuration?: Map<NormalizedPath, protocol.DiagnosticPerformanceData>; };
/**
* External capabilities used by multistep operation
*/
interface MultistepOperationHost {
getCurrentRequestId(): number;
sendRequestCompletedEvent(requestId: number): void;
getPerformanceData(): PerformanceData | undefined;
sendRequestCompletedEvent(requestId: number, performanceData: PerformanceData | undefined): void;
getServerHost(): ServerHost;
isCancellationRequested(): boolean;
executeWithRequestId(requestId: number, action: () => void): void;
executeWithRequestId(requestId: number, action: () => void, performanceData: PerformanceData | undefined): void;
logError(error: Error, message: string): void;
}
@@ -355,6 +362,7 @@ interface MultistepOperationHost {
*/
class MultistepOperation implements NextStep {
private requestId: number | undefined;
private performanceData: PerformanceData | undefined;
private timerHandle: any;
private immediateId: number | undefined;
@@ -368,11 +376,12 @@ class MultistepOperation implements NextStep {
private complete() {
if (this.requestId !== undefined) {
this.operationHost.sendRequestCompletedEvent(this.requestId);
this.operationHost.sendRequestCompletedEvent(this.requestId, this.performanceData);
this.requestId = undefined;
}
this.setTimerHandle(undefined);
this.setImmediateId(undefined);
this.performanceData = undefined;
}
public immediate(actionType: string, action: () => void) {
@@ -381,7 +390,7 @@ class MultistepOperation implements NextStep {
this.setImmediateId(
this.operationHost.getServerHost().setImmediate(() => {
this.immediateId = undefined;
this.operationHost.executeWithRequestId(requestId, () => this.executeAction(action));
this.operationHost.executeWithRequestId(requestId, () => this.executeAction(action), this.performanceData);
}, actionType),
);
}
@@ -393,7 +402,7 @@ class MultistepOperation implements NextStep {
this.operationHost.getServerHost().setTimeout(
() => {
this.timerHandle = undefined;
this.operationHost.executeWithRequestId(requestId, () => this.executeAction(action));
this.operationHost.executeWithRequestId(requestId, () => this.executeAction(action), this.performanceData);
},
ms,
actionType,
@@ -428,6 +437,7 @@ class MultistepOperation implements NextStep {
this.operationHost.logError(e, `delayed processing of request ${this.requestId}`);
}
}
this.performanceData = this.operationHost.getPerformanceData();
if (stop || !this.hasPendingWork()) {
this.complete();
}
@@ -975,7 +985,7 @@ export class Session<TMessage = string> implements EventSender {
protected projectService: ProjectService;
private changeSeq = 0;
private performanceData: protocol.PerformanceData | undefined;
private performanceData: PerformanceData | undefined;
private currentRequestId!: number;
private errorCheck: MultistepOperation;
@@ -1013,11 +1023,12 @@ export class Session<TMessage = string> implements EventSender {
? opts.eventHandler || (event => this.defaultEventHandler(event))
: undefined;
const multistepOperationHost: MultistepOperationHost = {
executeWithRequestId: (requestId, action) => this.executeWithRequestId(requestId, action),
executeWithRequestId: (requestId, action, performanceData) => this.executeWithRequestId(requestId, action, performanceData),
getCurrentRequestId: () => this.currentRequestId,
getPerformanceData: () => this.performanceData,
getServerHost: () => this.host,
logError: (err, cmd) => this.logError(err, cmd),
sendRequestCompletedEvent: requestId => this.sendRequestCompletedEvent(requestId),
sendRequestCompletedEvent: (requestId, performanceData) => this.sendRequestCompletedEvent(requestId, performanceData),
isCancellationRequested: () => this.cancellationToken.isCancellationRequested(),
};
this.errorCheck = new MultistepOperation(multistepOperationHost);
@@ -1067,17 +1078,36 @@ export class Session<TMessage = string> implements EventSender {
}
}
private sendRequestCompletedEvent(requestId: number): void {
this.event<protocol.RequestCompletedEventBody>({ request_seq: requestId }, "requestCompleted");
private sendRequestCompletedEvent(requestId: number, performanceData: PerformanceData | undefined): void {
this.event<protocol.RequestCompletedEventBody>(
{
request_seq: requestId,
performanceData: performanceData && toProtocolPerformanceData(performanceData),
},
"requestCompleted",
);
}
private addPerformanceData(key: keyof protocol.PerformanceData, value: number) {
private addPerformanceData(key: Exclude<keyof PerformanceData, "diagnosticsDuration">, value: number) {
if (!this.performanceData) {
this.performanceData = {};
}
this.performanceData[key] = (this.performanceData[key] ?? 0) + value;
}
private addDiagnosticsPerformanceData(
file: NormalizedPath,
kind: protocol.DiagnosticEventKind,
duration: number,
): void {
if (!this.performanceData) {
this.performanceData = {};
}
let fileDiagnosticDuration = this.performanceData.diagnosticsDuration?.get(file);
if (!fileDiagnosticDuration) (this.performanceData.diagnosticsDuration ??= new Map()).set(file, fileDiagnosticDuration = {});
fileDiagnosticDuration[kind] = duration;
}
private performanceEventHandler(event: PerformanceEvent) {
switch (event.kind) {
case "UpdateGraph":
@@ -1217,14 +1247,21 @@ export class Session<TMessage = string> implements EventSender {
}
/** @internal */
doOutput(info: {} | undefined, cmdName: string, reqSeq: number, success: boolean, message?: string): void {
doOutput(
info: {} | undefined,
cmdName: string,
reqSeq: number,
success: boolean,
performanceData: PerformanceData | undefined,
message?: string,
): void {
const res: protocol.Response = {
seq: 0,
type: "response",
command: cmdName,
request_seq: reqSeq,
success,
performanceData: this.performanceData,
performanceData: performanceData && toProtocolPerformanceData(performanceData),
};
if (success) {
@@ -1259,7 +1296,7 @@ export class Session<TMessage = string> implements EventSender {
}
private semanticCheck(file: NormalizedPath, project: Project) {
const diagnosticsStartTime = this.hrtime();
const diagnosticsStartTime = timestamp();
tracing?.push(tracing.Phase.Session, "semanticCheck", { file, configFilePath: (project as ConfiguredProject).canonicalConfigFilePath }); // undefined is fine if the cast fails
const diags = isDeclarationFileInJSOnlyNonConfiguredProject(project, file)
? emptyArray
@@ -1269,21 +1306,21 @@ export class Session<TMessage = string> implements EventSender {
}
private syntacticCheck(file: NormalizedPath, project: Project) {
const diagnosticsStartTime = this.hrtime();
const diagnosticsStartTime = timestamp();
tracing?.push(tracing.Phase.Session, "syntacticCheck", { file, configFilePath: (project as ConfiguredProject).canonicalConfigFilePath }); // undefined is fine if the cast fails
this.sendDiagnosticsEvent(file, project, project.getLanguageService().getSyntacticDiagnostics(file), "syntaxDiag", diagnosticsStartTime);
tracing?.pop();
}
private suggestionCheck(file: NormalizedPath, project: Project) {
const diagnosticsStartTime = this.hrtime();
const diagnosticsStartTime = timestamp();
tracing?.push(tracing.Phase.Session, "suggestionCheck", { file, configFilePath: (project as ConfiguredProject).canonicalConfigFilePath }); // undefined is fine if the cast fails
this.sendDiagnosticsEvent(file, project, project.getLanguageService().getSuggestionDiagnostics(file), "suggestionDiag", diagnosticsStartTime);
tracing?.pop();
}
private regionSemanticCheck(file: NormalizedPath, project: Project, ranges: TextRange[]): void {
const diagnosticsStartTime = this.hrtime();
const diagnosticsStartTime = timestamp();
tracing?.push(tracing.Phase.Session, "regionSemanticCheck", { file, configFilePath: (project as ConfiguredProject).canonicalConfigFilePath }); // undefined is fine if the cast fails
let diagnosticsResult;
if (!this.shouldDoRegionCheck(file) || !(diagnosticsResult = project.getLanguageService().getRegionSemanticDiagnostics(file, ranges))) {
@@ -1308,23 +1345,22 @@ export class Session<TMessage = string> implements EventSender {
project: Project,
diagnostics: readonly Diagnostic[],
kind: protocol.DiagnosticEventKind,
diagnosticsStartTime: [number, number],
diagnosticsStartTime: number,
spans?: TextSpan[],
): void {
try {
const scriptInfo = Debug.checkDefined(project.getScriptInfo(file));
const duration = hrTimeToMilliseconds(this.hrtime(diagnosticsStartTime));
const duration = timestamp() - diagnosticsStartTime;
const body: protocol.DiagnosticEventBody = {
file,
diagnostics: diagnostics.map(diag => formatDiag(file, project, diag)),
spans: spans?.map(span => toProtocolTextSpan(span, scriptInfo)),
duration,
};
this.event<protocol.DiagnosticEventBody>(
body,
kind,
);
this.addDiagnosticsPerformanceData(file, kind, duration);
}
catch (err) {
this.logError(err, kind);
@@ -2606,16 +2642,14 @@ export class Session<TMessage = string> implements EventSender {
}
}
private reload(args: protocol.ReloadRequestArgs, reqSeq: number) {
private reload(args: protocol.ReloadRequestArgs) {
const file = toNormalizedPath(args.file);
const tempFileName = args.tmpfile === undefined ? undefined : toNormalizedPath(args.tmpfile);
const info = this.projectService.getScriptInfoForNormalizedPath(file);
if (info) {
this.changeSeq++;
// make sure no changes happen before this one is finished
if (info.reloadFromFile(tempFileName)) {
this.doOutput(/*info*/ undefined, protocol.CommandTypes.Reload, reqSeq, /*success*/ true);
}
info.reloadFromFile(tempFileName);
}
}
@@ -3292,12 +3326,13 @@ export class Session<TMessage = string> implements EventSender {
exit() {/*overridden*/}
private notRequired(): HandlerResponse {
return { responseRequired: false };
private notRequired(request: protocol.Request | undefined): HandlerResponse {
if (request) this.doOutput(/*info*/ undefined, request.command, request.seq, /*success*/ true, this.performanceData);
return { responseRequired: false, performanceData: this.performanceData };
}
private requiredResponse(response: {} | undefined): HandlerResponse {
return { response, responseRequired: true };
return { response, responseRequired: true, performanceData: this.performanceData };
}
private handlers = new Map(Object.entries<(request: any) => HandlerResponse>({ // TODO(jakebailey): correctly type the handlers
@@ -3376,7 +3411,7 @@ export class Session<TMessage = string> implements EventSender {
},
[protocol.CommandTypes.Exit]: () => {
this.exit();
return this.notRequired();
return this.notRequired(/*request*/ undefined);
},
[protocol.CommandTypes.Definition]: (request: protocol.DefinitionRequest) => {
return this.requiredResponse(this.getDefinition(request.arguments, /*simplifiedResult*/ true));
@@ -3427,7 +3462,7 @@ export class Session<TMessage = string> implements EventSender {
convertScriptKindName(request.arguments.scriptKindName!), // TODO: GH#18217
request.arguments.projectRootPath ? toNormalizedPath(request.arguments.projectRootPath) : undefined,
);
return this.notRequired();
return this.notRequired(request);
},
[protocol.CommandTypes.Quickinfo]: (request: protocol.QuickInfoRequest) => {
return this.requiredResponse(this.getQuickInfoWorker(request.arguments, /*simplifiedResult*/ true));
@@ -3534,34 +3569,33 @@ export class Session<TMessage = string> implements EventSender {
},
[protocol.CommandTypes.Geterr]: (request: protocol.GeterrRequest) => {
this.errorCheck.startNew(next => this.getDiagnostics(next, request.arguments.delay, request.arguments.files));
return this.notRequired();
return this.notRequired(/*request*/ undefined);
},
[protocol.CommandTypes.GeterrForProject]: (request: protocol.GeterrForProjectRequest) => {
this.errorCheck.startNew(next => this.getDiagnosticsForProject(next, request.arguments.delay, request.arguments.file));
return this.notRequired();
return this.notRequired(/*request*/ undefined);
},
[protocol.CommandTypes.Change]: (request: protocol.ChangeRequest) => {
this.change(request.arguments);
return this.notRequired();
return this.notRequired(request);
},
[protocol.CommandTypes.Configure]: (request: protocol.ConfigureRequest) => {
this.projectService.setHostConfiguration(request.arguments);
this.doOutput(/*info*/ undefined, protocol.CommandTypes.Configure, request.seq, /*success*/ true);
return this.notRequired();
return this.notRequired(request);
},
[protocol.CommandTypes.Reload]: (request: protocol.ReloadRequest) => {
this.reload(request.arguments, request.seq);
this.reload(request.arguments);
return this.requiredResponse({ reloadFinished: true });
},
[protocol.CommandTypes.Saveto]: (request: protocol.Request) => {
const savetoArgs = request.arguments as protocol.SavetoRequestArgs;
this.saveToTmp(savetoArgs.file, savetoArgs.tmpfile);
return this.notRequired();
return this.notRequired(request);
},
[protocol.CommandTypes.Close]: (request: protocol.Request) => {
const closeArgs = request.arguments as protocol.FileRequestArgs;
this.closeClientFile(closeArgs.file);
return this.notRequired();
return this.notRequired(request);
},
[protocol.CommandTypes.Navto]: (request: protocol.NavtoRequest) => {
return this.requiredResponse(this.getNavigateToItems(request.arguments, /*simplifiedResult*/ true));
@@ -3600,9 +3634,9 @@ export class Session<TMessage = string> implements EventSender {
[protocol.CommandTypes.ProjectInfo]: (request: protocol.ProjectInfoRequest) => {
return this.requiredResponse(this.getProjectInfo(request.arguments));
},
[protocol.CommandTypes.ReloadProjects]: () => {
[protocol.CommandTypes.ReloadProjects]: request => {
this.projectService.reloadProjects();
return this.notRequired();
return this.notRequired(request);
},
[protocol.CommandTypes.JsxClosingTag]: (request: protocol.JsxClosingTagRequest) => {
return this.requiredResponse(this.getJsxClosingTag(request.arguments));
@@ -3657,8 +3691,7 @@ export class Session<TMessage = string> implements EventSender {
},
[protocol.CommandTypes.ConfigurePlugin]: (request: protocol.ConfigurePluginRequest) => {
this.configurePlugin(request.arguments);
this.doOutput(/*info*/ undefined, protocol.CommandTypes.ConfigurePlugin, request.seq, /*success*/ true);
return this.notRequired();
return this.notRequired(request);
},
[protocol.CommandTypes.SelectionRange]: (request: protocol.SelectionRangeRequest) => {
return this.requiredResponse(this.getSmartSelectionRange(request.arguments, /*simplifiedResult*/ true));
@@ -3726,36 +3759,40 @@ export class Session<TMessage = string> implements EventSender {
this.cancellationToken.resetRequest(requestId);
}
public executeWithRequestId<T>(requestId: number, f: () => T) {
public executeWithRequestId<T>(requestId: number, f: () => T): T;
/** @internal */
public executeWithRequestId<T>(requestId: number, f: () => T, perfomanceData: PerformanceData | undefined): T; // eslint-disable-line @typescript-eslint/unified-signatures
public executeWithRequestId<T>(requestId: number, f: () => T, perfomanceData?: PerformanceData) {
const currentPerformanceData = this.performanceData;
try {
this.performanceData = perfomanceData;
this.setCurrentRequest(requestId);
return f();
}
finally {
this.resetCurrentRequest(requestId);
this.performanceData = currentPerformanceData;
}
}
public executeCommand(request: protocol.Request): HandlerResponse {
const handler = this.handlers.get(request.command);
if (handler) {
const response = this.executeWithRequestId(request.seq, () => handler(request));
const response = this.executeWithRequestId(request.seq, () => handler(request), /*perfomanceData*/ undefined);
this.projectService.enableRequestedPlugins();
return response;
}
else {
this.logger.msg(`Unrecognized JSON command:${stringifyIndented(request)}`, Msg.Err);
this.doOutput(/*info*/ undefined, protocol.CommandTypes.Unknown, request.seq, /*success*/ false, `Unrecognized JSON command: ${request.command}`);
this.doOutput(/*info*/ undefined, protocol.CommandTypes.Unknown, request.seq, /*success*/ false, /*performanceData*/ undefined, `Unrecognized JSON command: ${request.command}`);
return { responseRequired: false };
}
}
public onMessage(message: TMessage) {
this.gcTimer.scheduleCollect();
this.performanceData = undefined;
let start: [number, number] | undefined;
const currentPerformanceData = this.performanceData;
if (this.logger.hasLevel(LogLevel.requestTime)) {
start = this.hrtime();
if (this.logger.hasLevel(LogLevel.verbose)) {
@@ -3772,7 +3809,7 @@ export class Session<TMessage = string> implements EventSender {
tracing?.instant(tracing.Phase.Session, "request", { seq: request.seq, command: request.command });
tracing?.push(tracing.Phase.Session, "executeCommand", { seq: request.seq, command: request.command }, /*separateBeginAndEnd*/ true);
const { response, responseRequired } = this.executeCommand(request);
const { response, responseRequired, performanceData } = this.executeCommand(request);
tracing?.pop();
if (this.logger.hasLevel(LogLevel.requestTime)) {
@@ -3788,10 +3825,23 @@ export class Session<TMessage = string> implements EventSender {
// Note: Log before writing the response, else the editor can complete its activity before the server does
tracing?.instant(tracing.Phase.Session, "response", { seq: request.seq, command: request.command, success: !!response });
if (response) {
this.doOutput(response, request.command, request.seq, /*success*/ true);
this.doOutput(
response,
request.command,
request.seq,
/*success*/ true,
performanceData,
);
}
else if (responseRequired) {
this.doOutput(/*info*/ undefined, request.command, request.seq, /*success*/ false, "No content available.");
this.doOutput(
/*info*/ undefined,
request.command,
request.seq,
/*success*/ false,
performanceData,
"No content available.",
);
}
}
catch (err) {
@@ -3801,7 +3851,7 @@ export class Session<TMessage = string> implements EventSender {
if (err instanceof OperationCanceledException) {
// Handle cancellation exceptions
tracing?.instant(tracing.Phase.Session, "commandCanceled", { seq: request?.seq, command: request?.command });
this.doOutput({ canceled: true }, request!.command, request!.seq, /*success*/ true);
this.doOutput({ canceled: true }, request!.command, request!.seq, /*success*/ true, this.performanceData);
return;
}
@@ -3813,9 +3863,13 @@ export class Session<TMessage = string> implements EventSender {
request ? request.command : protocol.CommandTypes.Unknown,
request ? request.seq : 0,
/*success*/ false,
this.performanceData,
"Error processing request. " + (err as StackTraceError).message + "\n" + (err as StackTraceError).stack,
);
}
finally {
this.performanceData = currentPerformanceData;
}
}
protected parseMessage(message: TMessage): protocol.Request {
@@ -3848,6 +3902,12 @@ interface FileAndProject {
readonly project: Project;
}
function toProtocolPerformanceData(performanceData: PerformanceData): protocol.PerformanceData {
const diagnosticsDuration = performanceData.diagnosticsDuration &&
arrayFrom(performanceData.diagnosticsDuration, ([file, data]) => ({ ...data, file }));
return { ...performanceData, diagnosticsDuration };
}
function toProtocolTextSpan(textSpan: TextSpan, scriptInfo: ScriptInfo): protocol.TextSpan {
return {
start: scriptInfo.positionToLineOffset(textSpan.start),
@@ -3898,6 +3958,7 @@ function convertNewFileTextChangeToCodeEdit(textChanges: FileTextChanges): proto
export interface HandlerResponse {
response?: {};
responseRequired?: boolean;
/** @internal */ performanceData?: PerformanceData;
}
/** @internal */
+26
View File
@@ -1,10 +1,19 @@
import {
ApplyCodeActionCommandResult,
DirectoryWatcherCallback,
FileWatcher,
FileWatcherCallback,
InstallPackageOptions,
Path,
SortedReadonlyArray,
System,
TypeAcquisition,
WatchOptions,
} from "./_namespaces/ts.js";
import {
Project,
ProjectService,
} from "./_namespaces/ts.server.js";
export interface CompressedData {
length: number;
@@ -20,6 +29,7 @@ export type RequireResult = ModuleImportResult;
export interface ServerHost extends System {
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number, options?: WatchOptions): FileWatcher;
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean, options?: WatchOptions): FileWatcher;
preferNonRecursiveWatch?: boolean;
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
clearTimeout(timeoutId: any): void;
setImmediate(callback: (...args: any[]) => void, ...args: any[]): any;
@@ -30,3 +40,19 @@ export interface ServerHost extends System {
/** @internal */
importPlugin?(root: string, moduleName: string): Promise<ModuleImportResult>;
}
export interface InstallPackageOptionsWithProject extends InstallPackageOptions {
projectName: string;
projectRootPath: Path;
}
// for backwards-compatibility
// eslint-disable-next-line @typescript-eslint/naming-convention
export interface ITypingsInstaller {
isKnownTypesPackageName(name: string): boolean;
installPackage(options: InstallPackageOptionsWithProject): Promise<ApplyCodeActionCommandResult>;
enqueueInstallTypingsRequest(p: Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray<string> | undefined): void;
attach(projectService: ProjectService): void;
onProjectClosed(p: Project): void;
readonly globalTypingsCacheLocation: string | undefined;
}
-164
View File
@@ -1,164 +0,0 @@
import {
ApplyCodeActionCommandResult,
arrayIsEqualTo,
CompilerOptions,
getAllowJSCompilerOption,
InstallPackageOptions,
noop,
notImplemented,
Path,
returnFalse,
sort,
SortedReadonlyArray,
TypeAcquisition,
} from "./_namespaces/ts.js";
import {
emptyArray,
Project,
ProjectService,
} from "./_namespaces/ts.server.js";
export interface InstallPackageOptionsWithProject extends InstallPackageOptions {
projectName: string;
projectRootPath: Path;
}
// for backwards-compatibility
// eslint-disable-next-line @typescript-eslint/naming-convention
export interface ITypingsInstaller {
isKnownTypesPackageName(name: string): boolean;
installPackage(options: InstallPackageOptionsWithProject): Promise<ApplyCodeActionCommandResult>;
enqueueInstallTypingsRequest(p: Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray<string> | undefined): void;
attach(projectService: ProjectService): void;
onProjectClosed(p: Project): void;
readonly globalTypingsCacheLocation: string | undefined;
}
export const nullTypingsInstaller: ITypingsInstaller = {
isKnownTypesPackageName: returnFalse,
// Should never be called because we never provide a types registry.
installPackage: notImplemented,
enqueueInstallTypingsRequest: noop,
attach: noop,
onProjectClosed: noop,
globalTypingsCacheLocation: undefined!, // TODO: GH#18217
};
interface TypingsCacheEntry {
readonly typeAcquisition: TypeAcquisition;
readonly compilerOptions: CompilerOptions;
readonly typings: SortedReadonlyArray<string>;
readonly unresolvedImports: SortedReadonlyArray<string> | undefined;
/* mainly useful for debugging */
poisoned: boolean;
}
function setIsEqualTo(arr1: string[] | undefined, arr2: string[] | undefined): boolean {
if (arr1 === arr2) {
return true;
}
if ((arr1 || emptyArray).length === 0 && (arr2 || emptyArray).length === 0) {
return true;
}
const set = new Map<string, boolean>();
let unique = 0;
for (const v of arr1!) {
if (set.get(v) !== true) {
set.set(v, true);
unique++;
}
}
for (const v of arr2!) {
const isSet = set.get(v);
if (isSet === undefined) {
return false;
}
if (isSet === true) {
set.set(v, false);
unique--;
}
}
return unique === 0;
}
function typeAcquisitionChanged(opt1: TypeAcquisition, opt2: TypeAcquisition): boolean {
return opt1.enable !== opt2.enable ||
!setIsEqualTo(opt1.include, opt2.include) ||
!setIsEqualTo(opt1.exclude, opt2.exclude);
}
function compilerOptionsChanged(opt1: CompilerOptions, opt2: CompilerOptions): boolean {
// TODO: add more relevant properties
return getAllowJSCompilerOption(opt1) !== getAllowJSCompilerOption(opt2);
}
function unresolvedImportsChanged(imports1: SortedReadonlyArray<string> | undefined, imports2: SortedReadonlyArray<string> | undefined): boolean {
if (imports1 === imports2) {
return false;
}
return !arrayIsEqualTo(imports1, imports2);
}
/** @internal */
export class TypingsCache {
private readonly perProjectCache = new Map<string, TypingsCacheEntry>();
constructor(private readonly installer: ITypingsInstaller) {
}
isKnownTypesPackageName(name: string): boolean {
return this.installer.isKnownTypesPackageName(name);
}
installPackage(options: InstallPackageOptionsWithProject): Promise<ApplyCodeActionCommandResult> {
return this.installer.installPackage(options);
}
enqueueInstallTypingsForProject(project: Project, unresolvedImports: SortedReadonlyArray<string> | undefined, forceRefresh: boolean) {
const typeAcquisition = project.getTypeAcquisition();
if (!typeAcquisition || !typeAcquisition.enable) {
return;
}
const entry = this.perProjectCache.get(project.getProjectName());
if (
forceRefresh ||
!entry ||
typeAcquisitionChanged(typeAcquisition, entry.typeAcquisition) ||
compilerOptionsChanged(project.getCompilationSettings(), entry.compilerOptions) ||
unresolvedImportsChanged(unresolvedImports, entry.unresolvedImports)
) {
// Note: entry is now poisoned since it does not really contain typings for a given combination of compiler options\typings options.
// instead it acts as a placeholder to prevent issuing multiple requests
this.perProjectCache.set(project.getProjectName(), {
compilerOptions: project.getCompilationSettings(),
typeAcquisition,
typings: entry ? entry.typings : emptyArray,
unresolvedImports,
poisoned: true,
});
// something has been changed, issue a request to update typings
this.installer.enqueueInstallTypingsRequest(project, typeAcquisition, unresolvedImports);
}
}
updateTypingsForProject(projectName: string, compilerOptions: CompilerOptions, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray<string>, newTypings: string[]) {
const typings = sort(newTypings);
this.perProjectCache.set(projectName, {
compilerOptions,
typeAcquisition,
typings,
unresolvedImports,
poisoned: false,
});
return !typeAcquisition || !typeAcquisition.enable ? emptyArray : typings;
}
onProjectClosed(project: Project) {
if (this.perProjectCache.delete(project.getProjectName())) {
this.installer.onProjectClosed(project);
}
}
}
+1 -24
View File
@@ -1,10 +1,4 @@
import {
binarySearch,
Comparer,
getBaseFileName,
identity,
SortedArray,
} from "./_namespaces/ts.js";
import { getBaseFileName } from "./_namespaces/ts.js";
import {
Logger,
LogLevel,
@@ -88,20 +82,3 @@ export function getBaseConfigFileName(configFilePath: NormalizedPath): "tsconfig
const base = getBaseFileName(configFilePath);
return base === "tsconfig.json" || base === "jsconfig.json" ? base : undefined;
}
/** @internal */
export function removeSorted<T>(array: SortedArray<T>, remove: T, compare: Comparer<T>): void {
if (!array || array.length === 0) {
return;
}
if (array[0] === remove) {
array.splice(0, 1);
return;
}
const removeIndex = binarySearch(array, remove, identity, compare);
if (removeIndex >= 0) {
array.splice(removeIndex, 1);
}
}
@@ -385,7 +385,7 @@ function getInfo(sourceFile: SourceFile, tokenPos: number, errorCode: number, ch
if (!classDeclaration && isPrivateIdentifier(token)) return undefined;
// Prefer to change the class instead of the interface if they are merged
const declaration = classDeclaration || find(symbol.declarations, d => isInterfaceDeclaration(d) || isTypeLiteralNode(d)) as InterfaceDeclaration | TypeLiteralNode | undefined;
const declaration = classDeclaration || find(symbol.declarations, d => isInterfaceDeclaration(d) || isTypeLiteralNode(d));
if (declaration && !isSourceFileFromLibrary(program, declaration.getSourceFile())) {
const makeStatic = !isTypeLiteralNode(declaration) && ((leftExpressionType as TypeReference).target || leftExpressionType) !== checker.getDeclaredTypeOfSymbol(symbol);
if (makeStatic && (isPrivateIdentifier(token) || isInterfaceDeclaration(declaration))) return undefined;
+3 -6
View File
@@ -610,8 +610,7 @@ function typeContainsTypeParameter(type: Type) {
return type.flags & TypeFlags.TypeParameter;
}
/** @internal */
export function getArgumentTypesAndTypeParameters(checker: TypeChecker, importAdder: ImportAdder, instanceTypes: Type[], contextNode: Node | undefined, scriptTarget: ScriptTarget, flags?: NodeBuilderFlags, tracker?: SymbolTracker) {
function getArgumentTypesAndTypeParameters(checker: TypeChecker, importAdder: ImportAdder, instanceTypes: Type[], contextNode: Node | undefined, scriptTarget: ScriptTarget, flags?: NodeBuilderFlags, tracker?: SymbolTracker) {
// Types to be used as the types of the parameters in the new function
// E.g. from this source:
// added("", 0)
@@ -874,13 +873,11 @@ export function setJsonCompilerOptionValue(
setJsonCompilerOptionValues(changeTracker, configFile, [[optionName, optionValue]]);
}
/** @internal */
export function createJsonPropertyAssignment(name: string, initializer: Expression) {
function createJsonPropertyAssignment(name: string, initializer: Expression) {
return factory.createPropertyAssignment(factory.createStringLiteral(name), initializer);
}
/** @internal */
export function findJsonProperty(obj: ObjectLiteralExpression, name: string): PropertyAssignment | undefined {
function findJsonProperty(obj: ObjectLiteralExpression, name: string): PropertyAssignment | undefined {
return find(obj.properties, (p): p is PropertyAssignment => isPropertyAssignment(p) && !!p.name && isStringLiteral(p.name) && p.name.text === name);
}
+1 -1
View File
@@ -398,7 +398,7 @@ import {
// Exported only for tests
/** @internal */
export const moduleSpecifierResolutionLimit = 100;
/** @internal */
/** @internal @knipignore */
export const moduleSpecifierResolutionCacheAttemptLimit = 1000;
/** @internal */
+3 -7
View File
@@ -201,7 +201,6 @@ import {
isVoidExpression,
isWriteAccess,
JSDocPropertyLikeTag,
JSDocTag,
length,
map,
mapDefined,
@@ -242,7 +241,6 @@ import {
skipAlias,
some,
SourceFile,
Statement,
StringLiteral,
StringLiteralLike,
stripQuotes,
@@ -324,8 +322,7 @@ export interface SpanEntry {
readonly fileName: string;
readonly textSpan: TextSpan;
}
/** @internal */
export function nodeEntry(node: Node, kind: NodeEntryKind = EntryKind.Node): NodeEntry {
function nodeEntry(node: Node, kind: NodeEntryKind = EntryKind.Node): NodeEntry {
return {
kind,
node: (node as NamedDeclaration).name || node,
@@ -377,7 +374,7 @@ function getContextNodeForNodeEntry(node: Node): ContextNode | undefined {
const declOrStatement = findAncestor(validImport, node =>
isDeclaration(node) ||
isStatement(node) ||
isJSDocTag(node))! as NamedDeclaration | Statement | JSDocTag;
isJSDocTag(node))!;
return isDeclaration(declOrStatement) ?
getContextNode(declOrStatement) :
declOrStatement;
@@ -886,8 +883,7 @@ function getTextSpan(node: Node, sourceFile: SourceFile, endNode?: Node): TextSp
return createTextSpanFromBounds(start, end);
}
/** @internal */
export function getTextSpanOfEntry(entry: Entry) {
function getTextSpanOfEntry(entry: Entry) {
return entry.kind === EntryKind.Span ? entry.textSpan :
getTextSpan(entry.node, entry.node.getSourceFile());
}
+3 -4
View File
@@ -159,13 +159,13 @@ export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile
}
if (node.kind === SyntaxKind.AwaitKeyword) {
const functionDeclaration = findAncestor(node, n => isFunctionLikeDeclaration(n)) as FunctionLikeDeclaration | undefined;
const functionDeclaration = findAncestor(node, n => isFunctionLikeDeclaration(n));
const isAsyncFunction = functionDeclaration && some(functionDeclaration.modifiers, node => node.kind === SyntaxKind.AsyncKeyword);
return isAsyncFunction ? [createDefinitionFromSignatureDeclaration(typeChecker, functionDeclaration)] : undefined;
}
if (node.kind === SyntaxKind.YieldKeyword) {
const functionDeclaration = findAncestor(node, n => isFunctionLikeDeclaration(n)) as FunctionLikeDeclaration | undefined;
const functionDeclaration = findAncestor(node, n => isFunctionLikeDeclaration(n));
const isGeneratorFunction = functionDeclaration && functionDeclaration.asteriskToken;
return isGeneratorFunction ? [createDefinitionFromSignatureDeclaration(typeChecker, functionDeclaration)] : undefined;
}
@@ -716,8 +716,7 @@ function createDefinitionFromSignatureDeclaration(typeChecker: TypeChecker, decl
return createDefinitionInfo(decl, typeChecker, decl.symbol, decl, /*unverified*/ false, failedAliasResolution);
}
/** @internal */
export function findReferenceInPosition(refs: readonly FileReference[], pos: number): FileReference | undefined {
function findReferenceInPosition(refs: readonly FileReference[], pos: number): FileReference | undefined {
return find(refs, ref => textRangeContainsPositionInclusive(ref, pos));
}
+1 -2
View File
@@ -787,10 +787,9 @@ function getContainingModuleSymbol(importer: Importer, checker: TypeChecker): Sy
}
function getSourceFileLikeForImportDeclaration(node: ImporterOrCallExpression): SourceFileLike {
if (node.kind === SyntaxKind.CallExpression) {
if (node.kind === SyntaxKind.CallExpression || node.kind === SyntaxKind.JSDocImportTag) {
return node.getSourceFile();
}
const { parent } = node;
if (parent.kind === SyntaxKind.SourceFile) {
return parent as SourceFile;
+1 -2
View File
@@ -212,8 +212,7 @@ export function organizeImports(
}
}
/** @internal */
export function getDetectionLists(preferences: UserPreferences): { comparersToTest: Comparer<string>[]; typeOrdersToTest: OrganizeImportsTypeOrder[]; } {
function getDetectionLists(preferences: UserPreferences): { comparersToTest: Comparer<string>[]; typeOrdersToTest: OrganizeImportsTypeOrder[]; } {
// Returns the possible detection outcomes, given the user's preferences. The earlier in the list, the higher the priority.
return {
comparersToTest: typeof preferences.organizeImportsIgnoreCase === "boolean"
+10 -2
View File
@@ -71,8 +71,9 @@ function pasteEdits(
newText = actualPastedText ? newText.slice(0, pos) + actualPastedText[0] + newText.slice(end) : newText.slice(0, pos) + pastedText[i] + newText.slice(end);
}
let importAdder: codefix.ImportAdder;
Debug.checkDefined(host.runWithTemporaryFileUpdate).call(host, targetFile.fileName, newText, (updatedProgram: Program, originalProgram: Program | undefined, updatedFile: SourceFile) => {
const importAdder = codefix.createImportAdder(updatedFile, updatedProgram, preferences, host);
importAdder = codefix.createImportAdder(updatedFile, updatedProgram, preferences, host);
if (copiedFrom?.range) {
Debug.assert(copiedFrom.range.length === pastedText.length);
copiedFrom.range.forEach(copy => {
@@ -90,7 +91,7 @@ function pasteEdits(
}
statements.push(...statementsInSourceFile.slice(startNodeIndex, endNodeIndex === -1 ? statementsInSourceFile.length : endNodeIndex + 1));
});
const usage = getUsageInfo(copiedFrom.file, statements, originalProgram!.getTypeChecker(), getExistingLocals(updatedFile, statements, originalProgram!.getTypeChecker()));
const usage = getUsageInfo(copiedFrom.file, statements, originalProgram!.getTypeChecker(), getExistingLocals(updatedFile, statements, originalProgram!.getTypeChecker()), { pos: copiedFrom.range[0].pos, end: copiedFrom.range[copiedFrom.range.length - 1].end });
Debug.assertIsDefined(originalProgram);
const useEsModuleSyntax = !fileShouldUseJavaScriptRequire(targetFile.fileName, originalProgram, host, !!copiedFrom.file.commonJsModuleIndicator);
addExportsInOldFile(copiedFrom.file, usage.targetFileImportsFromOldFile, changes, useEsModuleSyntax);
@@ -115,6 +116,13 @@ function pasteEdits(
}
importAdder.writeFixes(changes, getQuotePreference(copiedFrom ? copiedFrom.file : targetFile, preferences));
});
/**
* If there are no import fixes, getPasteEdits should return without making any changes to the file.
*/
if (!importAdder!.hasFixes()) {
return;
}
pasteLocations.forEach((paste, i) => {
changes.replaceRangeWithText(
targetFile,
+21 -27
View File
@@ -129,6 +129,7 @@ import {
PropertyAccessExpression,
PropertyAssignment,
QuotePreference,
rangeContainsRange,
RefactorContext,
RefactorEditInfo,
RequireOrImportCall,
@@ -145,6 +146,7 @@ import {
SyntaxKind,
takeWhile,
textChanges,
TextRange,
TransformFlags,
tryCast,
TypeAliasDeclaration,
@@ -287,15 +289,13 @@ export function addNewFileToTsconfig(program: Program, changes: textChanges.Chan
}
}
/** @internal */
export function deleteMovedStatements(sourceFile: SourceFile, moved: readonly StatementRange[], changes: textChanges.ChangeTracker) {
function deleteMovedStatements(sourceFile: SourceFile, moved: readonly StatementRange[], changes: textChanges.ChangeTracker) {
for (const { first, afterLast } of moved) {
changes.deleteNodeRangeExcludingEnd(sourceFile, first, afterLast);
}
}
/** @internal */
export function deleteUnusedOldImports(oldFile: SourceFile, toMove: readonly Statement[], toDelete: Set<Symbol>, importAdder: codefix.ImportAdder) {
function deleteUnusedOldImports(oldFile: SourceFile, toMove: readonly Statement[], toDelete: Set<Symbol>, importAdder: codefix.ImportAdder) {
for (const statement of oldFile.statements) {
if (contains(toMove, statement)) continue;
forEachImportInStatement(statement, i => {
@@ -328,8 +328,7 @@ export function addExportsInOldFile(oldFile: SourceFile, targetFileImportsFromOl
});
}
/** @internal */
export function updateImportsInOtherFiles(
function updateImportsInOtherFiles(
changes: textChanges.ChangeTracker,
program: Program,
host: LanguageServiceHost,
@@ -438,15 +437,13 @@ function createRequireCall(moduleSpecifier: StringLiteralLike): CallExpression {
return factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, [moduleSpecifier]);
}
/** @internal */
export function moduleSpecifierFromImport(i: SupportedImport): StringLiteralLike {
function moduleSpecifierFromImport(i: SupportedImport): StringLiteralLike {
return (i.kind === SyntaxKind.ImportDeclaration ? i.moduleSpecifier
: i.kind === SyntaxKind.ImportEqualsDeclaration ? i.moduleReference.expression
: i.initializer.arguments[0]);
}
/** @internal */
export function forEachImportInStatement(statement: Statement, cb: (importNode: SupportedImport) => void): void {
function forEachImportInStatement(statement: Statement, cb: (importNode: SupportedImport) => void): void {
if (isImportDeclaration(statement)) {
if (isStringLiteral(statement.moduleSpecifier)) cb(statement as SupportedImport);
}
@@ -547,8 +544,7 @@ function isExported(sourceFile: SourceFile, decl: TopLevelDeclarationStatement,
getNamesToExportInCommonJS(decl).some(name => sourceFile.symbol.exports!.has(escapeLeadingUnderscores(name)));
}
/** @internal */
export function deleteUnusedImports(sourceFile: SourceFile, importDecl: SupportedImport, changes: textChanges.ChangeTracker, isUnused: (name: Identifier) => boolean): void {
function deleteUnusedImports(sourceFile: SourceFile, importDecl: SupportedImport, changes: textChanges.ChangeTracker, isUnused: (name: Identifier) => boolean): void {
if (importDecl.kind === SyntaxKind.ImportDeclaration && importDecl.importClause) {
const { name, namedBindings } = importDecl.importClause;
if ((!name || isUnused(name)) && (!namedBindings || namedBindings.kind === SyntaxKind.NamedImports && namedBindings.elements.length !== 0 && namedBindings.elements.every(e => isUnused(e.name)))) {
@@ -638,8 +634,7 @@ function getNamesToExportInCommonJS(decl: TopLevelDeclarationStatement): readonl
}
}
/** @internal */
export function filterImport(i: SupportedImport, moduleSpecifier: StringLiteralLike, keep: (name: Identifier) => boolean): SupportedImportStatement | undefined {
function filterImport(i: SupportedImport, moduleSpecifier: StringLiteralLike, keep: (name: Identifier) => boolean): SupportedImportStatement | undefined {
switch (i.kind) {
case SyntaxKind.ImportDeclaration: {
const clause = i.importClause;
@@ -685,13 +680,11 @@ function filterBindingName(name: BindingName, keep: (name: Identifier) => boolea
}
}
/** @internal */
export function nameOfTopLevelDeclaration(d: TopLevelDeclaration): Identifier | undefined {
function nameOfTopLevelDeclaration(d: TopLevelDeclaration): Identifier | undefined {
return isExpressionStatement(d) ? tryCast(d.expression.left.name, isIdentifier) : tryCast(d.name, isIdentifier);
}
/** @internal */
export function getTopLevelDeclarationStatement(d: TopLevelDeclaration): TopLevelDeclarationStatement {
function getTopLevelDeclarationStatement(d: TopLevelDeclaration): TopLevelDeclarationStatement {
switch (d.kind) {
case SyntaxKind.VariableDeclaration:
return d.parent.parent;
@@ -704,8 +697,7 @@ export function getTopLevelDeclarationStatement(d: TopLevelDeclaration): TopLeve
}
}
/** @internal */
export function addExportToChanges(sourceFile: SourceFile, decl: TopLevelDeclarationStatement, name: Identifier, changes: textChanges.ChangeTracker, useEs6Exports: boolean): void {
function addExportToChanges(sourceFile: SourceFile, decl: TopLevelDeclarationStatement, name: Identifier, changes: textChanges.ChangeTracker, useEs6Exports: boolean): void {
if (isExported(sourceFile, decl, useEs6Exports, name)) return;
if (useEs6Exports) {
if (!isExpressionStatement(decl)) changes.insertExportModifier(sourceFile, decl);
@@ -871,7 +863,7 @@ function isPureImport(node: Node): boolean {
}
/** @internal */
export function getUsageInfo(oldFile: SourceFile, toMove: readonly Statement[], checker: TypeChecker, existingTargetLocals: ReadonlySet<Symbol> = new Set()): UsageInfo {
export function getUsageInfo(oldFile: SourceFile, toMove: readonly Statement[], checker: TypeChecker, existingTargetLocals: ReadonlySet<Symbol> = new Set(), enclosingRange?: TextRange): UsageInfo {
const movedSymbols = new Set<Symbol>();
const oldImportsNeededByTargetFile = new Map<Symbol, [/*isValidTypeOnlyUseSite*/ boolean, codefix.ImportOrRequireAliasDeclaration | undefined]>();
const targetFileImportsFromOldFile = new Map<Symbol, /*isValidTypeOnlyUseSite*/ boolean>();
@@ -890,7 +882,7 @@ export function getUsageInfo(oldFile: SourceFile, toMove: readonly Statement[],
const unusedImportsFromOldFile = new Set<Symbol>();
for (const statement of toMove) {
forEachReference(statement, checker, (symbol, isValidTypeOnlyUseSite) => {
forEachReference(statement, checker, enclosingRange, (symbol, isValidTypeOnlyUseSite) => {
if (!symbol.declarations || isGlobalType(checker, symbol)) {
return;
}
@@ -926,7 +918,7 @@ export function getUsageInfo(oldFile: SourceFile, toMove: readonly Statement[],
unusedImportsFromOldFile.delete(jsxNamespaceSymbol);
}
forEachReference(statement, checker, (symbol, isValidTypeOnlyUseSite) => {
forEachReference(statement, checker, enclosingRange, (symbol, isValidTypeOnlyUseSite) => {
if (movedSymbols.has(symbol)) oldFileImportsFromTargetFile.set(symbol, isValidTypeOnlyUseSite);
unusedImportsFromOldFile.delete(symbol);
});
@@ -969,9 +961,12 @@ function inferNewFileName(importsFromNewFile: Map<Symbol, unknown>, movedSymbols
return forEachKey(importsFromNewFile, symbolNameNoDefault) || forEachKey(movedSymbols, symbolNameNoDefault) || "newFile";
}
function forEachReference(node: Node, checker: TypeChecker, onReference: (s: Symbol, isValidTypeOnlyUseSite: boolean) => void) {
function forEachReference(node: Node, checker: TypeChecker, enclosingRange: TextRange | undefined, onReference: (s: Symbol, isValidTypeOnlyUseSite: boolean) => void) {
node.forEachChild(function cb(node) {
if (isIdentifier(node) && !isDeclarationName(node)) {
if (enclosingRange && !rangeContainsRange(enclosingRange, node)) {
return;
}
const sym = checker.getSymbolAtLocation(node);
if (sym) onReference(sym, isValidTypeOnlyAliasUseSite(node));
}
@@ -1025,8 +1020,7 @@ function isVariableDeclarationInImport(decl: VariableDeclaration) {
!!decl.initializer && isRequireCall(decl.initializer, /*requireStringLiteralLikeArgument*/ true);
}
/** @internal */
export function isTopLevelDeclaration(node: Node): node is TopLevelDeclaration {
function isTopLevelDeclaration(node: Node): node is TopLevelDeclaration {
return isNonVariableTopLevelDeclaration(node) && isSourceFile(node.parent) || isVariableDeclaration(node) && isSourceFile(node.parent.parent.parent);
}
function sourceFileOfTopLevelDeclaration(node: TopLevelDeclaration): Node {
@@ -1151,7 +1145,7 @@ export function getExistingLocals(sourceFile: SourceFile, statements: readonly S
}
for (const statement of statements) {
forEachReference(statement, checker, s => {
forEachReference(statement, checker, /*enclosingRange*/ undefined, s => {
const symbol = skipAlias(s, checker);
if (symbol.valueDeclaration && getSourceFileOfNode(symbol.valueDeclaration).path === sourceFile.path) {
existingLocals.add(symbol);
+1 -2
View File
@@ -16,7 +16,6 @@ import {
getTextOfIdentifierOrLiteral,
getTextOfNode,
getTouchingPropertyName,
ImportSpecifier,
isExternalModuleNameRelative,
isIdentifier,
isImportOrExportSpecifierName,
@@ -136,7 +135,7 @@ function wouldRenameInOtherNodeModules(
): DiagnosticMessage | undefined {
if (!preferences.providePrefixAndSuffixTextForRename && symbol.flags & SymbolFlags.Alias) {
const importSpecifier = symbol.declarations && find(symbol.declarations, decl => isImportSpecifier(decl));
if (importSpecifier && !(importSpecifier as ImportSpecifier).propertyName) {
if (importSpecifier && !importSpecifier.propertyName) {
symbol = checker.getAliasedSymbol(symbol);
}
}
+10 -5
View File
@@ -457,9 +457,9 @@ class NodeObject<TKind extends SyntaxKind> implements Node {
return this.getChildren(sourceFile)[index];
}
public getChildren(sourceFile?: SourceFileLike): readonly Node[] {
public getChildren(sourceFile: SourceFileLike = getSourceFileOfNode(this)): readonly Node[] {
this.assertHasRealPosition("Node without a real position cannot be scanned and thus has no token nodes - use forEachChild and collect the result if that's fine");
return getNodeChildren(this) ?? setNodeChildren(this, createChildren(this, sourceFile));
return getNodeChildren(this, sourceFile) ?? setNodeChildren(this, sourceFile, createChildren(this, sourceFile));
}
public getFirstToken(sourceFile?: SourceFileLike): Node | undefined {
@@ -558,7 +558,7 @@ function createSyntaxList(nodes: NodeArray<Node>, parent: Node): Node {
pos = node.end;
}
addSyntheticNodes(children, pos, nodes.end, parent);
setNodeChildren(list, children);
list._children = children;
return list;
}
@@ -1866,17 +1866,22 @@ export function createLanguageService(
host.onReleaseParsedCommandLine?.(configFileName, oldResolvedRef, oldOptions);
}
else if (oldResolvedRef) {
onReleaseOldSourceFile(oldResolvedRef.sourceFile, oldOptions);
releaseOldSourceFile(oldResolvedRef.sourceFile, oldOptions);
}
}
// Release any files we have acquired in the old program but are
// not part of the new program.
function onReleaseOldSourceFile(oldSourceFile: SourceFile, oldOptions: CompilerOptions) {
function releaseOldSourceFile(oldSourceFile: SourceFile, oldOptions: CompilerOptions) {
const oldSettingsKey = documentRegistry.getKeyForCompilationSettings(oldOptions);
documentRegistry.releaseDocumentWithKey(oldSourceFile.resolvedPath, oldSettingsKey, oldSourceFile.scriptKind, oldSourceFile.impliedNodeFormat);
}
function onReleaseOldSourceFile(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean, newSourceFileByResolvedPath: SourceFile | undefined) {
releaseOldSourceFile(oldSourceFile, oldOptions);
host.onReleaseOldSourceFile?.(oldSourceFile, oldOptions, hasSourceFileByPath, newSourceFileByResolvedPath);
}
function getOrCreateSourceFile(fileName: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined {
return getOrCreateSourceFileByPath(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), languageVersionOrOptions, onError, shouldCreateNewSourceFile);
}
+1 -1
View File
@@ -117,7 +117,7 @@ export function getSourceMapper(host: SourceMapperHost): SourceMapper {
const declarationPath = outPath ?
removeFileExtension(outPath) + Extension.Dts :
getDeclarationEmitOutputFilePathWorker(info.fileName, program.getCompilerOptions(), currentDirectory, program.getCommonSourceDirectory(), getCanonicalFileName);
getDeclarationEmitOutputFilePathWorker(info.fileName, program.getCompilerOptions(), program);
if (declarationPath === undefined) return undefined;
const newLoc = getDocumentPositionMapper(declarationPath, info.fileName).getGeneratedPosition(info);
+1
View File
@@ -430,6 +430,7 @@ export interface LanguageServiceHost extends GetEffectiveTypeRootsHost, MinimalR
/** @internal */ sendPerformanceEvent?(kind: PerformanceEvent["kind"], durationMs: number): void;
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
/** @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void;
/** @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean, newSourceFileByResolvedPath: SourceFile | undefined): void;
/** @internal */ getIncompleteCompletionsCache?(): IncompleteCompletionsCache;
/** @internal */ runWithTemporaryFileUpdate?(rootFile: string, updatedText: string, cb: (updatedProgram: Program, originalProgram: Program | undefined, updatedPastedText: SourceFile) => void): void;
jsDocParsingMode?: JSDocParsingMode | undefined;
+15 -57
View File
@@ -30,7 +30,6 @@ import {
ConditionalExpression,
contains,
ContextFlags,
createPrinterWithRemoveCommentsOmitTrailingSemicolon,
createRange,
createScanner,
createTextSpan,
@@ -53,7 +52,6 @@ import {
DoStatement,
ElementAccessExpression,
EmitFlags,
EmitHint,
emitModuleKindIsNonNodeESM,
emptyArray,
EndOfFileToken,
@@ -177,7 +175,6 @@ import {
isFunctionExpression,
isFunctionLike,
isGetAccessorDeclaration,
isGlobalScopeAugmentation,
isHeritageClause,
isIdentifier,
isIdentifierPart,
@@ -649,8 +646,7 @@ export function climbPastPropertyAccess(node: Node) {
return isRightSideOfPropertyAccess(node) ? node.parent : node;
}
/** @internal */
export function climbPastPropertyOrElementAccess(node: Node) {
function climbPastPropertyOrElementAccess(node: Node) {
return isRightSideOfPropertyAccess(node) || isArgumentExpressionOfElementAccess(node) ? node.parent : node;
}
@@ -1149,8 +1145,7 @@ export function findListItemInfo(node: Node): ListItemInfo | undefined {
};
}
/** @internal */
export function hasChildOfKind(n: Node, kind: SyntaxKind, sourceFile: SourceFile): boolean {
function hasChildOfKind(n: Node, kind: SyntaxKind, sourceFile: SourceFile): boolean {
return !!findChildOfKind(n, kind, sourceFile);
}
@@ -2008,8 +2003,7 @@ export function findPrecedingMatchingToken(token: Node, matchingTokenKind: Synta
}
}
/** @internal */
export function removeOptionality(type: Type, isOptionalExpression: boolean, isOptionalChain: boolean) {
function removeOptionality(type: Type, isOptionalExpression: boolean, isOptionalChain: boolean) {
return isOptionalExpression ? type.getNonNullableType() :
isOptionalChain ? type.getNonOptionalType() :
type;
@@ -2398,8 +2392,7 @@ export function isTypeKeyword(kind: SyntaxKind): boolean {
return contains(typeKeywords, kind);
}
/** @internal */
export function isTypeKeywordToken(node: Node): node is Token<SyntaxKind.TypeKeyword> {
function isTypeKeywordToken(node: Node): node is Token<SyntaxKind.TypeKeyword> {
return node.kind === SyntaxKind.TypeKeyword;
}
@@ -2872,8 +2865,7 @@ function getDisplayPartWriter(): DisplayPartsSymbolWriter {
}
}
/** @internal */
export function symbolPart(text: string, symbol: Symbol) {
function symbolPart(text: string, symbol: Symbol) {
return displayPart(text, displayPartKind(symbol));
function displayPartKind(symbol: Symbol): SymbolDisplayPartKind {
@@ -2958,13 +2950,11 @@ export function typeParameterNamePart(text: string) {
return displayPart(text, SymbolDisplayPartKind.typeParameterName);
}
/** @internal */
export function linkTextPart(text: string) {
function linkTextPart(text: string) {
return displayPart(text, SymbolDisplayPartKind.linkText);
}
/** @internal */
export function linkNamePart(text: string, target: Declaration): JSDocLinkDisplayPart {
function linkNamePart(text: string, target: Declaration): JSDocLinkDisplayPart {
return {
text,
kind: SymbolDisplayPartKind[SymbolDisplayPartKind.linkName],
@@ -2975,8 +2965,7 @@ export function linkNamePart(text: string, target: Declaration): JSDocLinkDispla
};
}
/** @internal */
export function linkPart(text: string) {
function linkPart(text: string) {
return displayPart(text, SymbolDisplayPartKind.link);
}
@@ -3090,15 +3079,6 @@ export function signatureToDisplayParts(typechecker: TypeChecker, signature: Sig
});
}
/** @internal */
export function nodeToDisplayParts(node: Node, enclosingDeclaration: Node): SymbolDisplayPart[] {
const file = enclosingDeclaration.getSourceFile();
return mapToDisplayParts(writer => {
const printer = createPrinterWithRemoveCommentsOmitTrailingSemicolon();
printer.writeNode(EmitHint.Unspecified, node, file, writer);
});
}
/** @internal */
export function isImportOrExportSpecifierName(location: Node): location is Identifier {
return !!location.parent && isImportOrExportSpecifier(location.parent) && location.parent.propertyName === location;
@@ -3251,7 +3231,7 @@ export function suppressLeadingTrivia(node: Node) {
/**
* Sets EmitFlags to suppress trailing trivia on the node.
*
* @internal
* @internal @knipignore
*/
export function suppressTrailingTrivia(node: Node) {
addEmitFlagsRecursively(node, EmitFlags.NoTrailingComments, getLastChild);
@@ -3490,8 +3470,7 @@ function syntaxRequiresTrailingModuleBlockOrSemicolonOrASI(kind: SyntaxKind) {
return kind === SyntaxKind.ModuleDeclaration;
}
/** @internal */
export function syntaxRequiresTrailingSemicolonOrASI(kind: SyntaxKind) {
function syntaxRequiresTrailingSemicolonOrASI(kind: SyntaxKind) {
return kind === SyntaxKind.VariableStatement
|| kind === SyntaxKind.ExpressionStatement
|| kind === SyntaxKind.DoStatement
@@ -3509,8 +3488,7 @@ export function syntaxRequiresTrailingSemicolonOrASI(kind: SyntaxKind) {
|| kind === SyntaxKind.ExportAssignment;
}
/** @internal */
export const syntaxMayBeASICandidate = or(
const syntaxMayBeASICandidate = or(
syntaxRequiresTrailingCommaOrSemicolonOrASI,
syntaxRequiresTrailingFunctionBlockOrSemicolonOrASI,
syntaxRequiresTrailingModuleBlockOrSemicolonOrASI,
@@ -3650,8 +3628,7 @@ export function tryAndIgnoreErrors<T>(cb: () => T): T | undefined {
}
}
/** @internal */
export function tryIOAndConsumeErrors<T>(host: unknown, toApply: ((...a: any[]) => T) | undefined, ...args: any[]) {
function tryIOAndConsumeErrors<T>(host: unknown, toApply: ((...a: any[]) => T) | undefined, ...args: any[]) {
return tryAndIgnoreErrors(() => toApply && toApply.apply(host, args));
}
@@ -3683,8 +3660,7 @@ export function findPackageJson(directory: string, host: LanguageServiceHost): s
return packageJson;
}
/** @internal */
export function getPackageJsonsVisibleToFile(fileName: string, host: LanguageServiceHost): readonly ProjectPackageJsonInfo[] {
function getPackageJsonsVisibleToFile(fileName: string, host: LanguageServiceHost): readonly ProjectPackageJsonInfo[] {
if (!host.fileExists) {
return [];
}
@@ -3922,8 +3898,7 @@ export function isInsideNodeModules(fileOrDirectory: string): boolean {
return contains(getPathComponents(fileOrDirectory), "node_modules");
}
/** @internal */
export function isDiagnosticWithLocation(diagnostic: Diagnostic): diagnostic is DiagnosticWithLocation {
function isDiagnosticWithLocation(diagnostic: Diagnostic): diagnostic is DiagnosticWithLocation {
return diagnostic.file !== undefined && diagnostic.start !== undefined && diagnostic.length !== undefined;
}
@@ -4058,8 +4033,7 @@ export function getDefaultLikeExportNameFromDeclaration(symbol: Symbol): string
});
}
/** @internal */
export function getSymbolParentOrFail(symbol: Symbol) {
function getSymbolParentOrFail(symbol: Symbol) {
return Debug.checkDefined(
symbol.parent,
`Symbol parent was undefined. Flags: ${Debug.formatSymbolFlags(symbol.flags)}. ` +
@@ -4146,22 +4120,6 @@ export function startsWithUnderscore(name: string): boolean {
return name.charCodeAt(0) === CharacterCodes._;
}
/** @internal */
export function isGlobalDeclaration(declaration: Declaration) {
return !isNonGlobalDeclaration(declaration);
}
/** @internal */
export function isNonGlobalDeclaration(declaration: Declaration) {
const sourceFile = declaration.getSourceFile();
// If the file is not a module, the declaration is global
if (!sourceFile.externalModuleIndicator && !sourceFile.commonJsModuleIndicator) {
return false;
}
// If the file is a module written in TypeScript, it still might be in a `declare global` augmentation
return isInJSFile(declaration) || !findAncestor(declaration, d => isModuleDeclaration(d) && isGlobalScopeAugmentation(d));
}
/** @internal */
export function isDeprecatedDeclaration(decl: Declaration) {
return !!(getCombinedNodeFlagsAlwaysIncludeJSDoc(decl) & ModifierFlags.Deprecated);
-3
View File
@@ -1,3 +0,0 @@
/* Generated file to emulate the compiler namespace. */
export * from "../../harness/_namespaces/compiler.js";
+9 -9
View File
@@ -1,3 +1,11 @@
import { fork } from "child_process";
import { statSync } from "fs";
import Mocha from "mocha";
import ms from "ms";
import os from "os";
import path from "path";
import readline from "readline";
import tty from "tty";
import {
configOption,
globalTimeout,
@@ -26,20 +34,12 @@ import * as ts from "../_namespaces/ts.js";
import * as Utils from "../_namespaces/Utils.js";
export function start(importTests: () => Promise<unknown>) {
const Mocha = require("mocha") as typeof import("mocha");
const Base = Mocha.reporters.Base;
const color = Base.color;
const cursor = Base.cursor;
const ms = require("ms") as typeof import("ms");
const readline = require("readline") as typeof import("readline");
const os = require("os") as typeof import("os");
const tty = require("tty") as typeof import("tty");
const isatty = tty.isatty(1) && tty.isatty(2);
const path = require("path") as typeof import("path");
const { fork } = require("child_process") as typeof import("child_process");
const { statSync } = require("fs") as typeof import("fs");
// NOTE: paths for module and types for FailedTestReporter _do not_ line up due to our use of --outFile for run.js
// NOTE: paths for module and types for FailedTestReporter _do not_ line up when bundled
const FailedTestReporter = require(Utils.findUpFile("scripts/failed-tests.cjs")) as typeof import("../../../scripts/failed-tests.cjs");
const perfdataFileNameFragment = ".parallelperf";
+1 -3
View File
@@ -1,3 +1,4 @@
import Mocha from "mocha";
import {
createRunner,
globalTimeout,
@@ -39,9 +40,6 @@ export function start(importTests: () => Promise<unknown>) {
let exceptionsHooked = false;
hookUncaughtExceptions();
// Capitalization is aligned with the global `Mocha` namespace for typespace/namespace references.
const Mocha = require("mocha") as typeof import("mocha");
/**
* Mixin helper.
* @param base The base class constructor.
+5
View File
@@ -88,6 +88,7 @@ const testConfigContent = customConfig && IO.fileExists(customConfig)
export let taskConfigsFolder: string;
export let workerCount: number;
export let runUnitTests: boolean | undefined;
export let skipSysTests: boolean | undefined;
export let stackTraceLimit: number | "full" | undefined;
export let noColors = false;
export let keepFailed = false;
@@ -101,6 +102,7 @@ export interface TestConfig {
test?: string[];
runners?: string[];
runUnitTests?: boolean;
skipSysTests?: boolean;
noColors?: boolean;
timeout?: number;
keepFailed?: boolean;
@@ -143,6 +145,9 @@ function handleTestConfig() {
if (testConfig.shards) {
setShards(testConfig.shards);
}
if (testConfig.skipSysTests) {
skipSysTests = true;
}
if (testConfig.stackTraceLimit === "full") {
(Error as any).stackTraceLimit = Infinity;

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